1 | ;
|
2 | Object.defineProperty(exports, "__esModule", { value: true });
|
3 | require("source-map-support/register");
|
4 | // TODO should I get rid of the lib above for production browser build?
|
5 | var lodash_1 = require("lodash");
|
6 | var fp_1 = require("lodash/fp");
|
7 | var hl = require("highland");
|
8 | var VError = require("verror");
|
9 | var cxml_xpath_1 = require("../spinoffs/cxml-xpath");
|
10 | var GPML2013a = require("../../xmlns/pathvisio.org/GPML/2013a");
|
11 | var GPMLDefaults = require("../GPMLDefaults");
|
12 | var Processor_1 = require("../Processor");
|
13 | var edge_1 = require("../edge/edge");
|
14 | var group_1 = require("../group");
|
15 | var gpml_utilities_1 = require("../gpml-utilities");
|
16 | var VOCABULARY_NAME_TO_IRI = require("../spinoffs/VOCABULARY_NAME_TO_IRI.json");
|
17 | var GPML2013aKeyMappings = require("./KeyMappings.json");
|
18 | var GPML2013aKeyValueMappings = require("./KeyValueConverters");
|
19 | var GPML2013aValueMappings = require("./ValueMappings.json");
|
20 | var GPML2013aValueConverters = require("./ValueConverters");
|
21 | // TODO get text alignment correctly mapped to Box Model CSS terms
|
22 | var iassign = require("immutable-assign");
|
23 | iassign.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 | });
|
29 | exports.RECURSION_LIMIT = 1000;
|
30 | function 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 | }
|
35 | function 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 | }
|
60 | var stringifyKeyValue = fp_1.curry(function (source, key) {
|
61 | return source.hasOwnProperty(key)
|
62 | ? fp_1.startCase(key) + ": " + source[key]
|
63 | : null;
|
64 | });
|
65 | extendDeep(GPML2013a.document.Pathway.constructor.prototype, GPMLDefaults.Pathway);
|
66 | extendDeep(GPML2013a.DataNodeType.prototype, GPMLDefaults.DataNode);
|
67 | extendDeep(GPML2013a.GraphicalLineType.prototype, GPMLDefaults.GraphicalLine);
|
68 | extendDeep(GPML2013a.GroupType.prototype, GPMLDefaults.Group);
|
69 | extendDeep(GPML2013a.InteractionType.prototype, GPMLDefaults.Interaction);
|
70 | extendDeep(GPML2013a.LabelType.prototype, GPMLDefaults.Label);
|
71 | extendDeep(GPML2013a.ShapeType.prototype, GPMLDefaults.Shape);
|
72 | extendDeep(GPML2013a.StateType.prototype, GPMLDefaults.State);
|
73 | extendDeep(GPML2013a.EdgeGraphicsType.prototype.Anchor, GPMLDefaults.Anchor);
|
74 | // TODO specify types
|
75 | function 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 | }
|
709 | exports.toPvjson = toPvjson;
|
710 | //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidG9Qdmpzb24uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvMjAxM2EvdG9Qdmpzb24udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFBQSx1Q0FBcUM7QUFDckMsdUVBQXVFO0FBRXZFLGlDQUEyQztBQUMzQyxnQ0F1Qm1CO0FBQ25CLDZCQUErQjtBQUMvQiwrQkFBaUM7QUFFakMscURBQW1EO0FBa0JuRCxnRUFBa0U7QUFFbEUsOENBQWdEO0FBRWhELDBDQUF5QztBQUN6QyxxQ0FHc0I7QUFDdEIsa0NBR2tCO0FBQ2xCLG9EQWMyQjtBQUMzQixnRkFBa0Y7QUFFbEYseURBQTJEO0FBQzNELGdFQUFrRTtBQUNsRSw2REFBK0Q7QUFDL0QsNERBQThEO0FBRTlELGtFQUFrRTtBQUVsRSwwQ0FBNEM7QUFDNUMsT0FBTyxDQUFDLFNBQVMsQ0FBQztJQUNoQix5RkFBeUY7SUFDekYsb0dBQW9HO0lBQ3BHLGVBQWU7SUFDZixnQkFBZ0IsRUFBRSxJQUFJO0NBQ3ZCLENBQUMsQ0FBQztBQVVVLFFBQUEsZUFBZSxHQUFHLElBQUksQ0FBQztBQUVwQyx5QkFDRSxDQUFxQixFQUNyQixXQUE4QjtJQUU5QixJQUFNLEdBQUcsR0FBRyxDQUFDLENBQUMsSUFBSSxFQUFFLENBQUMsTUFBTSxDQUFDLFVBQUEsQ0FBQyxJQUFJLE9BQUEsV0FBVyxDQUFDLENBQUMsQ0FBQyxFQUFkLENBQWMsQ0FBQyxDQUFDO0lBQ2pELElBQU0sRUFBRSxHQUFHLENBQUMsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxNQUFNLENBQUMsVUFBQSxDQUFDLElBQUksT0FBQSxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUMsRUFBZixDQUFlLENBQUMsQ0FBQztJQUNqRCxNQUFNLENBQUMsQ0FBQyxHQUFHLEVBQUUsRUFBRSxDQUFDLENBQUM7QUFDbkIsQ0FBQztBQUVELG9CQUFvQixtQkFBbUIsRUFBRSxNQUFNO0lBQzdDLElBQU0sTUFBTSxHQUFHLFlBQU8sQ0FBQyxtQkFBbUIs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 |
\ | No newline at end of file |