@graphty/graph-io 0.3.44 → 0.3.46

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (114) hide show
  1. package/dist/chunks/{approximations-3Q4TsdTh.js → approximations-wWjCRzKj.js} +2 -2
  2. package/dist/chunks/{approximations-3Q4TsdTh.js.map → approximations-wWjCRzKj.js.map} +1 -1
  3. package/dist/chunks/{block-JQiwViEt.js → block-DiGq58c3.js} +50 -44
  4. package/dist/chunks/block-DiGq58c3.js.map +1 -0
  5. package/dist/chunks/{choose-BemygfH8.js → choose--jM0yYCo.js} +3 -3
  6. package/dist/chunks/{choose-BemygfH8.js.map → choose--jM0yYCo.js.map} +1 -1
  7. package/dist/chunks/{constants-BFUR_CtU.js → constants-BKwqelYD.js} +2 -2
  8. package/dist/chunks/{constants-BFUR_CtU.js.map → constants-BKwqelYD.js.map} +1 -1
  9. package/dist/chunks/{emit-DCwFLts5.js → emit-CwU8cUmG.js} +3 -3
  10. package/dist/chunks/{emit-DCwFLts5.js.map → emit-CwU8cUmG.js.map} +1 -1
  11. package/dist/chunks/{escape-B1rMftd9.js → escape-CgzxiYPg.js} +6 -6
  12. package/dist/chunks/{escape-B1rMftd9.js.map → escape-CgzxiYPg.js.map} +1 -1
  13. package/dist/chunks/{export-D7IGzTG4.js → export-BvqAXCKh.js} +4 -4
  14. package/dist/chunks/{export-D7IGzTG4.js.map → export-BvqAXCKh.js.map} +1 -1
  15. package/dist/chunks/{exporter-ChPyhBOv.js → exporter--Mk9gXCJ.js} +4 -4
  16. package/dist/chunks/{exporter-ChPyhBOv.js.map → exporter--Mk9gXCJ.js.map} +1 -1
  17. package/dist/chunks/{exporter-KEPxYUXD.js → exporter-CJgfhF-l.js} +7 -7
  18. package/dist/chunks/{exporter-KEPxYUXD.js.map → exporter-CJgfhF-l.js.map} +1 -1
  19. package/dist/chunks/{exporter-quPUCBiC.js → exporter-CrDWIyiq.js} +9 -9
  20. package/dist/chunks/{exporter-quPUCBiC.js.map → exporter-CrDWIyiq.js.map} +1 -1
  21. package/dist/chunks/{exporter-BtnqYuuj.js → exporter-DndFlGSa.js} +6 -6
  22. package/dist/chunks/{exporter-BtnqYuuj.js.map → exporter-DndFlGSa.js.map} +1 -1
  23. package/dist/chunks/{format-GDmO6m6Q.js → format-BpQBx8MZ.js} +35 -35
  24. package/dist/chunks/{format-GDmO6m6Q.js.map → format-BpQBx8MZ.js.map} +1 -1
  25. package/dist/chunks/{generic-BL06jrJf.js → generic-Dq1ntt9q.js} +4 -4
  26. package/dist/chunks/{generic-BL06jrJf.js.map → generic-Dq1ntt9q.js.map} +1 -1
  27. package/dist/chunks/{importer-dwoYpSqb.js → importer-BSvfrX_h.js} +7 -7
  28. package/dist/chunks/{importer-dwoYpSqb.js.map → importer-BSvfrX_h.js.map} +1 -1
  29. package/dist/chunks/{importer-CdzeN6X4.js → importer-CMmeMWlC.js} +6 -6
  30. package/dist/chunks/{importer-CdzeN6X4.js.map → importer-CMmeMWlC.js.map} +1 -1
  31. package/dist/chunks/{importer-C2nzGhdV.js → importer-COTK9Tsl.js} +17 -9
  32. package/dist/chunks/importer-COTK9Tsl.js.map +1 -0
  33. package/dist/chunks/{importer-ChKNC_GN.js → importer-DiZRmOQG.js} +8 -8
  34. package/dist/chunks/{importer-ChKNC_GN.js.map → importer-DiZRmOQG.js.map} +1 -1
  35. package/dist/chunks/{importer-CbX2_rNF.js → importer-e6LGpqHB.js} +10 -10
  36. package/dist/chunks/importer-e6LGpqHB.js.map +1 -0
  37. package/dist/chunks/{importer-B7r2owVf.js → importer-iFYPEKaJ.js} +9 -9
  38. package/dist/chunks/{importer-B7r2owVf.js.map → importer-iFYPEKaJ.js.map} +1 -1
  39. package/dist/chunks/{importer-BFmOP96W.js → importer-yh_aBCU6.js} +6 -6
  40. package/dist/chunks/{importer-BFmOP96W.js.map → importer-yh_aBCU6.js.map} +1 -1
  41. package/dist/chunks/{json-elements-C4FwgnH5.js → json-elements-DJZRZ6jd.js} +4 -4
  42. package/dist/chunks/{json-elements-C4FwgnH5.js.map → json-elements-DJZRZ6jd.js.map} +1 -1
  43. package/dist/chunks/{lexicon-B-knUi-l.js → lexicon-CT69Kd87.js} +5 -4
  44. package/dist/chunks/{lexicon-B-knUi-l.js.map → lexicon-CT69Kd87.js.map} +1 -1
  45. package/dist/chunks/{ontology-export-BSpbY5FL.js → ontology-export-G4MqRdux.js} +3 -3
  46. package/dist/chunks/{ontology-export-BSpbY5FL.js.map → ontology-export-G4MqRdux.js.map} +1 -1
  47. package/dist/chunks/{records-Nwz_rbNt.js → records-CiaWZrFH.js} +2 -2
  48. package/dist/chunks/{records-Nwz_rbNt.js.map → records-CiaWZrFH.js.map} +1 -1
  49. package/dist/chunks/{styles-_N-C8S-U.js → styles-BQnsga7p.js} +5 -5
  50. package/dist/chunks/{styles-_N-C8S-U.js.map → styles-BQnsga7p.js.map} +1 -1
  51. package/dist/chunks/{styles-Brt9JMfs.js → styles-D3fRphrO.js} +4 -4
  52. package/dist/chunks/{styles-Brt9JMfs.js.map → styles-D3fRphrO.js.map} +1 -1
  53. package/dist/chunks/{styles-yed-DAfcIkf7.js → styles-yed-BF5x3_Y5.js} +17 -17
  54. package/dist/chunks/{styles-yed-DAfcIkf7.js.map → styles-yed-BF5x3_Y5.js.map} +1 -1
  55. package/dist/chunks/{text-CgzMqHQb.js → text-CzJNFOS9.js} +2 -2
  56. package/dist/chunks/{text-CgzMqHQb.js.map → text-CzJNFOS9.js.map} +1 -1
  57. package/dist/chunks/writer-DMKvthQE.js +448 -0
  58. package/dist/chunks/writer-DMKvthQE.js.map +1 -0
  59. package/dist/csv.js +5 -5
  60. package/dist/cx.js +1 -1
  61. package/dist/cx2.js +2 -2
  62. package/dist/cys.js +1 -1
  63. package/dist/dot.js +2 -2
  64. package/dist/gexf.js +5 -5
  65. package/dist/gml.js +3884 -8
  66. package/dist/gml.js.map +1 -1
  67. package/dist/graph-io.js +90 -89
  68. package/dist/graph-io.js.map +1 -1
  69. package/dist/graphml.js +3 -3
  70. package/dist/json.js +1 -1
  71. package/dist/neo4j.js +4 -4
  72. package/dist/obo.js +1 -1
  73. package/dist/pajek.js +1 -1
  74. package/dist/src/formats/dot/styles.d.ts +1 -1
  75. package/dist/src/formats/dot/styles.d.ts.map +1 -1
  76. package/dist/src/formats/dot/styles.js +12 -0
  77. package/dist/src/formats/dot/styles.js.map +1 -1
  78. package/dist/src/formats/pajek/styles.d.ts +1 -1
  79. package/dist/src/formats/pajek/styles.d.ts.map +1 -1
  80. package/dist/src/formats/pajek/styles.js +4 -3
  81. package/dist/src/formats/pajek/styles.js.map +1 -1
  82. package/dist/src/styles/canon/color-tables.d.ts +2 -1
  83. package/dist/src/styles/canon/color-tables.d.ts.map +1 -1
  84. package/dist/src/styles/canon/color-tables.js +7 -2
  85. package/dist/src/styles/canon/color-tables.js.map +1 -1
  86. package/dist/src/styles/cyjs/emit.d.ts.map +1 -1
  87. package/dist/src/styles/cyjs/emit.js +2 -1
  88. package/dist/src/styles/cyjs/emit.js.map +1 -1
  89. package/dist/src/styles/cytoscape/lexicon.d.ts.map +1 -1
  90. package/dist/src/styles/cytoscape/lexicon.js +3 -1
  91. package/dist/src/styles/cytoscape/lexicon.js.map +1 -1
  92. package/dist/src/styles/defaults.d.ts.map +1 -1
  93. package/dist/src/styles/defaults.js +7 -0
  94. package/dist/src/styles/defaults.js.map +1 -1
  95. package/dist/src/styles/io/writer.d.ts +9 -0
  96. package/dist/src/styles/io/writer.d.ts.map +1 -1
  97. package/dist/src/styles/io/writer.js +31 -1
  98. package/dist/src/styles/io/writer.js.map +1 -1
  99. package/dist/styles.js +21 -21
  100. package/dist/styles.js.map +1 -1
  101. package/dist/xgmml.js +3 -3
  102. package/package.json +1 -1
  103. package/src/formats/dot/styles.ts +15 -1
  104. package/src/formats/pajek/styles.ts +4 -3
  105. package/src/styles/canon/color-tables.ts +7 -2
  106. package/src/styles/cyjs/emit.ts +2 -1
  107. package/src/styles/cytoscape/lexicon.ts +3 -1
  108. package/src/styles/defaults.ts +8 -0
  109. package/src/styles/io/writer.ts +36 -1
  110. package/dist/chunks/block-JQiwViEt.js.map +0 -1
  111. package/dist/chunks/importer-C2nzGhdV.js.map +0 -1
  112. package/dist/chunks/importer-CbX2_rNF.js.map +0 -1
  113. package/dist/chunks/index-B9fdNpTA.js +0 -4310
  114. package/dist/chunks/index-B9fdNpTA.js.map +0 -1
package/dist/styles.js CHANGED
@@ -1,9 +1,9 @@
1
- import { j as StyleNotes, q as featuresOf, k as styleFingerprint } from "./chunks/block-JQiwViEt.js";
2
- import { t, S, u, a, v, T, i, r, w } from "./chunks/block-JQiwViEt.js";
3
- import { S as StyleBudget, e as evaluateCytoscapeJs } from "./chunks/emit-DCwFLts5.js";
4
- import { C, t as t2 } from "./chunks/emit-DCwFLts5.js";
5
- import { p as planStyles } from "./chunks/generic-BL06jrJf.js";
6
- import { M, e } from "./chunks/generic-BL06jrJf.js";
1
+ import { t as StyleNotes, y as featuresOf, s as styleFingerprint } from "./chunks/block-DiGq58c3.js";
2
+ import { z, S, A, a, B, T, q, r, C } from "./chunks/block-DiGq58c3.js";
3
+ import { S as StyleBudget, e as evaluateCytoscapeJs } from "./chunks/emit-CwU8cUmG.js";
4
+ import { C as C2, t } from "./chunks/emit-CwU8cUmG.js";
5
+ import { p as planStyles } from "./chunks/generic-Dq1ntt9q.js";
6
+ import { M, e } from "./chunks/generic-Dq1ntt9q.js";
7
7
  const CYTOSCAPE_ANNOTATIONS_COLUMN = "__Annotations";
8
8
  const TYPE_PREFIX = "org.cytoscape.view.presentation.annotations.";
9
9
  const SHAPES = /* @__PURE__ */ new Map([
@@ -51,11 +51,11 @@ function readAnnotations(snapshot) {
51
51
  const cell = graph.has(CYTOSCAPE_ANNOTATIONS_COLUMN) ? graph.value(CYTOSCAPE_ANNOTATIONS_COLUMN, 0) : null;
52
52
  const entries = cellStrings(cell);
53
53
  const fields = entries.map(parseEntry);
54
- const byId = new Map(fields.map((f, i2) => [f.get("uuid") ?? String(i2), f]));
54
+ const byId = new Map(fields.map((f, i) => [f.get("uuid") ?? String(i), f]));
55
55
  const annotations = [];
56
56
  const skipped = /* @__PURE__ */ new Set();
57
- fields.forEach((f, i2) => {
58
- const read = readOne(f, String(i2), byId);
57
+ fields.forEach((f, i) => {
58
+ const read = readOne(f, String(i), byId);
59
59
  if (read === null) {
60
60
  skipped.add((f.get("type") ?? "").replace(TYPE_PREFIX, ""));
61
61
  } else {
@@ -237,8 +237,8 @@ function withFunctions(style) {
237
237
  }
238
238
  const copy = /* @__PURE__ */ Object.create(null);
239
239
  for (const name of Object.keys(props)) {
240
- const v2 = props[name];
241
- copy[name] = v2 === "fn" ? FUNCTION : v2;
240
+ const v = props[name];
241
+ copy[name] = v === "fn" ? FUNCTION : v;
242
242
  }
243
243
  return { selector: e2.selector, style: copy };
244
244
  });
@@ -260,9 +260,9 @@ function readCytoscapeStyles(input) {
260
260
  if (input.rendered !== void 0) {
261
261
  rendered = /* @__PURE__ */ new Map();
262
262
  const list = elementList(input.elements);
263
- for (let i2 = 0; i2 < list.length && i2 < input.rendered.length; i2++) {
264
- const json = list[i2];
265
- const r22 = input.rendered[i2];
263
+ for (let i = 0; i < list.length && i < input.rendered.length; i++) {
264
+ const json = list[i];
265
+ const r22 = input.rendered[i];
266
266
  if (json !== null && typeof json === "object" && r22 !== null && r22 !== void 0 && typeof r22 === "object") {
267
267
  rendered.set(json, r22);
268
268
  }
@@ -300,23 +300,23 @@ function readCytoscapeStyles(input) {
300
300
  );
301
301
  }
302
302
  export {
303
- C as CYTOSCAPE_IMPORT_KEY,
304
- t as MAX_STYLE_BLOCK_LENGTH,
303
+ C2 as CYTOSCAPE_IMPORT_KEY,
304
+ z as MAX_STYLE_BLOCK_LENGTH,
305
305
  M as MAX_STYLE_RULES,
306
306
  S as STYLE_BLOCK_NAME,
307
- u as STYLE_ENUMS,
307
+ A as STYLE_ENUMS,
308
308
  a as STYLE_ISSUE,
309
- v as STYLE_PROPERTIES,
309
+ B as STYLE_PROPERTIES,
310
310
  T as TOOL_DEFAULTS,
311
311
  e as extractStyles,
312
312
  featuresOf,
313
- i as isStyleValue,
313
+ q as isStyleValue,
314
314
  planStyles,
315
315
  readAnnotations,
316
316
  readCytoscapeStyles,
317
317
  r as resolveStyles,
318
318
  styleFingerprint,
319
- t2 as toCytoscapeStylesheet,
320
- w as toolDefaults
319
+ t as toCytoscapeStylesheet,
320
+ C as toolDefaults
321
321
  };
322
322
  //# sourceMappingURL=styles.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"styles.js","sources":["../src/styles/annotations.ts","../src/styles/cyjs/live.ts"],"sourcesContent":["/**\n * The annotations a file draws beside its graph: shapes, text notes and arrows that are not nodes or edges. Cytoscape\n * desktop keeps them in the network's `__Annotations` column (sessions, XGMML, CX and CX2 all carry it), one\n * `key=value|key=value` string per annotation; this reads them as neutral facts in the position convention (y up,\n * the file's own units), so they line up with `extractPositions()`.\n */\n\nimport type { GraphSnapshot } from \"@graphty/graph-format\";\n\nimport type { StyleArrowShape, StyleColor, StyleNodeShape } from \"./types.js\";\n\n/**\n * A point in the position convention: y up, in the file's own units.\n * @category Styles\n */\nexport interface AnnotationPoint {\n /** The x coordinate. */\n readonly x: number;\n /** The y coordinate, y up. */\n readonly y: number;\n}\n\n/**\n * What every annotation has.\n * @category Styles\n */\nexport interface AnnotationBase {\n /** The file's id for the annotation, or its index when the file gives none. */\n readonly id: string;\n /** Whether it is drawn behind the graph or in front of it. */\n readonly layer: \"background\" | \"foreground\";\n /** Its drawing order within its layer, lowest first. */\n readonly z: number;\n}\n\n/**\n * A filled, outlined shape.\n * @category Styles\n */\nexport interface ShapeAnnotation extends AnnotationBase {\n /** Which kind of annotation this is: always \"shape\". */\n readonly kind: \"shape\";\n /** The box's center. */\n readonly center: AnnotationPoint;\n /** The box's width. */\n readonly width: number;\n /** The box's height. */\n readonly height: number;\n /** The outline's shape. */\n readonly shape: StyleNodeShape;\n /** The fill color, or null for none. */\n readonly fill: StyleColor | null;\n /** The fill's opacity, 0..1. */\n readonly fillOpacity: number;\n /** The outline's color. */\n readonly borderColor: StyleColor;\n /** The outline's opacity, 0..1. */\n readonly borderOpacity: number;\n /** The outline's width. */\n readonly borderWidth: number;\n}\n\n/**\n * A line of text.\n * @category Styles\n */\nexport interface TextAnnotation extends AnnotationBase {\n /** Which kind of annotation this is: always \"text\". */\n readonly kind: \"text\";\n /** The text. */\n readonly text: string;\n /** Where the text is placed: the top-left corner of its box, or its center. */\n readonly at: AnnotationPoint;\n /** What `at` is. */\n readonly anchor: \"top-left\" | \"center\";\n /** The font size, in the file's units. */\n readonly fontSize: number;\n /** The font family. */\n readonly fontFamily: string;\n /** Whether the text is bold. */\n readonly bold: boolean;\n /** Whether the text is italic. */\n readonly italic: boolean;\n /** The text color. */\n readonly color: StyleColor;\n /** The text's opacity, 0..1. */\n readonly opacity: number;\n}\n\n/**\n * A line between two points, with an arrowhead at either end.\n * @category Styles\n */\nexport interface ArrowAnnotation extends AnnotationBase {\n /** Which kind of annotation this is: always \"arrow\". */\n readonly kind: \"arrow\";\n /** Where the line starts. */\n readonly from: AnnotationPoint;\n /** Where it ends. */\n readonly to: AnnotationPoint;\n /** The line color. */\n readonly color: StyleColor;\n /** The line's opacity, 0..1. */\n readonly opacity: number;\n /** The line width. */\n readonly width: number;\n /** The arrowhead at the start. */\n readonly sourceArrow: StyleArrowShape;\n /** The arrowhead at the end. */\n readonly targetArrow: StyleArrowShape;\n /** The start's arrowhead size as a factor of the normal size. */\n readonly sourceSize: number;\n /** The end's arrowhead size as a factor of the normal size. */\n readonly targetSize: number;\n}\n\n/**\n * One annotation.\n * @category Styles\n */\nexport type GraphAnnotation = ShapeAnnotation | TextAnnotation | ArrowAnnotation;\n\n/**\n * A file's annotations, and the kinds it holds that are not read (images, groups of annotations), by the file's\n * own type name, once each.\n * @category Styles\n */\nexport interface FileAnnotations {\n /** The annotations read, in the file's order. */\n readonly annotations: readonly GraphAnnotation[];\n /** The file's type names of the annotations not read. */\n readonly skipped: readonly string[];\n}\n\n/** The graph column Cytoscape desktop keeps its annotations in. */\nconst CYTOSCAPE_ANNOTATIONS_COLUMN = \"__Annotations\";\n\nconst TYPE_PREFIX = \"org.cytoscape.view.presentation.annotations.\";\n\n/** Cytoscape's annotation shape names, lowercase, as neutral shapes. */\nconst SHAPES: ReadonlyMap<string, StyleNodeShape> = new Map<string, StyleNodeShape>([\n [\"rectangle\", \"rectangle\"],\n [\"roundedrectangle\", \"round-rectangle\"],\n [\"rounded_rectangle\", \"round-rectangle\"],\n [\"ellipse\", \"ellipse\"],\n [\"triangle\", \"triangle\"],\n [\"diamond\", \"diamond\"],\n [\"pentagon\", \"pentagon\"],\n [\"hexagon\", \"hexagon\"],\n [\"octagon\", \"octagon\"],\n [\"parallelogram\", \"parallelogram\"],\n [\"star5\", \"star\"],\n [\"star6\", \"star\"],\n]);\n\n/**\n * Cytoscape's annotation arrowheads, by the position in its `ArrowType` list (older sessions) and by name (newer\n * ones), lowercase.\n */\nconst ARROW_ORDER: readonly StyleArrowShape[] = [\n \"circle\",\n \"triangle\",\n \"vee\",\n \"diamond\",\n \"triangle-open\",\n \"none\",\n \"tee\",\n \"triangle\",\n \"triangle\",\n \"triangle\",\n \"tee\",\n \"other:x\",\n];\nconst ARROW_NAMES: ReadonlyMap<string, StyleArrowShape> = new Map<string, StyleArrowShape>([\n [\"circle\", \"circle\"],\n [\"closed arrow\", \"triangle\"],\n [\"concave arrow\", \"vee\"],\n [\"diamond\", \"diamond\"],\n [\"open arrow\", \"triangle-open\"],\n [\"no arrow\", \"none\"],\n [\"pipe\", \"tee\"],\n [\"triangle\", \"triangle\"],\n [\"t\", \"tee\"],\n [\"x\", \"other:x\"],\n]);\n\n/**\n * The annotations a graph holds, from the column Cytoscape desktop keeps them in.\n * @param snapshot - the graph\n * @returns the annotations; none when the graph has the column empty or not at all\n * @category Styles\n */\nexport function readAnnotations(snapshot: GraphSnapshot): FileAnnotations {\n const { graph } = snapshot;\n const cell = graph.has(CYTOSCAPE_ANNOTATIONS_COLUMN) ? graph.value(CYTOSCAPE_ANNOTATIONS_COLUMN, 0) : null;\n const entries = cellStrings(cell);\n const fields = entries.map(parseEntry);\n const byId = new Map(fields.map((f, i) => [f.get(\"uuid\") ?? String(i), f]));\n const annotations: GraphAnnotation[] = [];\n const skipped = new Set<string>();\n fields.forEach((f, i) => {\n const read = readOne(f, String(i), byId);\n if (read === null) {\n skipped.add((f.get(\"type\") ?? \"\").replace(TYPE_PREFIX, \"\"));\n } else {\n annotations.push(...read);\n }\n });\n return { annotations, skipped: [...skipped] };\n}\n\n/**\n * A cell's strings: a list cell's items, or the lines of a text cell.\n * @param cell - the cell\n * @returns the strings\n */\nfunction cellStrings(cell: unknown): string[] {\n if (typeof cell === \"string\") {\n return cell.split(/[\\r\\n]+/).filter((s) => s !== \"\");\n }\n if (cell !== null && typeof cell === \"object\" && Symbol.iterator in cell) {\n return Array.from(cell as Iterable<unknown>).filter((s): s is string => typeof s === \"string\" && s !== \"\");\n }\n return [];\n}\n\n/**\n * One annotation string's fields.\n * @param entry - `key=value|key=value`\n * @returns the fields\n */\nfunction parseEntry(entry: string): Map<string, string> {\n const out = new Map<string, string>();\n for (const part of entry.split(\"|\")) {\n const eq = part.indexOf(\"=\");\n if (eq > 0) {\n out.set(part.slice(0, eq), part.slice(eq + 1));\n }\n }\n return out;\n}\n\n/**\n * One annotation as neutral facts; a bounded text annotation is a shape and its text.\n * @param f - its fields\n * @param index - its position, its id when it has no uuid\n * @param byId - every annotation's fields by id, for an arrow's ends\n * @returns the annotations, or null for a kind not read\n */\nfunction readOne(\n f: ReadonlyMap<string, string>,\n index: string,\n byId: ReadonlyMap<string, ReadonlyMap<string, string>>,\n): GraphAnnotation[] | null {\n const type = (f.get(\"type\") ?? \"\").replace(TYPE_PREFIX, \"\");\n const zoom = positive(f.get(\"zoom\")) ?? 1;\n const base: AnnotationBase = {\n id: f.get(\"uuid\") ?? index,\n layer: f.get(\"canvas\") === \"background\" ? \"background\" : \"foreground\",\n z: num(f.get(\"z\")) ?? 0,\n };\n switch (type) {\n case \"ShapeAnnotation\":\n return [shapeOf(f, base, zoom)];\n case \"TextAnnotation\":\n return [textOf(f, base, zoom, { x: num(f.get(\"x\")) ?? 0, y: -(num(f.get(\"y\")) ?? 0) }, \"top-left\")];\n case \"BoundedTextAnnotation\": {\n const shape = shapeOf(f, base, zoom);\n return [shape, textOf(f, { ...base, id: `${base.id}:text` }, zoom, shape.center, \"center\")];\n }\n case \"ArrowAnnotation\":\n return arrowOf(f, base, zoom, byId);\n default:\n return null;\n }\n}\n\n/**\n * A shape annotation: `x`, `y` its top-left corner, y down; `width`, `height` and the outline at the saved zoom.\n * @param f - its fields\n * @param base - its id, layer and order\n * @param zoom - the zoom its sizes were saved at\n * @returns the shape\n */\nfunction shapeOf(f: ReadonlyMap<string, string>, base: AnnotationBase, zoom: number): ShapeAnnotation {\n const x = num(f.get(\"x\")) ?? 0;\n const y = num(f.get(\"y\")) ?? 0;\n const width = (positive(f.get(\"width\")) ?? 0) / zoom;\n const height = (positive(f.get(\"height\")) ?? 0) / zoom;\n const fill = javaColor(f.get(\"fillColor\"));\n const border = javaColor(f.get(\"edgeColor\")) ?? { color: \"#000000\", alpha: 1 };\n return {\n ...base,\n kind: \"shape\",\n center: { x: x + width / 2, y: -(y + height / 2) },\n width,\n height,\n shape: SHAPES.get((f.get(\"shapeType\") ?? \"rectangle\").toLowerCase()) ?? \"rectangle\",\n fill: fill?.color ?? null,\n fillOpacity: fill === null ? 0 : fill.alpha * percent(f.get(\"fillOpacity\")),\n borderColor: border.color,\n borderOpacity: border.alpha * percent(f.get(\"edgeOpacity\")),\n borderWidth: (num(f.get(\"edgeThickness\")) ?? 1) / zoom,\n };\n}\n\n/**\n * A text annotation, or the text of a bounded one.\n * @param f - its fields\n * @param base - its id, layer and order\n * @param zoom - the zoom its font size was saved at\n * @param at - where it is placed\n * @param anchor - what `at` is\n * @returns the text\n */\nfunction textOf(\n f: ReadonlyMap<string, string>,\n base: AnnotationBase,\n zoom: number,\n at: AnnotationPoint,\n anchor: TextAnnotation[\"anchor\"],\n): TextAnnotation {\n // java.awt.Font styles: 1 bold, 2 italic, 3 both\n const style = num(f.get(\"fontStyle\")) ?? 0;\n const color = javaColor(f.get(\"color\")) ?? { color: \"#000000\", alpha: 1 };\n return {\n ...base,\n kind: \"text\",\n text: f.get(\"text\") ?? \"\",\n at,\n anchor,\n fontSize: (positive(f.get(\"fontSize\")) ?? 12) / zoom,\n fontFamily: f.get(\"fontFamily\") ?? \"sans-serif\",\n bold: (style & 1) !== 0,\n italic: (style & 2) !== 0,\n color: color.color,\n opacity: color.alpha,\n };\n}\n\n/**\n * An arrow annotation. Cytoscape keeps its start as the annotation it leaves (`sourceAnnotation`) and its end as a\n * point, a node's center at save time (`targetNode`) or another annotation, and saves the arrow's top-left corner\n * as `x`, `y`: the start wherever the end lies right of and below it, which is taken for the start, else the center\n * of the annotation it leaves.\n * @param f - its fields\n * @param base - its id, layer and order\n * @param zoom - the zoom its line width was saved at\n * @param byId - every annotation's fields by id\n * @returns the arrow, or null when it has no end\n */\nfunction arrowOf(\n f: ReadonlyMap<string, string>,\n base: AnnotationBase,\n zoom: number,\n byId: ReadonlyMap<string, ReadonlyMap<string, string>>,\n): ArrowAnnotation[] | null {\n const target = f.get(\"targetAnnotation\");\n const to = point(f.get(\"targetPoint\")) ?? point(f.get(\"targetNode\")) ?? centerOf(byId.get(target ?? \"\"), zoom);\n if (to === null) {\n return null;\n }\n const corner = { x: num(f.get(\"x\")) ?? 0, y: num(f.get(\"y\")) ?? 0 };\n const source = centerOf(byId.get(f.get(\"sourceAnnotation\") ?? \"\"), zoom) ?? corner;\n // ponytail: the start is exact only when the end lies right of and below it; elsewhere the center of the\n // annotation it leaves, as Cytoscape stores no other start. Clip to that annotation's box if it matters.\n const from = { x: to.x > corner.x ? corner.x : source.x, y: to.y > corner.y ? corner.y : source.y };\n const color = javaColor(f.get(\"lineColor\")) ?? { color: \"#000000\", alpha: 1 };\n return [\n {\n ...base,\n kind: \"arrow\",\n from: { x: from.x, y: -from.y },\n to: { x: to.x, y: -to.y },\n color: color.color,\n opacity: color.alpha * percent(f.get(\"lineOpacity\")),\n width: (positive(f.get(\"lineThickness\")) ?? 1) / zoom,\n sourceArrow: arrowShape(f.get(\"sourceType\")),\n targetArrow: arrowShape(f.get(\"targetType\")),\n sourceSize: positive(f.get(\"sourceSize\")) ?? 1,\n targetSize: positive(f.get(\"targetSize\")) ?? 1,\n },\n ];\n}\n\n/**\n * An annotation's center, y down as the file writes it: a shape's box center, a text's corner.\n * @param f - its fields, or undefined\n * @param zoom - the zoom the arrow was saved at\n * @returns the point, or null\n */\nfunction centerOf(f: ReadonlyMap<string, string> | undefined, zoom: number): AnnotationPoint | null {\n if (f === undefined) {\n return null;\n }\n const x = num(f.get(\"x\"));\n const y = num(f.get(\"y\"));\n if (x === null || y === null) {\n return null;\n }\n return { x: x + (positive(f.get(\"width\")) ?? 0) / zoom / 2, y: y + (positive(f.get(\"height\")) ?? 0) / zoom / 2 };\n}\n\n/**\n * An arrowhead by its `ArrowType` position or name.\n * @param raw - the field\n * @returns the shape; a triangle for one not known\n */\nfunction arrowShape(raw: string | undefined): StyleArrowShape {\n if (raw === undefined) {\n return \"none\";\n }\n const n = num(raw);\n if (n !== null) {\n return ARROW_ORDER[n] ?? \"triangle\";\n }\n return ARROW_NAMES.get(raw.trim().toLowerCase()) ?? \"triangle\";\n}\n\n/**\n * A `x,y` point as the file writes it.\n * @param raw - the field\n * @returns the point, or null\n */\nfunction point(raw: string | undefined): AnnotationPoint | null {\n const [x, y] = (raw ?? \"\").split(\",\").map((s) => num(s));\n return x === null || x === undefined || y === null || y === undefined ? null : { x, y };\n}\n\n/**\n * A Java color as a signed ARGB integer.\n * @param raw - the field\n * @returns the color and its alpha, or null\n */\nfunction javaColor(raw: string | undefined): { color: StyleColor; alpha: number } | null {\n const n = num(raw);\n if (n === null || !Number.isInteger(n)) {\n return null;\n }\n const argb = n >>> 0;\n return {\n color: `#${(argb & 0xffffff).toString(16).padStart(6, \"0\")}`,\n alpha: (argb >>> 24) / 255,\n };\n}\n\n/**\n * A 0..100 percentage as 0..1; 1 when absent.\n * @param raw - the field\n * @returns the fraction\n */\nfunction percent(raw: string | undefined): number {\n const n = num(raw);\n return n === null ? 1 : Math.min(1, Math.max(0, n / 100));\n}\n\n/**\n * A finite number.\n * @param raw - the field\n * @returns the number, or null\n */\nfunction num(raw: string | undefined): number | null {\n if (raw === undefined || raw.trim() === \"\") {\n return null;\n }\n const n = Number(raw);\n return Number.isFinite(n) ? n : null;\n}\n\n/**\n * A positive number.\n * @param raw - the field\n * @returns the number, or null\n */\nfunction positive(raw: string | undefined): number | null {\n const n = num(raw);\n return n !== null && n > 0 ? n : null;\n}\n","/**\n * The styles of a live Cytoscape.js core: the rules from its stylesheet (`cy.style().json()`) and, when given, the\n * truth per element from what the core reports it draws (`ele.style()`). Reported values win over the stylesheet\n * where they disagree, so a property whose stylesheet value is a function (which `cy.style().json()` writes as \"fn\")\n * is still exact: it is copied per element from the reported values and noted as `W_STYLE_LAYER_FLATTENED` with the\n * sample (and the rule reason) `FUNCTION`.\n */\n\nimport type { GraphSnapshot } from \"@graphty/graph-format\";\n\nimport { StyleBudget } from \"../budget.js\";\nimport { StyleNotes } from \"../notes.js\";\nimport { featuresOf, styleFingerprint } from \"../plan/features.js\";\nimport { planStyles } from \"../plan/plan.js\";\nimport type { ExtractedStyles, StyleWorkBudget } from \"../types.js\";\nimport { evaluateCytoscapeJs } from \"./cascade.js\";\n\n/** The input of `readCytoscapeStyles()`. */\nexport interface CytoscapeLiveInput {\n /** The core's elements: `cy.elements().jsons()`, or `{ nodes, edges }`. */\n readonly elements: unknown;\n /** The core's stylesheet: `cy.style().json()` (a function is written there as \"fn\"), or the one it was given. */\n readonly style: unknown;\n /**\n * What the core draws for each element, `ele.style()`, in the order of `elements` (for `{ nodes, edges }`, the\n * nodes then the edges); optional, and null for an element with none.\n */\n readonly rendered?: readonly (Readonly<Record<string, unknown>> | null | undefined)[];\n /** The graph the styles are for (the core's elements as a snapshot); the values come out indexed like it. */\n readonly snapshot: GraphSnapshot;\n /** The graph-io format id recorded as the styles' source; default \"json\". */\n readonly format?: string;\n /** Whether Cytoscape.js's defaults fill what the stylesheet leaves unset; default true. */\n readonly toolDefaults?: boolean;\n /**\n * Where problems are noted; graph-io's own engine passes its notes here.\n * @internal\n */\n readonly notes?: StyleNotes;\n /** The counted work budget. */\n readonly budget?: StyleWorkBudget;\n /** Cancels the work. */\n readonly signal?: AbortSignal;\n}\n\n/**\n * What a stylesheet function is read as: a function, whatever it returned.\n * @returns nothing\n */\nconst FUNCTION = (): null => null;\n\n/**\n * The stylesheet with every \"fn\" value (how `cy.style().json()` writes a function) read as a function.\n * @param style - the stylesheet\n * @returns the stylesheet to apply\n */\nfunction withFunctions(style: unknown): unknown {\n if (!Array.isArray(style)) {\n return style;\n }\n return style.map((entry: unknown) => {\n if (entry === null || typeof entry !== \"object\") {\n return entry;\n }\n const e = entry as Record<string, unknown>;\n const props = e.style ?? e.css;\n if (props === null || typeof props !== \"object\") {\n return entry;\n }\n const copy = Object.create(null) as Record<string, unknown>;\n for (const name of Object.keys(props)) {\n const v = (props as Record<string, unknown>)[name];\n copy[name] = v === \"fn\" ? FUNCTION : v;\n }\n return { selector: e.selector, style: copy };\n });\n}\n\n/**\n * The element list in order: an array as it is, `{ nodes, edges }` as the nodes then the edges.\n * @param elements - the elements\n * @returns the list\n */\nfunction elementList(elements: unknown): readonly unknown[] {\n if (Array.isArray(elements)) {\n return elements;\n }\n if (elements !== null && typeof elements === \"object\") {\n const e = elements as Record<string, unknown>;\n return [...(Array.isArray(e.nodes) ? e.nodes : []), ...(Array.isArray(e.edges) ? e.edges : [])];\n }\n return [];\n}\n\n/**\n * Reads the styles of a live Cytoscape.js core: the stylesheet's rules, with what the core reports it draws as the\n * truth per element when given.\n * @param input - the elements, the stylesheet, the reported values and the graph\n * @returns the styles, exact for every element\n * @category Styles\n */\nexport function readCytoscapeStyles(input: CytoscapeLiveInput): ExtractedStyles {\n const notes = input.notes ?? new StyleNotes();\n const budget = input.budget ?? new StyleBudget();\n let rendered: Map<object, Readonly<Record<string, unknown>>> | undefined;\n if (input.rendered !== undefined) {\n rendered = new Map();\n const list = elementList(input.elements);\n for (let i = 0; i < list.length && i < input.rendered.length; i++) {\n const json = list[i];\n const r = input.rendered[i];\n if (json !== null && typeof json === \"object\" && r !== null && r !== undefined && typeof r === \"object\") {\n rendered.set(json, r);\n }\n }\n }\n const r = evaluateCytoscapeJs({\n elements: input.elements,\n style: withFunctions(input.style),\n snapshot: input.snapshot,\n toolDefaults: input.toolDefaults,\n rendered,\n notes,\n budget,\n signal: input.signal,\n });\n const s = input.snapshot;\n return planStyles(\n {\n format: input.format ?? \"json\",\n dialect: \"cytoscape-js\",\n tool: \"cytoscape-js\",\n units: \"px\",\n node: { values: r.node.values, rules: r.node.rules, columns: r.node.columns },\n edge: { values: r.edge.values, rules: r.edge.rules, columns: r.edge.columns },\n fingerprint: styleFingerprint(s),\n },\n { node: featuresOf(s, \"node\"), edge: featuresOf(s, \"edge\") },\n {\n toolDefaults: input.toolDefaults,\n notes,\n budget,\n signal: input.signal,\n rawColumns: { node: r.node.rawColumns, edge: r.edge.rawColumns },\n },\n );\n}\n"],"names":["i","e","v","r"],"mappings":"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"}
1
+ {"version":3,"file":"styles.js","sources":["../src/styles/annotations.ts","../src/styles/cyjs/live.ts"],"sourcesContent":["/**\n * The annotations a file draws beside its graph: shapes, text notes and arrows that are not nodes or edges. Cytoscape\n * desktop keeps them in the network's `__Annotations` column (sessions, XGMML, CX and CX2 all carry it), one\n * `key=value|key=value` string per annotation; this reads them as neutral facts in the position convention (y up,\n * the file's own units), so they line up with `extractPositions()`.\n */\n\nimport type { GraphSnapshot } from \"@graphty/graph-format\";\n\nimport type { StyleArrowShape, StyleColor, StyleNodeShape } from \"./types.js\";\n\n/**\n * A point in the position convention: y up, in the file's own units.\n * @category Styles\n */\nexport interface AnnotationPoint {\n /** The x coordinate. */\n readonly x: number;\n /** The y coordinate, y up. */\n readonly y: number;\n}\n\n/**\n * What every annotation has.\n * @category Styles\n */\nexport interface AnnotationBase {\n /** The file's id for the annotation, or its index when the file gives none. */\n readonly id: string;\n /** Whether it is drawn behind the graph or in front of it. */\n readonly layer: \"background\" | \"foreground\";\n /** Its drawing order within its layer, lowest first. */\n readonly z: number;\n}\n\n/**\n * A filled, outlined shape.\n * @category Styles\n */\nexport interface ShapeAnnotation extends AnnotationBase {\n /** Which kind of annotation this is: always \"shape\". */\n readonly kind: \"shape\";\n /** The box's center. */\n readonly center: AnnotationPoint;\n /** The box's width. */\n readonly width: number;\n /** The box's height. */\n readonly height: number;\n /** The outline's shape. */\n readonly shape: StyleNodeShape;\n /** The fill color, or null for none. */\n readonly fill: StyleColor | null;\n /** The fill's opacity, 0..1. */\n readonly fillOpacity: number;\n /** The outline's color. */\n readonly borderColor: StyleColor;\n /** The outline's opacity, 0..1. */\n readonly borderOpacity: number;\n /** The outline's width. */\n readonly borderWidth: number;\n}\n\n/**\n * A line of text.\n * @category Styles\n */\nexport interface TextAnnotation extends AnnotationBase {\n /** Which kind of annotation this is: always \"text\". */\n readonly kind: \"text\";\n /** The text. */\n readonly text: string;\n /** Where the text is placed: the top-left corner of its box, or its center. */\n readonly at: AnnotationPoint;\n /** What `at` is. */\n readonly anchor: \"top-left\" | \"center\";\n /** The font size, in the file's units. */\n readonly fontSize: number;\n /** The font family. */\n readonly fontFamily: string;\n /** Whether the text is bold. */\n readonly bold: boolean;\n /** Whether the text is italic. */\n readonly italic: boolean;\n /** The text color. */\n readonly color: StyleColor;\n /** The text's opacity, 0..1. */\n readonly opacity: number;\n}\n\n/**\n * A line between two points, with an arrowhead at either end.\n * @category Styles\n */\nexport interface ArrowAnnotation extends AnnotationBase {\n /** Which kind of annotation this is: always \"arrow\". */\n readonly kind: \"arrow\";\n /** Where the line starts. */\n readonly from: AnnotationPoint;\n /** Where it ends. */\n readonly to: AnnotationPoint;\n /** The line color. */\n readonly color: StyleColor;\n /** The line's opacity, 0..1. */\n readonly opacity: number;\n /** The line width. */\n readonly width: number;\n /** The arrowhead at the start. */\n readonly sourceArrow: StyleArrowShape;\n /** The arrowhead at the end. */\n readonly targetArrow: StyleArrowShape;\n /** The start's arrowhead size as a factor of the normal size. */\n readonly sourceSize: number;\n /** The end's arrowhead size as a factor of the normal size. */\n readonly targetSize: number;\n}\n\n/**\n * One annotation.\n * @category Styles\n */\nexport type GraphAnnotation = ShapeAnnotation | TextAnnotation | ArrowAnnotation;\n\n/**\n * A file's annotations, and the kinds it holds that are not read (images, groups of annotations), by the file's\n * own type name, once each.\n * @category Styles\n */\nexport interface FileAnnotations {\n /** The annotations read, in the file's order. */\n readonly annotations: readonly GraphAnnotation[];\n /** The file's type names of the annotations not read. */\n readonly skipped: readonly string[];\n}\n\n/** The graph column Cytoscape desktop keeps its annotations in. */\nconst CYTOSCAPE_ANNOTATIONS_COLUMN = \"__Annotations\";\n\nconst TYPE_PREFIX = \"org.cytoscape.view.presentation.annotations.\";\n\n/** Cytoscape's annotation shape names, lowercase, as neutral shapes. */\nconst SHAPES: ReadonlyMap<string, StyleNodeShape> = new Map<string, StyleNodeShape>([\n [\"rectangle\", \"rectangle\"],\n [\"roundedrectangle\", \"round-rectangle\"],\n [\"rounded_rectangle\", \"round-rectangle\"],\n [\"ellipse\", \"ellipse\"],\n [\"triangle\", \"triangle\"],\n [\"diamond\", \"diamond\"],\n [\"pentagon\", \"pentagon\"],\n [\"hexagon\", \"hexagon\"],\n [\"octagon\", \"octagon\"],\n [\"parallelogram\", \"parallelogram\"],\n [\"star5\", \"star\"],\n [\"star6\", \"star\"],\n]);\n\n/**\n * Cytoscape's annotation arrowheads, by the position in its `ArrowType` list (older sessions) and by name (newer\n * ones), lowercase.\n */\nconst ARROW_ORDER: readonly StyleArrowShape[] = [\n \"circle\",\n \"triangle\",\n \"vee\",\n \"diamond\",\n \"triangle-open\",\n \"none\",\n \"tee\",\n \"triangle\",\n \"triangle\",\n \"triangle\",\n \"tee\",\n \"other:x\",\n];\nconst ARROW_NAMES: ReadonlyMap<string, StyleArrowShape> = new Map<string, StyleArrowShape>([\n [\"circle\", \"circle\"],\n [\"closed arrow\", \"triangle\"],\n [\"concave arrow\", \"vee\"],\n [\"diamond\", \"diamond\"],\n [\"open arrow\", \"triangle-open\"],\n [\"no arrow\", \"none\"],\n [\"pipe\", \"tee\"],\n [\"triangle\", \"triangle\"],\n [\"t\", \"tee\"],\n [\"x\", \"other:x\"],\n]);\n\n/**\n * The annotations a graph holds, from the column Cytoscape desktop keeps them in.\n * @param snapshot - the graph\n * @returns the annotations; none when the graph has the column empty or not at all\n * @category Styles\n */\nexport function readAnnotations(snapshot: GraphSnapshot): FileAnnotations {\n const { graph } = snapshot;\n const cell = graph.has(CYTOSCAPE_ANNOTATIONS_COLUMN) ? graph.value(CYTOSCAPE_ANNOTATIONS_COLUMN, 0) : null;\n const entries = cellStrings(cell);\n const fields = entries.map(parseEntry);\n const byId = new Map(fields.map((f, i) => [f.get(\"uuid\") ?? String(i), f]));\n const annotations: GraphAnnotation[] = [];\n const skipped = new Set<string>();\n fields.forEach((f, i) => {\n const read = readOne(f, String(i), byId);\n if (read === null) {\n skipped.add((f.get(\"type\") ?? \"\").replace(TYPE_PREFIX, \"\"));\n } else {\n annotations.push(...read);\n }\n });\n return { annotations, skipped: [...skipped] };\n}\n\n/**\n * A cell's strings: a list cell's items, or the lines of a text cell.\n * @param cell - the cell\n * @returns the strings\n */\nfunction cellStrings(cell: unknown): string[] {\n if (typeof cell === \"string\") {\n return cell.split(/[\\r\\n]+/).filter((s) => s !== \"\");\n }\n if (cell !== null && typeof cell === \"object\" && Symbol.iterator in cell) {\n return Array.from(cell as Iterable<unknown>).filter((s): s is string => typeof s === \"string\" && s !== \"\");\n }\n return [];\n}\n\n/**\n * One annotation string's fields.\n * @param entry - `key=value|key=value`\n * @returns the fields\n */\nfunction parseEntry(entry: string): Map<string, string> {\n const out = new Map<string, string>();\n for (const part of entry.split(\"|\")) {\n const eq = part.indexOf(\"=\");\n if (eq > 0) {\n out.set(part.slice(0, eq), part.slice(eq + 1));\n }\n }\n return out;\n}\n\n/**\n * One annotation as neutral facts; a bounded text annotation is a shape and its text.\n * @param f - its fields\n * @param index - its position, its id when it has no uuid\n * @param byId - every annotation's fields by id, for an arrow's ends\n * @returns the annotations, or null for a kind not read\n */\nfunction readOne(\n f: ReadonlyMap<string, string>,\n index: string,\n byId: ReadonlyMap<string, ReadonlyMap<string, string>>,\n): GraphAnnotation[] | null {\n const type = (f.get(\"type\") ?? \"\").replace(TYPE_PREFIX, \"\");\n const zoom = positive(f.get(\"zoom\")) ?? 1;\n const base: AnnotationBase = {\n id: f.get(\"uuid\") ?? index,\n layer: f.get(\"canvas\") === \"background\" ? \"background\" : \"foreground\",\n z: num(f.get(\"z\")) ?? 0,\n };\n switch (type) {\n case \"ShapeAnnotation\":\n return [shapeOf(f, base, zoom)];\n case \"TextAnnotation\":\n return [textOf(f, base, zoom, { x: num(f.get(\"x\")) ?? 0, y: -(num(f.get(\"y\")) ?? 0) }, \"top-left\")];\n case \"BoundedTextAnnotation\": {\n const shape = shapeOf(f, base, zoom);\n return [shape, textOf(f, { ...base, id: `${base.id}:text` }, zoom, shape.center, \"center\")];\n }\n case \"ArrowAnnotation\":\n return arrowOf(f, base, zoom, byId);\n default:\n return null;\n }\n}\n\n/**\n * A shape annotation: `x`, `y` its top-left corner, y down; `width`, `height` and the outline at the saved zoom.\n * @param f - its fields\n * @param base - its id, layer and order\n * @param zoom - the zoom its sizes were saved at\n * @returns the shape\n */\nfunction shapeOf(f: ReadonlyMap<string, string>, base: AnnotationBase, zoom: number): ShapeAnnotation {\n const x = num(f.get(\"x\")) ?? 0;\n const y = num(f.get(\"y\")) ?? 0;\n const width = (positive(f.get(\"width\")) ?? 0) / zoom;\n const height = (positive(f.get(\"height\")) ?? 0) / zoom;\n const fill = javaColor(f.get(\"fillColor\"));\n const border = javaColor(f.get(\"edgeColor\")) ?? { color: \"#000000\", alpha: 1 };\n return {\n ...base,\n kind: \"shape\",\n center: { x: x + width / 2, y: -(y + height / 2) },\n width,\n height,\n shape: SHAPES.get((f.get(\"shapeType\") ?? \"rectangle\").toLowerCase()) ?? \"rectangle\",\n fill: fill?.color ?? null,\n fillOpacity: fill === null ? 0 : fill.alpha * percent(f.get(\"fillOpacity\")),\n borderColor: border.color,\n borderOpacity: border.alpha * percent(f.get(\"edgeOpacity\")),\n borderWidth: (num(f.get(\"edgeThickness\")) ?? 1) / zoom,\n };\n}\n\n/**\n * A text annotation, or the text of a bounded one.\n * @param f - its fields\n * @param base - its id, layer and order\n * @param zoom - the zoom its font size was saved at\n * @param at - where it is placed\n * @param anchor - what `at` is\n * @returns the text\n */\nfunction textOf(\n f: ReadonlyMap<string, string>,\n base: AnnotationBase,\n zoom: number,\n at: AnnotationPoint,\n anchor: TextAnnotation[\"anchor\"],\n): TextAnnotation {\n // java.awt.Font styles: 1 bold, 2 italic, 3 both\n const style = num(f.get(\"fontStyle\")) ?? 0;\n const color = javaColor(f.get(\"color\")) ?? { color: \"#000000\", alpha: 1 };\n return {\n ...base,\n kind: \"text\",\n text: f.get(\"text\") ?? \"\",\n at,\n anchor,\n fontSize: (positive(f.get(\"fontSize\")) ?? 12) / zoom,\n fontFamily: f.get(\"fontFamily\") ?? \"sans-serif\",\n bold: (style & 1) !== 0,\n italic: (style & 2) !== 0,\n color: color.color,\n opacity: color.alpha,\n };\n}\n\n/**\n * An arrow annotation. Cytoscape keeps its start as the annotation it leaves (`sourceAnnotation`) and its end as a\n * point, a node's center at save time (`targetNode`) or another annotation, and saves the arrow's top-left corner\n * as `x`, `y`: the start wherever the end lies right of and below it, which is taken for the start, else the center\n * of the annotation it leaves.\n * @param f - its fields\n * @param base - its id, layer and order\n * @param zoom - the zoom its line width was saved at\n * @param byId - every annotation's fields by id\n * @returns the arrow, or null when it has no end\n */\nfunction arrowOf(\n f: ReadonlyMap<string, string>,\n base: AnnotationBase,\n zoom: number,\n byId: ReadonlyMap<string, ReadonlyMap<string, string>>,\n): ArrowAnnotation[] | null {\n const target = f.get(\"targetAnnotation\");\n const to = point(f.get(\"targetPoint\")) ?? point(f.get(\"targetNode\")) ?? centerOf(byId.get(target ?? \"\"), zoom);\n if (to === null) {\n return null;\n }\n const corner = { x: num(f.get(\"x\")) ?? 0, y: num(f.get(\"y\")) ?? 0 };\n const source = centerOf(byId.get(f.get(\"sourceAnnotation\") ?? \"\"), zoom) ?? corner;\n // ponytail: the start is exact only when the end lies right of and below it; elsewhere the center of the\n // annotation it leaves, as Cytoscape stores no other start. Clip to that annotation's box if it matters.\n const from = { x: to.x > corner.x ? corner.x : source.x, y: to.y > corner.y ? corner.y : source.y };\n const color = javaColor(f.get(\"lineColor\")) ?? { color: \"#000000\", alpha: 1 };\n return [\n {\n ...base,\n kind: \"arrow\",\n from: { x: from.x, y: -from.y },\n to: { x: to.x, y: -to.y },\n color: color.color,\n opacity: color.alpha * percent(f.get(\"lineOpacity\")),\n width: (positive(f.get(\"lineThickness\")) ?? 1) / zoom,\n sourceArrow: arrowShape(f.get(\"sourceType\")),\n targetArrow: arrowShape(f.get(\"targetType\")),\n sourceSize: positive(f.get(\"sourceSize\")) ?? 1,\n targetSize: positive(f.get(\"targetSize\")) ?? 1,\n },\n ];\n}\n\n/**\n * An annotation's center, y down as the file writes it: a shape's box center, a text's corner.\n * @param f - its fields, or undefined\n * @param zoom - the zoom the arrow was saved at\n * @returns the point, or null\n */\nfunction centerOf(f: ReadonlyMap<string, string> | undefined, zoom: number): AnnotationPoint | null {\n if (f === undefined) {\n return null;\n }\n const x = num(f.get(\"x\"));\n const y = num(f.get(\"y\"));\n if (x === null || y === null) {\n return null;\n }\n return { x: x + (positive(f.get(\"width\")) ?? 0) / zoom / 2, y: y + (positive(f.get(\"height\")) ?? 0) / zoom / 2 };\n}\n\n/**\n * An arrowhead by its `ArrowType` position or name.\n * @param raw - the field\n * @returns the shape; a triangle for one not known\n */\nfunction arrowShape(raw: string | undefined): StyleArrowShape {\n if (raw === undefined) {\n return \"none\";\n }\n const n = num(raw);\n if (n !== null) {\n return ARROW_ORDER[n] ?? \"triangle\";\n }\n return ARROW_NAMES.get(raw.trim().toLowerCase()) ?? \"triangle\";\n}\n\n/**\n * A `x,y` point as the file writes it.\n * @param raw - the field\n * @returns the point, or null\n */\nfunction point(raw: string | undefined): AnnotationPoint | null {\n const [x, y] = (raw ?? \"\").split(\",\").map((s) => num(s));\n return x === null || x === undefined || y === null || y === undefined ? null : { x, y };\n}\n\n/**\n * A Java color as a signed ARGB integer.\n * @param raw - the field\n * @returns the color and its alpha, or null\n */\nfunction javaColor(raw: string | undefined): { color: StyleColor; alpha: number } | null {\n const n = num(raw);\n if (n === null || !Number.isInteger(n)) {\n return null;\n }\n const argb = n >>> 0;\n return {\n color: `#${(argb & 0xffffff).toString(16).padStart(6, \"0\")}`,\n alpha: (argb >>> 24) / 255,\n };\n}\n\n/**\n * A 0..100 percentage as 0..1; 1 when absent.\n * @param raw - the field\n * @returns the fraction\n */\nfunction percent(raw: string | undefined): number {\n const n = num(raw);\n return n === null ? 1 : Math.min(1, Math.max(0, n / 100));\n}\n\n/**\n * A finite number.\n * @param raw - the field\n * @returns the number, or null\n */\nfunction num(raw: string | undefined): number | null {\n if (raw === undefined || raw.trim() === \"\") {\n return null;\n }\n const n = Number(raw);\n return Number.isFinite(n) ? n : null;\n}\n\n/**\n * A positive number.\n * @param raw - the field\n * @returns the number, or null\n */\nfunction positive(raw: string | undefined): number | null {\n const n = num(raw);\n return n !== null && n > 0 ? n : null;\n}\n","/**\n * The styles of a live Cytoscape.js core: the rules from its stylesheet (`cy.style().json()`) and, when given, the\n * truth per element from what the core reports it draws (`ele.style()`). Reported values win over the stylesheet\n * where they disagree, so a property whose stylesheet value is a function (which `cy.style().json()` writes as \"fn\")\n * is still exact: it is copied per element from the reported values and noted as `W_STYLE_LAYER_FLATTENED` with the\n * sample (and the rule reason) `FUNCTION`.\n */\n\nimport type { GraphSnapshot } from \"@graphty/graph-format\";\n\nimport { StyleBudget } from \"../budget.js\";\nimport { StyleNotes } from \"../notes.js\";\nimport { featuresOf, styleFingerprint } from \"../plan/features.js\";\nimport { planStyles } from \"../plan/plan.js\";\nimport type { ExtractedStyles, StyleWorkBudget } from \"../types.js\";\nimport { evaluateCytoscapeJs } from \"./cascade.js\";\n\n/** The input of `readCytoscapeStyles()`. */\nexport interface CytoscapeLiveInput {\n /** The core's elements: `cy.elements().jsons()`, or `{ nodes, edges }`. */\n readonly elements: unknown;\n /** The core's stylesheet: `cy.style().json()` (a function is written there as \"fn\"), or the one it was given. */\n readonly style: unknown;\n /**\n * What the core draws for each element, `ele.style()`, in the order of `elements` (for `{ nodes, edges }`, the\n * nodes then the edges); optional, and null for an element with none.\n */\n readonly rendered?: readonly (Readonly<Record<string, unknown>> | null | undefined)[];\n /** The graph the styles are for (the core's elements as a snapshot); the values come out indexed like it. */\n readonly snapshot: GraphSnapshot;\n /** The graph-io format id recorded as the styles' source; default \"json\". */\n readonly format?: string;\n /** Whether Cytoscape.js's defaults fill what the stylesheet leaves unset; default true. */\n readonly toolDefaults?: boolean;\n /**\n * Where problems are noted; graph-io's own engine passes its notes here.\n * @internal\n */\n readonly notes?: StyleNotes;\n /** The counted work budget. */\n readonly budget?: StyleWorkBudget;\n /** Cancels the work. */\n readonly signal?: AbortSignal;\n}\n\n/**\n * What a stylesheet function is read as: a function, whatever it returned.\n * @returns nothing\n */\nconst FUNCTION = (): null => null;\n\n/**\n * The stylesheet with every \"fn\" value (how `cy.style().json()` writes a function) read as a function.\n * @param style - the stylesheet\n * @returns the stylesheet to apply\n */\nfunction withFunctions(style: unknown): unknown {\n if (!Array.isArray(style)) {\n return style;\n }\n return style.map((entry: unknown) => {\n if (entry === null || typeof entry !== \"object\") {\n return entry;\n }\n const e = entry as Record<string, unknown>;\n const props = e.style ?? e.css;\n if (props === null || typeof props !== \"object\") {\n return entry;\n }\n const copy = Object.create(null) as Record<string, unknown>;\n for (const name of Object.keys(props)) {\n const v = (props as Record<string, unknown>)[name];\n copy[name] = v === \"fn\" ? FUNCTION : v;\n }\n return { selector: e.selector, style: copy };\n });\n}\n\n/**\n * The element list in order: an array as it is, `{ nodes, edges }` as the nodes then the edges.\n * @param elements - the elements\n * @returns the list\n */\nfunction elementList(elements: unknown): readonly unknown[] {\n if (Array.isArray(elements)) {\n return elements;\n }\n if (elements !== null && typeof elements === \"object\") {\n const e = elements as Record<string, unknown>;\n return [...(Array.isArray(e.nodes) ? e.nodes : []), ...(Array.isArray(e.edges) ? e.edges : [])];\n }\n return [];\n}\n\n/**\n * Reads the styles of a live Cytoscape.js core: the stylesheet's rules, with what the core reports it draws as the\n * truth per element when given.\n * @param input - the elements, the stylesheet, the reported values and the graph\n * @returns the styles, exact for every element\n * @category Styles\n */\nexport function readCytoscapeStyles(input: CytoscapeLiveInput): ExtractedStyles {\n const notes = input.notes ?? new StyleNotes();\n const budget = input.budget ?? new StyleBudget();\n let rendered: Map<object, Readonly<Record<string, unknown>>> | undefined;\n if (input.rendered !== undefined) {\n rendered = new Map();\n const list = elementList(input.elements);\n for (let i = 0; i < list.length && i < input.rendered.length; i++) {\n const json = list[i];\n const r = input.rendered[i];\n if (json !== null && typeof json === \"object\" && r !== null && r !== undefined && typeof r === \"object\") {\n rendered.set(json, r);\n }\n }\n }\n const r = evaluateCytoscapeJs({\n elements: input.elements,\n style: withFunctions(input.style),\n snapshot: input.snapshot,\n toolDefaults: input.toolDefaults,\n rendered,\n notes,\n budget,\n signal: input.signal,\n });\n const s = input.snapshot;\n return planStyles(\n {\n format: input.format ?? \"json\",\n dialect: \"cytoscape-js\",\n tool: \"cytoscape-js\",\n units: \"px\",\n node: { values: r.node.values, rules: r.node.rules, columns: r.node.columns },\n edge: { values: r.edge.values, rules: r.edge.rules, columns: r.edge.columns },\n fingerprint: styleFingerprint(s),\n },\n { node: featuresOf(s, \"node\"), edge: featuresOf(s, \"edge\") },\n {\n toolDefaults: input.toolDefaults,\n notes,\n budget,\n signal: input.signal,\n rawColumns: { node: r.node.rawColumns, edge: r.edge.rawColumns },\n },\n );\n}\n"],"names":["e","r"],"mappings":"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"}
package/dist/xgmml.js CHANGED
@@ -1,6 +1,6 @@
1
- import { X, a } from "./chunks/styles-_N-C8S-U.js";
2
- import { x } from "./chunks/exporter-BtnqYuuj.js";
3
- import { x as x2 } from "./chunks/importer-BFmOP96W.js";
1
+ import { X, a } from "./chunks/styles-BQnsga7p.js";
2
+ import { x } from "./chunks/exporter-DndFlGSa.js";
3
+ import { x as x2 } from "./chunks/importer-yh_aBCU6.js";
4
4
  export {
5
5
  X as XGMML_ISSUE,
6
6
  a as XGMML_LOSS,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@graphty/graph-io",
3
- "version": "0.3.44",
3
+ "version": "0.3.46",
4
4
  "description": "Read and write 13 graph file formats (JSON, GraphML, GEXF, CSV, GML, DOT, Pajek, Neo4j CSV, XGMML, CX2, CX, OBO, Cytoscape sessions) as @graphty/graph-format snapshots",
5
5
  "author": "Adam Powers <apowers@ato.ms>",
6
6
  "type": "module",
@@ -45,7 +45,7 @@ import {
45
45
  styleBlockLosses,
46
46
  writeStyleBlock,
47
47
  } from "../../styles/io/block.js";
48
- import type { ExporterStyleInput } from "../../styles/io/writer.js";
48
+ import { type ExporterStyleInput, sharedInExportCall } from "../../styles/io/writer.js";
49
49
  import { StyleNotes } from "../../styles/notes.js";
50
50
  import { styleFingerprint } from "../../styles/plan/features.js";
51
51
  import { plainCell, resolveStyles } from "../../styles/plan/resolve.js";
@@ -1521,6 +1521,20 @@ export function dotStyledExport(
1521
1521
  if (input === undefined) {
1522
1522
  return null;
1523
1523
  }
1524
+ // the registry's check before writing and the write of one export call share the work
1525
+ return sharedInExportCall(input, [snapshot, onMixedDirection], () =>
1526
+ styledExport(snapshot, input, onMixedDirection),
1527
+ );
1528
+ }
1529
+
1530
+ /**
1531
+ * Works out a DOT export with styles: dotStyledExport() without the sharing.
1532
+ * @param snapshot - the graph handed to the exporter
1533
+ * @param input - the styles
1534
+ * @param onMixedDirection - the exporter's option
1535
+ * @returns the styled export
1536
+ */
1537
+ function styledExport(snapshot: GraphSnapshot, input: ExporterStyleInput, onMixedDirection: unknown): DotStyledExport {
1524
1538
  const approximated = new StyleApproximations();
1525
1539
  const replaced: LossNote[] = [];
1526
1540
  const out = snapshot.withColumns();
@@ -220,7 +220,7 @@ function styleColumns(table: GraphSnapshot["nodes"], keys: readonly string[]): s
220
220
 
221
221
  /**
222
222
  * The styles of a Pajek file, read the way Pajek draws them, with Pajek's stated defaults beneath: a labeled ellipse
223
- * with a black border, black solid lines, and an arrow at the target of every arc. A file graphty wrote gives back its `graphty.styles` block.
223
+ * with a black border and a black centered label, black solid lines, and an arrow at the target of every arc. A file graphty wrote gives back its `graphty.styles` block.
224
224
  * @param snapshot - the graph the import built
225
225
  * @param context - the work budget and the block text the import kept
226
226
  * @returns the styles
@@ -365,7 +365,8 @@ function shapeKeyword(get: Get, approximate: Approximate): string {
365
365
  }
366
366
 
367
367
  /**
368
- * A vertex's parameters from its values, leaving out the ellipse and the black border 1 wide Pajek draws by default.
368
+ * A vertex's parameters from its values, leaving out what Pajek draws by default: an ellipse with a black border 1
369
+ * wide and a black label.
369
370
  * @param get - the vertex's values
370
371
  * @param approximate - records approximations
371
372
  * @returns the parameters, the shape keyword under `shape`
@@ -389,7 +390,7 @@ function vertexParams(get: Get, approximate: Approximate): Map<string, Written>
389
390
  ] as const;
390
391
  for (const [property, key] of colors) {
391
392
  const v = get(property);
392
- if (typeof v === "string" && !(property === "borderColor" && v === "#000000")) {
393
+ if (typeof v === "string" && (property === "fill" || v !== "#000000")) {
393
394
  out.set(key, pajekColorText(v));
394
395
  }
395
396
  }
@@ -6,7 +6,8 @@
6
6
  * - X11: the names Graphviz 2.43 resolves in its default `x11` scheme, measured with `dot -Txdot` (`gray` is
7
7
  * `#c0c0c0` there, not CSS's `#808080`).
8
8
  * - Brewer: the ColorBrewer schemes Graphviz knows (`/blues9/3`), measured the same way; index i is entry i - 1.
9
- * - dvips: the 68 CMYK color names of LaTeX's dvips driver, which Pajek uses, converted to RGB.
9
+ * - dvips: the 68 CMYK color names of LaTeX's dvips driver, which Pajek uses, converted to RGB, plus the ten names
10
+ * Pajek adds to them (LightYellow ... LSkyBlue), as the Pajek 6.02 manual's Figure 19 (p. 105) fills their swatches.
10
11
  * - Java: the `java.awt.Color` constants Cytoscape and Gephi write.
11
12
  */
12
13
 
@@ -185,7 +186,11 @@ export const DVIPS_COLORS: ReadonlyMap<string, string> = table(
185
186
  "SkyBlue=61ffe0 Turquoise=26ffcc TealBlue=1ffaa3 Aquamarine=2effb2 BlueGreen=26ffab Emerald=00ff80 " +
186
187
  "JungleGreen=03ff7a SeaGreen=4fff80 Green=00ff00 ForestGreen=00e000 PineGreen=00bf29 LimeGreen=80ff00 " +
187
188
  "YellowGreen=8fff42 SpringGreen=bdff3d OliveGreen=009900 RawSienna=8c0000 Sepia=4d0000 Brown=660000 " +
188
- "Tan=db9470 Gray=808080 Black=000000 White=ffffff",
189
+ "Tan=db9470 Gray=808080 Black=000000 White=ffffff " +
190
+ // Pajek's own names, not in dvips: the RGB fill of each swatch in the Pajek 6.02 manual, Figure 19, p. 105
191
+ // (http://mrvar.fdv.uni-lj.si/pajek/pajekman.pdf); Pajek's SVG export draws LightCyan as rgb(204,255,255) too.
192
+ "LightYellow=ffff99 LightCyan=ccffff LightMagenta=ffccff LightPurple=ccccff LightGreen=ccffb3 " +
193
+ "LightOrange=ffccb3 Canary=ffff7f LFadedGreen=e6ffcc Pink=ffd9f3 LSkyBlue=d9f3ff",
189
194
  );
190
195
 
191
196
  /** Java's `java.awt.Color` constants, lowercase, with and without the underscore. */
@@ -145,7 +145,8 @@ function toCyjs(target: StyleTarget, property: string, value: StyleValue): Writt
145
145
  case "labelItalic":
146
146
  return exact({ "font-style": value === true ? "italic" : "normal" });
147
147
  case "curved":
148
- return exact({ "curve-style": value === true ? "bezier" : "straight" });
148
+ // `bezier` bows only parallel edges; `unbundled-bezier` bows every edge
149
+ return exact({ "curve-style": value === true ? "unbundled-bezier" : "straight" });
149
150
  case "labelPosition":
150
151
  return labelPositionToCyjs(String(value));
151
152
  case "shape":
@@ -554,6 +554,7 @@ const IDENTIFIERS: Readonly<Record<StyleTarget, ReadonlyMap<string, string>>> =
554
554
  ["edgetooltip", "EDGE_TOOLTIP"],
555
555
  ["curved", "EDGE_CURVED_LEGACY"],
556
556
  ["edgecurved", "EDGE_CURVED"],
557
+ ["edgebend", "EDGE_BEND"],
557
558
  ]),
558
559
  };
559
560
 
@@ -610,7 +611,8 @@ function normalizeObject(
610
611
  if (k === "lockedVisualProperties" || v === null || v === undefined) {
611
612
  continue;
612
613
  }
613
- if (typeof v === "object" && !Array.isArray(v) && !/^[A-Z_0-9]+$/.test(k)) {
614
+ // a 2.x edgeBend of one handle is a record: kept whole, as its handles
615
+ if (typeof v === "object" && !Array.isArray(v) && !/^[A-Z_0-9]+$/.test(k) && k.toLowerCase() !== "edgebend") {
614
616
  if (depth + 1 > MAX_VP_DEPTH) {
615
617
  deep++;
616
618
  } else {
@@ -106,6 +106,9 @@ const GEPHI = "gephi master 92e503df61a7";
106
106
  const VIS = "vis-network 10.1.2 vis-network.esm.js";
107
107
  const SIGMA = "sigma 3.0.3 packages/sigma/src";
108
108
  const PAJEK = "Pajek 6.02 reference manual";
109
+ const PAJEK_SHAPES =
110
+ "the SHAPES.CFG Pajek writes when none exists (DrawEPS.htm), " +
111
+ "github.com/ohshane/radical-clustering 0f568f67893558035868b3db1bf365870ba52f6b shapes.cfg, SHAPE ELLIPSE";
109
112
  const OGDF = "ogdf master 1a40505ac006";
110
113
  const NX = "networkx 6da4704cbf32 networkx/drawing/nx_pylab.py line";
111
114
 
@@ -416,9 +419,14 @@ export const TOOL_DEFAULTS: ReadonlyMap<StyleTool, ToolDefaults> = new Map<Style
416
419
  opacity: v(1, `${PAJEK} p. 87`),
417
420
  borderColor: v("#000000", `${PAJEK}, vertex parameter bc (default Black)`),
418
421
  borderWidth: v(0.2, `${PAJEK}, vertex parameter bw (default 1, against the default vertex size 5)`),
422
+ labelColor: v("#000000", `${PAJEK_SHAPES} (lc Black)`),
423
+ labelPosition: v("center", `${PAJEK_SHAPES} (lr 0); ${PAJEK} p. 85 (radius 0 is centered)`),
419
424
  },
420
425
  edge: {
421
426
  color: v("#000000", `${PAJEK} p. 90`),
427
+ // No line width: Pajek's w is read as the file has it, not as a factor of the vertex size as bw is,
428
+ // so a default of 1 here, with no vertex size in the file, became the length every other length
429
+ // of the drawing was scaled by, and a border 0.2 wide was drawn far too thin to see.
422
430
  lineStyle: v("solid", `${PAJEK} p. 90`),
423
431
  opacity: v(1, `${PAJEK} p. 87`),
424
432
  sourceArrow: v("none", `${PAJEK} p. 91`),
@@ -128,6 +128,37 @@ export function prepareStyleExport(
128
128
  };
129
129
  }
130
130
 
131
+ /**
132
+ * The work an exporter shares between the check and the write of one export call, by the styles input made for that
133
+ * call (null until the first exporter step does it). Only an input writePlan() made is here, so an input a caller
134
+ * builds and changes in place is always worked out again.
135
+ */
136
+ const CALL_WORK = new WeakMap<
137
+ ExporterStyleInput,
138
+ { readonly key: readonly unknown[]; readonly value: unknown } | null
139
+ >();
140
+
141
+ /**
142
+ * Work an exporter does from its styles input once per export call: the registry checks before it writes, with the
143
+ * same input, graph and options. Outside an export call (an input the caller made) it is done every time.
144
+ * @param input - the exporter's `options.styles`
145
+ * @param key - what else the work reads (the graph, options), compared by identity
146
+ * @param compute - the work
147
+ * @returns its result
148
+ */
149
+ export function sharedInExportCall<T>(input: ExporterStyleInput, key: readonly unknown[], compute: () => T): T {
150
+ if (!CALL_WORK.has(input)) {
151
+ return compute();
152
+ }
153
+ const done = CALL_WORK.get(input);
154
+ if (done?.key.length === key.length && done.key.every((k, i) => k === key[i])) {
155
+ return done.value as T;
156
+ }
157
+ const value = compute();
158
+ CALL_WORK.set(input, { key, value });
159
+ return value;
160
+ }
161
+
131
162
  /**
132
163
  * What an exporter is handed to write a graph's styles: the snapshot with the block and tagged values added where
133
164
  * the format keeps them, and its `options.styles`.
@@ -164,9 +195,13 @@ function writePlan(
164
195
  }
165
196
  }
166
197
  const block = writeStyleBlock(extracted, { snapshot });
198
+ const input = exporter.styles === undefined ? null : { picture, block, tags, rules: extracted };
199
+ if (input !== null) {
200
+ CALL_WORK.set(input, null);
201
+ }
167
202
  return {
168
203
  snapshot: styledSnapshot(snapshot, caps, tags, block, extracted.styles.rules),
169
- input: exporter.styles === undefined ? null : { picture, block, tags, rules: extracted },
204
+ input,
170
205
  extracted,
171
206
  picture,
172
207
  };