UNPKG

60.8 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3require("source-map-support/register");
4// TODO should I get rid of the lib above for production browser build?
5var lodash_1 = require("lodash");
6var fp_1 = require("lodash/fp");
7var hl = require("highland");
8var VError = require("verror");
9var cxml_xpath_1 = require("../spinoffs/cxml-xpath");
10var GPML2013a = require("../../xmlns/pathvisio.org/GPML/2013a");
11var GPMLDefaults = require("../GPMLDefaults");
12var Processor_1 = require("../Processor");
13var edge_1 = require("../edge/edge");
14var group_1 = require("../group");
15var gpml_utilities_1 = require("../gpml-utilities");
16var VOCABULARY_NAME_TO_IRI = require("../spinoffs/VOCABULARY_NAME_TO_IRI.json");
17var GPML2013aKeyMappings = require("./KeyMappings.json");
18var GPML2013aKeyValueMappings = require("./KeyValueConverters");
19var GPML2013aValueMappings = require("./ValueMappings.json");
20var GPML2013aValueConverters = require("./ValueConverters");
21// TODO get text alignment correctly mapped to Box Model CSS terms
22var iassign = require("immutable-assign");
23iassign.setOption({
24 // Deep freeze both input and output. Used in development to make sure they don't change.
25 // TODO watch issue and re-enable when addressed: https://github.com/engineforce/ImassignM/issues/11
26 //freeze: true,
27 ignoreIfNoChange: true
28});
29exports.RECURSION_LIMIT = 1000;
30function partitionStream(s, partitioner) {
31 var yes = s.fork().filter(function (x) { return partitioner(x); });
32 var no = s.fork().filter(function (x) { return !partitioner(x); });
33 return [yes, no];
34}
35function extendDeep(targetOrTargetArray, source) {
36 var target = fp_1.isArray(targetOrTargetArray)
37 ? targetOrTargetArray[0]
38 : targetOrTargetArray;
39 // TODO: We run into problems if we try to extend both
40 // GraphicalLine and Interaction, because they share
41 // EdgeGraphicsType. To avoid an infinite recursion of
42 // extending, I'm using a short-term solution of just
43 // marking whether a target has been extended, and
44 // if so, skipping it.
45 // Look into a better way of handling this.
46 if (!target.hasOwnProperty("_extended")) {
47 fp_1.toPairsIn(target)
48 .filter(function (_a) {
49 var targetKey = _a[0], targetValue = _a[1];
50 return source.hasOwnProperty(targetKey) && fp_1.isObject(source[targetKey]);
51 })
52 .forEach(function (_a) {
53 var targetKey = _a[0], targetValue = _a[1];
54 extendDeep(targetValue, source[targetKey]);
55 });
56 lodash_1.assign(target.constructor.prototype, source);
57 target._extended = true;
58 }
59}
60var stringifyKeyValue = fp_1.curry(function (source, key) {
61 return source.hasOwnProperty(key)
62 ? fp_1.startCase(key) + ": " + source[key]
63 : null;
64});
65extendDeep(GPML2013a.document.Pathway.constructor.prototype, GPMLDefaults.Pathway);
66extendDeep(GPML2013a.DataNodeType.prototype, GPMLDefaults.DataNode);
67extendDeep(GPML2013a.GraphicalLineType.prototype, GPMLDefaults.GraphicalLine);
68extendDeep(GPML2013a.GroupType.prototype, GPMLDefaults.Group);
69extendDeep(GPML2013a.InteractionType.prototype, GPMLDefaults.Interaction);
70extendDeep(GPML2013a.LabelType.prototype, GPMLDefaults.Label);
71extendDeep(GPML2013a.ShapeType.prototype, GPMLDefaults.Shape);
72extendDeep(GPML2013a.StateType.prototype, GPMLDefaults.State);
73extendDeep(GPML2013a.EdgeGraphicsType.prototype.Anchor, GPMLDefaults.Anchor);
74// TODO specify types
75function toPvjson(inputStreamWithMessedUpRDFIDs, pathwayIri) {
76 // NOTE: GPML2013a incorrectly uses "rdf:id" instead of "rdf:ID".
77 // We need to fix this error so that CXML can process the GPML.
78 var inputStream = hl(inputStreamWithMessedUpRDFIDs)
79 .splitBy(' rdf:id="')
80 .intersperse(' rdf:ID="');
81 var selectorToCXML = {
82 // TODO why does TS require that we use the Pathway's "constructor.prototype"
83 // instead of just the Pathway?
84 // Why does Pathway.Graphics not need that?
85 // Why do many of the other require using the prototype?
86 //
87 "/Pathway/@*": GPML2013a.document.Pathway.constructor.prototype,
88 "/Pathway/Comment": GPML2013a.document.Pathway.Comment[0],
89 "/Pathway/Graphics/@*": GPML2013a.document.Pathway.Graphics,
90 "/Pathway/DataNode": GPML2013a.DataNodeType.prototype,
91 "/Pathway/State": GPML2013a.StateType.prototype,
92 "/Pathway/Interaction": GPML2013a.InteractionType.prototype,
93 "/Pathway/GraphicalLine": GPML2013a.GraphicalLineType.prototype,
94 "/Pathway/Label": GPML2013a.LabelType.prototype,
95 "/Pathway/Shape": GPML2013a.ShapeType.prototype,
96 "/Pathway/Group": GPML2013a.GroupType.prototype,
97 "/Pathway/InfoBox": GPML2013a.InfoBoxType.prototype,
98 "/Pathway/Legend": GPML2013a.LegendType.prototype,
99 "/Pathway/Biopax/bp:PublicationXref": GPML2013a.document.Pathway.Biopax.PublicationXref[0],
100 "/Pathway/Biopax/bp:openControlledVocabulary": GPML2013a.document.Pathway.Biopax.openControlledVocabulary[0]
101 };
102 var cxmlXPath = new cxml_xpath_1.CXMLXPath(inputStream, GPML2013a, {
103 bp: "http://www.biopax.org/release/biopax-level3.owl#"
104 //rdf: "http://www.w3.org/1999/02/22-rdf-syntax-ns#"
105 });
106 var cxmlSources = cxmlXPath.parse(selectorToCXML);
107 var processor = new Processor_1.Processor(GPML2013aKeyMappings, GPML2013aKeyValueMappings, GPML2013aValueMappings, GPML2013aValueConverters);
108 var fillInGPMLPropertiesFromParent = processor.fillInGPMLPropertiesFromParent, getPvjsonEntityLatestByGraphId = processor.getPvjsonEntityLatestByGraphId, graphIdsByGraphRef = processor.graphIdsByGraphRef, graphIdToZIndex = processor.graphIdToZIndex, getGPMLElementByGraphId = processor.getGPMLElementByGraphId, preprocessGPMLElement = processor.preprocessGPMLElement, processGPMLAndPropertiesAndType = processor.processGPMLAndPropertiesAndType, processProperties = processor.processProperties, processPropertiesAndType = processor.processPropertiesAndType, setPvjsonEntity = processor.setPvjsonEntity;
109 if (pathwayIri) {
110 processor.output = iassign(processor.output, function (o) {
111 return o.pathway;
112 }, function (pathway) {
113 pathway.id = pathwayIri;
114 return pathway;
115 });
116 }
117 var sortByZIndex = gpml_utilities_1.sortByMap(graphIdToZIndex);
118 var pathwayMetadataStream = hl([
119 cxmlSources["/Pathway/@*"].doto(function (pathway) {
120 if (gpml_utilities_1.supportedNamespaces.indexOf(pathway._namespace) === -1) {
121 // TODO should we do anything further?
122 throw new Error("Unsupported namespace: " + pathway._namespace);
123 }
124 }),
125 cxmlSources["/Pathway/Graphics/@*"]
126 ])
127 .merge()
128 .map(processProperties)
129 .reduce({}, function (acc, metadataChunk) {
130 return fp_1.assign(acc, metadataChunk);
131 })
132 .map(function (metadata) {
133 processor.output = iassign(processor.output, function (o) {
134 return o.pathway;
135 }, function (pathway) {
136 var mergedPathway = fp_1.assign(pathway, metadata);
137 // NOTE: GPML schema specifies that name is required
138 var name = mergedPathway.name;
139 var splitName = name.split(" (");
140 if (!!splitName &&
141 splitName.length === 2 &&
142 !!name.match(/\(/g) &&
143 name.match(/\(/g).length === 1 &&
144 !!name.match(/\)/g) &&
145 name.match(/\)/g).length === 1) {
146 mergedPathway.standardName = splitName[0];
147 mergedPathway.displayName = splitName[1].replace(")", "");
148 }
149 else {
150 mergedPathway.standardName = name;
151 mergedPathway.displayName = name;
152 }
153 var stringifyKeyValueForPathway = stringifyKeyValue(mergedPathway);
154 mergedPathway.textContent = fp_1.compact([
155 stringifyKeyValueForPathway("name"),
156 stringifyKeyValueForPathway("license"),
157 stringifyKeyValueForPathway("lastModified"),
158 stringifyKeyValueForPathway("organism")
159 ]).join("\n");
160 var context = [
161 "https://cdn.rawgit.com/wikipathways/WpVocabularies/7a46a05/contexts/pvjs.jsonld"
162 ];
163 if (!!mergedPathway.id) {
164 context.push({
165 "@base": mergedPathway.id + "/"
166 });
167 }
168 else {
169 // If there's no pathway IRI specified, we at least give the user a URL
170 // to search WikiPathways. This way, the user at least has a chance of
171 // to search WikiPathways to possibly find the source for this data.
172 // NOTE: GPML schema specifies that organism is optional
173 var organismIriComponent = mergedPathway.hasOwnProperty("organism")
174 ? "&species=" + mergedPathway.organism
175 : "";
176 mergedPathway.isSimilarTo = encodeURI("http://wikipathways.org/index.php/Special:SearchPathways?query=" + name + organismIriComponent + "&doSearch=1");
177 }
178 return fp_1.assign({
179 "@context": context
180 }, mergedPathway);
181 });
182 return processor.output;
183 })
184 .errors(function (err) {
185 throw new VError(err, " when processing pathwayMetadataStream\n\t\t\t\t");
186 });
187 var pathwayCommentStream = hl(cxmlSources["/Pathway/Comment"]).map(function (Comment) {
188 processor.output = iassign(processor.output, function (o) {
189 return o.pathway;
190 }, function (pathway) {
191 var comments = pathway.comments || [];
192 comments.push(processProperties(Comment));
193 pathway.comments = comments;
194 return pathway;
195 });
196 return processor.output;
197 });
198 var dataNodeStream = cxmlSources["/Pathway/DataNode"]
199 .map(processGPMLAndPropertiesAndType("DataNode"))
200 .map(function (entity) {
201 // TODO fix type def for unionLSV so I don't have to use "as"
202 entity.type = gpml_utilities_1.unionLSV(entity.type, entity.wpType);
203 return entity;
204 });
205 var stateStream = cxmlSources["/Pathway/State"]
206 .map(preprocessGPMLElement)
207 .flatMap(function (gpmlState) {
208 return hl(getGPMLElementByGraphId(gpmlState.GraphRef)).map(function (gpmlDataNode) {
209 return fillInGPMLPropertiesFromParent(gpmlDataNode, gpmlState);
210 });
211 })
212 .map(processPropertiesAndType("State"));
213 var shapeStream = cxmlSources["/Pathway/Shape"]
214 .map(processGPMLAndPropertiesAndType("Shape"))
215 .map(function (pvjsonEntity) {
216 var cellularComponent = pvjsonEntity.cellularComponent;
217 // CellularComponent is not a BioPAX term, but "PhysicalEntity" is.
218 if (!!cellularComponent) {
219 pvjsonEntity.type = gpml_utilities_1.unionLSV(pvjsonEntity.type, "PhysicalEntity", "CellularComponent", cellularComponent);
220 }
221 return pvjsonEntity;
222 });
223 var labelStream = cxmlSources["/Pathway/Label"].map(processGPMLAndPropertiesAndType("Label"));
224 var gpmlInteractionStream = cxmlSources["/Pathway/Interaction"].map(preprocessGPMLElement);
225 var gpmlGraphicalLineStream = cxmlSources["/Pathway/GraphicalLine"].map(preprocessGPMLElement);
226 var edgeStream = hl([
227 gpmlInteractionStream
228 .fork()
229 .map(edge_1.preprocessGPML)
230 .map(processPropertiesAndType("Interaction")),
231 gpmlGraphicalLineStream
232 .fork()
233 .map(edge_1.preprocessGPML)
234 .map(processPropertiesAndType("GraphicalLine"))
235 ]).merge();
236 var anchorStream = hl([
237 gpmlInteractionStream.fork(),
238 gpmlGraphicalLineStream.fork()
239 ])
240 .merge()
241 .filter(function (gpmlEdge) {
242 return (gpml_utilities_1.isDefinedCXML(gpmlEdge.Graphics) &&
243 gpml_utilities_1.isDefinedCXML(gpmlEdge.Graphics.Anchor));
244 })
245 .flatMap(function (gpmlEdge) {
246 var GraphId = gpmlEdge.GraphId, Graphics = gpmlEdge.Graphics;
247 var fillInGPMLPropertiesFromEdge = fillInGPMLPropertiesFromParent(gpmlEdge);
248 var gpmlAnchors = Graphics.Anchor;
249 return hl(gpmlAnchors)
250 .map(function (gpmlAnchor) {
251 var anchorShape = gpmlAnchor.Shape;
252 if (anchorShape === "None") {
253 // NOTE: For Anchors with Shape="None", PathVisio-Java displays
254 // the anchor as a 4x4 square when nothing is connected,
255 // but does not display it when something is connected.
256 // TODO: right now, PathVisio-Java writes out GPML such that the
257 // Anchor only has a GraphId when an Edge connects to this Anchor,
258 // but we may not be able to rely on this in the future.
259 if (gpml_utilities_1.isDefinedCXML(gpmlAnchor.GraphId)) {
260 lodash_1.assign(gpmlAnchor.Graphics, {
261 Height: 0,
262 Width: 0
263 });
264 }
265 else {
266 gpmlAnchor.Shape = "Rectangle";
267 lodash_1.assign(gpmlAnchor.Graphics, {
268 Height: 4,
269 Width: 4
270 });
271 }
272 }
273 else if (anchorShape === "Circle") {
274 lodash_1.assign(gpmlAnchor.Graphics, {
275 Height: 8,
276 Width: 8
277 });
278 }
279 else {
280 throw new Error("Anchor Shape \"" + anchorShape + "\" is not supported.");
281 }
282 return gpmlAnchor;
283 })
284 .map(preprocessGPMLElement)
285 .map(function (gpmlAnchor) {
286 var filledInAnchor = fillInGPMLPropertiesFromEdge(gpmlAnchor);
287 filledInAnchor.GraphRef = GraphId;
288 return filledInAnchor;
289 })
290 .map(processPropertiesAndType("Anchor"));
291 });
292 var groupStream = cxmlSources["/Pathway/Group"]
293 .map(group_1.preprocessGPML(processor))
294 .filter(function (Group) { return !!Group.Contains; })
295 .map(processGPMLAndPropertiesAndType("Group"));
296 var EDGES = ["Interaction", "GraphicalLine"];
297 var NODES = ["DataNode", "Shape", "Label", "State", "Group"];
298 function postprocessAll(s) {
299 /*
300 // We are sorting the elements by the order in which we must do their
301 // post-processing, e.g., if one edge is attached to another edge via
302 // an anchor, we must post-process the edge with the anchor before we
303 // post-process the other edge.
304 const isProcessableTests = [
305 curry(function(sortedIds: string[], pvjsonEntity: PvjsonEntity) {
306 // In this test, we ensure the entity
307 // 1) is not a group AND
308 // 2) is not attached to a group and not to an edge
309 // (ie., it is not attached to anything, or
310 // it is attached to something, but that something is neither a group nor an edge)
311
312 return (
313 pvjsonEntity.gpmlElementName !== "Group" &&
314 unionLSV(
315 pvjsonEntity["isAttachedToOrVia"],
316 pvjsonEntity["isAttachedTo"]
317 )
318 .map(
319 (isAttachedToOrViaId: string) =>
320 processor.output.entitiesById[isAttachedToOrViaId].gpmlElementName
321 )
322 .filter(
323 // Entity is attached to neither a group nor an edge.
324 // (Testing that entity is not attached to an edge at all,
325 // whether directly or indirectly via an anchor.)
326 isAttachedToOrViaGpmlElementName =>
327 ["Group", "Interaction", "GraphicalLine", "Anchor"].indexOf(
328 isAttachedToOrViaGpmlElementName
329 ) > -1
330 ).length === 0
331 );
332 }),
333 curry(function(sortedIds: string[], pvjsonEntity: PvjsonEntity) {
334 const gpmlElementName = pvjsonEntity.gpmlElementName;
335 if (
336 ["Interaction", "GraphicalLine", "State", "Anchor"].indexOf(
337 gpmlElementName
338 ) > -1
339 ) {
340 // This entity is an edge, a state or an anchor.
341 // All entities to which this entity is attached must be processable
342 // before it is itself processable.
343 // That means all entities to which this entity is attached to must
344 // be processed before it can be processed.
345 const isAttachedToIds = unionLSV(
346 pvjsonEntity["isAttachedTo"],
347 pvjsonEntity["isAttachedToOrVia"]
348 ) as string[];
349 const isAttachedToInSortedIds = isAttachedToIds.filter(
350 // entity with this id is sortedIds
351 isAttachedToId => sortedIds.indexOf(isAttachedToId) > -1
352 );
353 return isAttachedToIds.length === isAttachedToInSortedIds.length;
354 } else if (gpmlElementName === "Group") {
355 // is processable when group does not contain an entity that is not processable
356 return (
357 arrayify(pvjsonEntity["contains"])
358 .map(isAttachedToId => processor.output.entitiesById[isAttachedToId])
359 .filter(
360 candidateEntity => sortedIds.indexOf(candidateEntity.id) > -1
361 ).length > 0
362 );
363 }
364 })
365 ];
366 //*/
367 function sortUnsortedRecursive(_a, i) {
368 var sortedIds = _a.sortedIds, unsorted = _a.unsorted;
369 if (i === void 0) { i = 0; }
370 // TODO is there something better we can do than use RECURSION_LIMIT?
371 // WP2037 revision 90015 won't terminate without a limit, but converts
372 // OK with the limit set.
373 if (unsorted.length === 0 || i > exports.RECURSION_LIMIT) {
374 return { sortedIds: sortedIds, unsorted: unsorted };
375 }
376 i += 1;
377 return sortUnsortedRecursive(sortUnsortedOnce({ sortedIds: sortedIds, unsorted: unsorted }), i);
378 }
379 function sortUnsortedOnce(_a) {
380 var sortedIds = _a.sortedIds, unsorted = _a.unsorted;
381 var _b = fp_1.partition(function (pvjsonEntity) {
382 var dependencies = gpml_utilities_1.unionLSV(pvjsonEntity.contains, pvjsonEntity["isAttachedToOrVia"], pvjsonEntity.isAttachedTo);
383 return (
384 /*
385 dependencies
386 .map((id: string) => processor.output.entitiesById[id])
387 .indexOf(undefined) === -1 &&
388 //*/
389 fp_1.intersection(dependencies, sortedIds).length === dependencies.length);
390 }, unsorted), sortedOnThisIteration = _b[0], stillUnsorted = _b[1];
391 sortedOnThisIteration
392 .forEach(function (pvjsonEntity) {
393 sortedIds.push(pvjsonEntity.id);
394 });
395 return {
396 sortedIds: sortedIds,
397 unsorted: stillUnsorted
398 };
399 }
400 return (s
401 .reduce({
402 sortedIds: [],
403 unsorted: []
404 }, function (_a, pvjsonEntity) {
405 var sortedIds = _a.sortedIds, unsorted = _a.unsorted;
406 unsorted.push(pvjsonEntity);
407 return sortUnsortedOnce({ sortedIds: sortedIds, unsorted: unsorted });
408 })
409 .map(sortUnsortedRecursive)
410 .map(function (acc) {
411 var sortedIds = acc.sortedIds, unsorted = acc.unsorted;
412 return sortedIds
413 .map(function (id) { return processor.output.entitiesById[id]; })
414 .concat(unsorted);
415 })
416 .sequence());
417 }
418 var pvjsonEntityStream = hl([
419 hl([dataNodeStream, stateStream, shapeStream, labelStream]).merge(),
420 hl([edgeStream, anchorStream]).merge(),
421 groupStream
422 ])
423 .sequence()
424 .doto(setPvjsonEntity)
425 .through(postprocessAll)
426 .flatMap(function (pvjsonEntity) {
427 var id = pvjsonEntity.id, zIndex = pvjsonEntity.zIndex;
428 // TODO we might want to sort by other criteria, such as
429 // to order a State above its DataNode, which would be
430 // ordered above its Group, if any
431 var insertEntityIdAndSortByZIndex = fp_1.flow([
432 gpml_utilities_1.insertIfNotExists(id),
433 sortByZIndex
434 ]);
435 var finalSortedStream;
436 if (gpml_utilities_1.isPvjsonEdgeOrBurr(pvjsonEntity)) {
437 var isAttachedTo = pvjsonEntity.isAttachedTo;
438 gpml_utilities_1.arrayify(isAttachedTo).forEach(function (graphRef) {
439 var graphRefs = graphIdsByGraphRef[graphRef] || [];
440 if (graphRefs.indexOf(id) === -1) {
441 graphRefs.push(id);
442 }
443 graphIdsByGraphRef[graphRef] = graphRefs;
444 });
445 if (gpml_utilities_1.isPvjsonBurr(pvjsonEntity)) {
446 finalSortedStream = hl(getPvjsonEntityLatestByGraphId(isAttachedTo)).map(function (referencedEntity) {
447 if (gpml_utilities_1.isPvjsonNode(referencedEntity)) {
448 var attachmentDisplay = pvjsonEntity.attachmentDisplay;
449 var _a = attachmentDisplay.relativeOffset, relativeOffsetScalarX = _a[0], relativeOffsetScalarY = _a[1];
450 attachmentDisplay.offset = [
451 relativeOffsetScalarX * referencedEntity.width,
452 relativeOffsetScalarY * referencedEntity.height
453 ];
454 pvjsonEntity.attachmentDisplay = fp_1.omit(["relativeOffset"], attachmentDisplay);
455 }
456 setPvjsonEntity(pvjsonEntity);
457 // NOTE: burrs are not added to the property "contained".
458 // Rather, they are added to the property "burrs".
459 referencedEntity.burrs = referencedEntity.burrs || [];
460 insertEntityIdAndSortByZIndex(referencedEntity.burrs);
461 setPvjsonEntity(referencedEntity);
462 return processor.output;
463 });
464 }
465 else if (gpml_utilities_1.isPvjsonEdge(pvjsonEntity)) {
466 try {
467 var pvjsonEdge = edge_1.postprocessPVJSON(processor.output.entitiesById, pvjsonEntity);
468 processor.output = iassign(processor.output, function (o) {
469 return o.pathway.contains;
470 }, insertEntityIdAndSortByZIndex);
471 setPvjsonEntity(pvjsonEdge);
472 finalSortedStream = hl([processor.output]);
473 }
474 catch (err) {
475 return hl.fromError(err);
476 }
477 }
478 else {
479 return hl.fromError(new VError("\n\t\t\t\t\t\t\tUnexpected entity type.\n\t\t\t\t\t\t\tOnly Edge or Burr should return true for\n\t\t\t\t\t\t\tisPvjsonEdgeOrBurr(\n\t\t\t\t\t\t\t\t" + JSON.stringify(pvjsonEntity, null, " ") + "\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t"));
480 }
481 }
482 else if (gpml_utilities_1.isPvjsonGroup(pvjsonEntity)) {
483 // We still have some GPML files with empty Groups and/or nested Groups
484 // floating around, but we don't process them, because that's a
485 // curation issue, not a gpml2pvjson issue.
486 var containedCount = pvjsonEntity.contains.length;
487 if (containedCount === 0 || pvjsonEntity.hasOwnProperty("groupRef")) {
488 if (containedCount === 0) {
489 return hl.fromError(new Error("\n\t\t\t\t\t\t\t\tEncountered empty Group:\n\t\t\t\t\t\t\t\t" + JSON.stringify(pvjsonEntity, null, " ") + "\n\t\t\t\t\t\t\t\t"));
490 }
491 if (pvjsonEntity.hasOwnProperty("groupRef")) {
492 return hl.fromError(new Error("\n\t\t\t\t\t\t\t\tEncountered nested Group:\n\t\t\t\t\t\t\t\t" + JSON.stringify(pvjsonEntity, null, " ") + "\n\t\t\t\t\t\t\t\t"));
493 }
494 finalSortedStream = hl([processor.output]);
495 }
496 else {
497 var graphIdOfGroup = pvjsonEntity.id;
498 try {
499 finalSortedStream = hl(pvjsonEntity.contains.map(function (containedId) { return processor.output.entitiesById[containedId]; }))
500 .filter(function (groupedEntity) { return groupedEntity.kaavioType !== "Group"; })
501 .collect()
502 .map(function (groupedEntities) {
503 var pvjsonGroup = group_1.postprocessPVJSON(groupedEntities, pvjsonEntity);
504 var graphIdToZIndex = processor.graphIdToZIndex;
505 pvjsonGroup.contains = fp_1.sortBy([
506 function (thisEntityId) {
507 return graphIdToZIndex[thisEntityId];
508 }
509 ], groupedEntities.map(function (x) { return x.id; }));
510 var id = pvjsonGroup.id, x = pvjsonGroup.x, y = pvjsonGroup.y;
511 var groupedEntitiesFinal = groupedEntities.map(function (groupedEntity) {
512 if (gpml_utilities_1.isPvjsonEdge(groupedEntity)) {
513 groupedEntity.points = fp_1.map(function (point) {
514 point.x -= x;
515 point.y -= y;
516 return point;
517 }, groupedEntity.points);
518 }
519 else if (gpml_utilities_1.isPvjsonSingleFreeNode(groupedEntity)) {
520 groupedEntity.height;
521 groupedEntity.x -= x;
522 groupedEntity.y -= y;
523 }
524 else {
525 return hl.fromError(new Error("\n\t\t\t\t\t\t\t\t\t\t\t\tEncountered unexpected entity\n\t\t\t\t\t\t\t\t\t\t\t\t" + JSON.stringify(groupedEntity, null, " ") + "\n\t\t\t\t\t\t\t\t\t\t\t\tin Group\n\t\t\t\t\t\t\t\t\t\t\t\t" + JSON.stringify(pvjsonGroup, null, " ") + "\n\t\t\t\t\t\t\t\t\t\t\t\t"));
526 }
527 // NOTE: this is needed for GPML2013a, because GPML2013a uses both
528 // GroupId/GroupRef and GraphId/GraphRef. GPML2017 uses a single
529 // identifier per entity. That identifier can be referenced by
530 // GroupRef and/or GraphRef. Pvjson follows GPML2017 in this, so
531 // we convert from GPML2013a format:
532 // GroupRef="GROUP_ID_VALUE"
533 // to pvjson format:
534 // {isPartOf: "GRAPH_ID_VALUE"}
535 groupedEntity.isPartOf = id;
536 return fp_1.omit(["groupRef"], groupedEntity);
537 });
538 groupedEntitiesFinal.forEach(function (pvjsonEntity) {
539 setPvjsonEntity(pvjsonEntity);
540 });
541 setPvjsonEntity(pvjsonGroup);
542 processor.output = iassign(processor.output, function (o) {
543 return o.pathway.contains;
544 }, function (contains) {
545 return insertEntityIdAndSortByZIndex(fp_1.difference(contains, groupedEntitiesFinal.map(function (x) { return x.id; })), id);
546 });
547 return pvjsonGroup;
548 })
549 .map(function (pvjsonEntity) {
550 return processor.output;
551 });
552 }
553 catch (err) {
554 return hl.fromError(err);
555 }
556 }
557 }
558 else {
559 setPvjsonEntity(pvjsonEntity);
560 processor.output = iassign(processor.output, function (o) {
561 return o.pathway.contains;
562 }, insertEntityIdAndSortByZIndex);
563 finalSortedStream = hl([processor.output]);
564 }
565 return finalSortedStream;
566 });
567 pvjsonEntityStream.observe().last().doto(function () {
568 processor.pvjsonEntityLatestStream.end();
569 });
570 var openControlledVocabularyStream = hl(cxmlSources["/Pathway/Biopax/bp:openControlledVocabulary"])
571 .map(processPropertiesAndType("openControlledVocabulary"))
572 .map(function (openControlledVocabulary) {
573 var vocabularyName = openControlledVocabulary.ontology;
574 var vocabularyIRI = VOCABULARY_NAME_TO_IRI[vocabularyName];
575 if (!vocabularyIRI) {
576 return hl.fromError(new Error("\n\t\t\t\t\t\tEncountered unexpected name \"" + vocabularyName + "\" for openControlledVocabulary,\n\t\t\t\t\t\twith dbId \"" + openControlledVocabulary.dbId + "\"\n\t\t\t\t\t\t"));
577 /* TODO should we use this?
578 vocabularyIRI = `http://www.ebi.ac.uk/miriam/main/search?query=${vocabularyName.replace(
579 /\ /,
580 "+"
581 )}#`;
582 //*/
583 }
584 openControlledVocabulary.id =
585 vocabularyIRI + openControlledVocabulary.dbId;
586 return openControlledVocabulary;
587 })
588 .collect()
589 .map(function (openControlledVocabularies) {
590 // TODO should these go through the processor instead?
591 processor.output = iassign(processor.output, function (o) {
592 var pathway = o.pathway, entitiesById = o.entitiesById;
593 openControlledVocabularies.forEach(function (openControlledVocabulary) {
594 var id = openControlledVocabulary.id;
595 entitiesById[id] = openControlledVocabulary;
596 if (openControlledVocabulary.ontology === "Pathway Ontology") {
597 pathway.type.push(id);
598 }
599 });
600 return o;
601 });
602 return processor.output;
603 });
604 var publicationXrefStream = hl(cxmlSources["/Pathway/Biopax/bp:PublicationXref"])
605 .map(processPropertiesAndType("PublicationXref"))
606 .collect()
607 .map(function (publicationXrefs) {
608 publicationXrefs
609 .sort(function (a, b) {
610 var yearA = parseInt(a.year);
611 var yearB = parseInt(b.year);
612 if (yearA > yearB) {
613 return 1;
614 }
615 else if (yearA < yearB) {
616 return -1;
617 }
618 else {
619 return 0;
620 }
621 })
622 .forEach(function (publicationXref, i) {
623 publicationXref.textContent = String(i + 1);
624 });
625 return publicationXrefs;
626 })
627 .map(function (publicationXrefs) {
628 // TODO should these go through the processor instead?
629 processor.output = iassign(processor.output, function (o) {
630 return o.entitiesById;
631 }, function (entitiesById) {
632 publicationXrefs.forEach(function (publicationXref) {
633 entitiesById[publicationXref.id] = publicationXref;
634 });
635 return entitiesById;
636 });
637 return processor.output;
638 });
639 /* TODO do we need to handle these?
640 <xsd:element ref="gpml:InfoBox" minOccurs="1" maxOccurs="1" />
641 <xsd:element ref="gpml:Legend" minOccurs="0" maxOccurs="1"/>
642 */
643 return hl([
644 pathwayMetadataStream,
645 pathwayCommentStream,
646 pvjsonEntityStream,
647 openControlledVocabularyStream,
648 publicationXrefStream
649 ])
650 .merge()
651 .errors(function (err) {
652 throw new VError(err, " when converting pathway " + pathwayIri + "\n\t\t\t\t");
653 });
654 // // TODO Double-check old code to make sure nothing is missed.
655 // // TODO does the stream ever end?
656 // // TODO does backpressure work?
657 // TODO compare the old pvjs/kaavio code below for grouping entities to
658 // ensure we don't have any regression errors.
659 /*
660 getGroupedZIndexedEntities(zIndexedEntities) {
661 const { entitiesById } = this.props;
662 return zIndexedEntities
663 .filter(entity => !entity.isPartOf)
664 .reduce(function(acc, entity) {
665 const kaavioType = entity.kaavioType;
666 if (kaavioType === "Group") {
667 // TODO: refactor this so that contains is actually a map of the contained elements. Not just an array of their IDs
668 entity.contains = entity.contains
669 .map(id => entitiesById[id])
670 .sort(function(a, b) {
671 const zIndexA = a.zIndex;
672 const zIndexB = b.zIndex;
673 if (zIndexA < zIndexB) {
674 return 1;
675 } else if (zIndexA > zIndexB) {
676 return -1;
677 } else {
678 return 0;
679 }
680 })
681 .map(entity => entity.id);
682 } else if (entity.hasOwnProperty("burrs")) {
683 entity.burrs = entity.burrs
684 .map(id => entitiesById[id])
685 .sort(function(a, b) {
686 const zIndexA = a.zIndex;
687 const zIndexB = b.zIndex;
688 if (zIndexA < zIndexB) {
689 return 1;
690 } else if (zIndexA > zIndexB) {
691 return -1;
692 } else {
693 return 0;
694 }
695 })
696 .map(entity => entity.id);
697 }
698 if (
699 ["Burr"].indexOf(kaavioType) === -1 &&
700 !entity.hasOwnProperty("isPartOf")
701 ) {
702 acc.push(entity);
703 }
704 return acc;
705 }, []);
706 }
707 //*/
708}
709exports.toPvjson = toPvjson;
710//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidG9Qdmpzb24uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvMjAxM2EvdG9Qdmpzb24udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFBQSx1Q0FBcUM7QUFDckMsdUVBQXVFO0FBRXZFLGlDQUEyQztBQUMzQyxnQ0F1Qm1CO0FBQ25CLDZCQUErQjtBQUMvQiwrQkFBaUM7QUFFakMscURBQW1EO0FBa0JuRCxnRUFBa0U7QUFFbEUsOENBQWdEO0FBRWhELDBDQUF5QztBQUN6QyxxQ0FHc0I7QUFDdEIsa0NBR2tCO0FBQ2xCLG9EQWMyQjtBQUMzQixnRkFBa0Y7QUFFbEYseURBQTJEO0FBQzNELGdFQUFrRTtBQUNsRSw2REFBK0Q7QUFDL0QsNERBQThEO0FBRTlELGtFQUFrRTtBQUVsRSwwQ0FBNEM7QUFDNUMsT0FBTyxDQUFDLFNBQVMsQ0FBQztJQUNoQix5RkFBeUY7SUFDekYsb0dBQW9HO0lBQ3BHLGVBQWU7SUFDZixnQkFBZ0IsRUFBRSxJQUFJO0NBQ3ZCLENBQUMsQ0FBQztBQVVVLFFBQUEsZUFBZSxHQUFHLElBQUksQ0FBQztBQUVwQyx5QkFDRSxDQUFxQixFQUNyQixXQUE4QjtJQUU5QixJQUFNLEdBQUcsR0FBRyxDQUFDLENBQUMsSUFBSSxFQUFFLENBQUMsTUFBTSxDQUFDLFVBQUEsQ0FBQyxJQUFJLE9BQUEsV0FBVyxDQUFDLENBQUMsQ0FBQyxFQUFkLENBQWMsQ0FBQyxDQUFDO0lBQ2pELElBQU0sRUFBRSxHQUFHLENBQUMsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxNQUFNLENBQUMsVUFBQSxDQUFDLElBQUksT0FBQSxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUMsRUFBZixDQUFlLENBQUMsQ0FBQztJQUNqRCxNQUFNLENBQUMsQ0FBQyxHQUFHLEVBQUUsRUFBRSxDQUFDLENBQUM7QUFDbkIsQ0FBQztBQUVELG9CQUFvQixtQkFBbUIsRUFBRSxNQUFNO0lBQzdDLElBQU0sTUFBTSxHQUFHLFlBQU8sQ0FBQyxtQkFBbUIs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
\No newline at end of file