@graphty/graph-io 0.3.38 → 0.3.39

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 (103) hide show
  1. package/dist/chunks/{choose-CsO24U-5.js → choose-CS3fvGT1.js} +2 -2
  2. package/dist/chunks/{choose-CsO24U-5.js.map → choose-CS3fvGT1.js.map} +1 -1
  3. package/dist/chunks/{constants-BPRiVyBu.js → constants-DqKZT6cH.js} +2 -2
  4. package/dist/chunks/{constants-BPRiVyBu.js.map → constants-DqKZT6cH.js.map} +1 -1
  5. package/dist/chunks/{escape-BRcyzD77.js → escape-BpYMQZVa.js} +2 -2
  6. package/dist/chunks/{escape-BRcyzD77.js.map → escape-BpYMQZVa.js.map} +1 -1
  7. package/dist/chunks/{export-CTUlibzr.js → export-B-aVCwyG.js} +103 -92
  8. package/dist/chunks/export-B-aVCwyG.js.map +1 -0
  9. package/dist/chunks/{exporter-Bf5tZA0X.js → exporter-BqKs1Q12.js} +4 -4
  10. package/dist/chunks/{exporter-Bf5tZA0X.js.map → exporter-BqKs1Q12.js.map} +1 -1
  11. package/dist/chunks/{exporter-D-qQuRcG.js → exporter-CNJZF_BN.js} +6 -6
  12. package/dist/chunks/exporter-CNJZF_BN.js.map +1 -0
  13. package/dist/chunks/{exporter-Bn4jdYfd.js → exporter-DXqCPNrI.js} +4 -4
  14. package/dist/chunks/{exporter-Bn4jdYfd.js.map → exporter-DXqCPNrI.js.map} +1 -1
  15. package/dist/chunks/{exporter-F0vT919P.js → exporter-SFYkDzD0.js} +5 -4
  16. package/dist/chunks/exporter-SFYkDzD0.js.map +1 -0
  17. package/dist/chunks/{importer-oIUx9u_g.js → importer--tQQsY4W.js} +40 -18
  18. package/dist/chunks/importer--tQQsY4W.js.map +1 -0
  19. package/dist/chunks/{importer-yWUPR_nU.js → importer-B7Ir269L.js} +4 -4
  20. package/dist/chunks/{importer-yWUPR_nU.js.map → importer-B7Ir269L.js.map} +1 -1
  21. package/dist/chunks/{importer-BuzbaFFY.js → importer-BfJ1jnNr.js} +3 -3
  22. package/dist/chunks/{importer-BuzbaFFY.js.map → importer-BfJ1jnNr.js.map} +1 -1
  23. package/dist/chunks/{importer-CEuUmyPe.js → importer-CSt-gaYE.js} +6 -6
  24. package/dist/chunks/{importer-CEuUmyPe.js.map → importer-CSt-gaYE.js.map} +1 -1
  25. package/dist/chunks/{importer-Bgb9sgZZ.js → importer-CqgYq4Ld.js} +6 -8
  26. package/dist/chunks/importer-CqgYq4Ld.js.map +1 -0
  27. package/dist/chunks/{importer-CNMQnHDd.js → importer-DvFznt5-.js} +4 -4
  28. package/dist/chunks/{importer-CNMQnHDd.js.map → importer-DvFznt5-.js.map} +1 -1
  29. package/dist/chunks/{importer-DqMtyYLX.js → importer-PVXkeoaS.js} +6 -8
  30. package/dist/chunks/importer-PVXkeoaS.js.map +1 -0
  31. package/dist/chunks/{json-elements-AkglPS3m.js → json-elements-CXs4z1iL.js} +3 -3
  32. package/dist/chunks/{json-elements-AkglPS3m.js.map → json-elements-CXs4z1iL.js.map} +1 -1
  33. package/dist/chunks/{ontology-export-DDoG3egY.js → ontology-export-50L9DOV4.js} +2 -2
  34. package/dist/chunks/{ontology-export-DDoG3egY.js.map → ontology-export-50L9DOV4.js.map} +1 -1
  35. package/dist/chunks/{records-ChmWZGuz.js → records-C9jd7yLD.js} +2 -2
  36. package/dist/chunks/{records-ChmWZGuz.js.map → records-C9jd7yLD.js.map} +1 -1
  37. package/dist/chunks/{text-Btw3sBe_.js → text-Bjfa1xYL.js} +2 -2
  38. package/dist/chunks/{text-Btw3sBe_.js.map → text-Bjfa1xYL.js.map} +1 -1
  39. package/dist/csv.js +4 -4
  40. package/dist/cx.js +1 -1
  41. package/dist/cx2.js +2 -2
  42. package/dist/cys.js +1 -1
  43. package/dist/dot.js +1 -1
  44. package/dist/gexf.js +2 -2
  45. package/dist/gml.js +8 -6
  46. package/dist/gml.js.map +1 -1
  47. package/dist/graph-io.js +26 -26
  48. package/dist/graphml.js +2 -2
  49. package/dist/json.js +1 -1
  50. package/dist/neo4j.js +3 -3
  51. package/dist/obo.js +1 -1
  52. package/dist/pajek.js +1 -1
  53. package/dist/src/common/direction.js +1 -1
  54. package/dist/src/common/direction.js.map +1 -1
  55. package/dist/src/common/export.d.ts.map +1 -1
  56. package/dist/src/common/export.js +136 -71
  57. package/dist/src/common/export.js.map +1 -1
  58. package/dist/src/common/input.js +1 -1
  59. package/dist/src/common/input.js.map +1 -1
  60. package/dist/src/formats/dot/importer.d.ts +6 -0
  61. package/dist/src/formats/dot/importer.d.ts.map +1 -1
  62. package/dist/src/formats/dot/importer.js +11 -6
  63. package/dist/src/formats/dot/importer.js.map +1 -1
  64. package/dist/src/formats/dot/names.d.ts +5 -0
  65. package/dist/src/formats/dot/names.d.ts.map +1 -1
  66. package/dist/src/formats/dot/names.js +5 -0
  67. package/dist/src/formats/dot/names.js.map +1 -1
  68. package/dist/src/formats/dot/tokenizer.js +9 -9
  69. package/dist/src/formats/dot/tokenizer.js.map +1 -1
  70. package/dist/src/formats/gml/importer.d.ts +6 -0
  71. package/dist/src/formats/gml/importer.d.ts.map +1 -1
  72. package/dist/src/formats/gml/importer.js +6 -3
  73. package/dist/src/formats/gml/importer.js.map +1 -1
  74. package/dist/src/formats/graphml/importer.d.ts.map +1 -1
  75. package/dist/src/formats/graphml/importer.js +2 -4
  76. package/dist/src/formats/graphml/importer.js.map +1 -1
  77. package/dist/src/formats/obo/importer.d.ts.map +1 -1
  78. package/dist/src/formats/obo/importer.js +2 -1
  79. package/dist/src/formats/obo/importer.js.map +1 -1
  80. package/dist/src/formats/pajek/exporter.d.ts.map +1 -1
  81. package/dist/src/formats/pajek/exporter.js +4 -5
  82. package/dist/src/formats/pajek/exporter.js.map +1 -1
  83. package/dist/src/sniff.js +1 -1
  84. package/dist/src/sniff.js.map +1 -1
  85. package/dist/xgmml.js +2 -2
  86. package/package.json +2 -2
  87. package/src/common/direction.ts +1 -1
  88. package/src/common/export.ts +190 -97
  89. package/src/common/input.ts +1 -1
  90. package/src/formats/dot/importer.ts +35 -4
  91. package/src/formats/dot/names.ts +6 -0
  92. package/src/formats/dot/tokenizer.ts +9 -9
  93. package/src/formats/gml/importer.ts +14 -3
  94. package/src/formats/graphml/importer.ts +2 -4
  95. package/src/formats/obo/importer.ts +2 -1
  96. package/src/formats/pajek/exporter.ts +6 -4
  97. package/src/sniff.ts +1 -1
  98. package/dist/chunks/export-CTUlibzr.js.map +0 -1
  99. package/dist/chunks/exporter-D-qQuRcG.js.map +0 -1
  100. package/dist/chunks/exporter-F0vT919P.js.map +0 -1
  101. package/dist/chunks/importer-Bgb9sgZZ.js.map +0 -1
  102. package/dist/chunks/importer-DqMtyYLX.js.map +0 -1
  103. package/dist/chunks/importer-oIUx9u_g.js.map +0 -1
@@ -97,6 +97,7 @@ import {
97
97
  PARENT_COLUMN,
98
98
  PIN_ATTRIBUTE,
99
99
  POS_ATTRIBUTE,
100
+ POSITION_COLUMN,
100
101
  SOURCE_PORT_COLUMN,
101
102
  TARGET_PORT_COLUMN,
102
103
  } from "./names.js";
@@ -122,6 +123,12 @@ export interface DotImportOptions extends GraphChoiceOptions, CommonImportOption
122
123
  * @defaultValue true
123
124
  */
124
125
  positions?: boolean | undefined;
126
+ /**
127
+ * With `positions`, also keep `pos` as the text the file wrote; the position column is then
128
+ * named `graphty.position`, so a reader gets both.
129
+ * @defaultValue false
130
+ */
131
+ keepPositionSource?: boolean | undefined;
125
132
  }
126
133
 
127
134
  /**
@@ -323,7 +330,7 @@ interface Scope {
323
330
  */
324
331
  export const dotImporter: GraphImporter<DotImportOptions> = Object.freeze({
325
332
  format: DOT_FORMAT,
326
- options: Object.freeze(["mismatchedEdgeOperator", "positions"]),
333
+ options: Object.freeze(["keepPositionSource", "mismatchedEdgeOperator", "positions"]),
327
334
  extensions: EXTENSIONS,
328
335
  mimeTypes: MIME_TYPES,
329
336
 
@@ -376,7 +383,15 @@ export const dotImporter: GraphImporter<DotImportOptions> = Object.freeze({
376
383
  const reports = { current: report };
377
384
  const lexer = dotLexer(text, reports);
378
385
  const first = guard(report, () => lexer.next());
379
- const parser = new DotParser(lexer, sink, report, resolved, mismatch, options?.positions !== false);
386
+ const parser = new DotParser(
387
+ lexer,
388
+ sink,
389
+ report,
390
+ resolved,
391
+ mismatch,
392
+ options?.positions !== false,
393
+ options?.keepPositionSource === true,
394
+ );
380
395
  parser.headCharset = head.charset;
381
396
  const trailing = parseGraph(parser, report, first);
382
397
  if (trailing.kind !== "eof") {
@@ -429,7 +444,15 @@ export const dotImporter: GraphImporter<DotImportOptions> = Object.freeze({
429
444
  reports.current = report;
430
445
  const sink = sinkFor(done.length);
431
446
  reportSinkOptions(sink, options, report);
432
- const parser = new DotParser(lexer, sink, report, resolved, mismatch, options?.positions !== false);
447
+ const parser = new DotParser(
448
+ lexer,
449
+ sink,
450
+ report,
451
+ resolved,
452
+ mismatch,
453
+ options?.positions !== false,
454
+ options?.keepPositionSource === true,
455
+ );
433
456
  parser.headCharset = head.charset;
434
457
  token = parseGraph(parser, report, token);
435
458
  throwIfAborted(resolved.signal);
@@ -686,6 +709,8 @@ class DotParser {
686
709
  private readonly mismatch: "operator" | "header" | "error";
687
710
  private readonly positions: boolean;
688
711
 
712
+ private readonly keepPositionSource: boolean;
713
+
689
714
  private readonly ids: IdCoercer;
690
715
 
691
716
  private readonly resolver: DirectionResolver;
@@ -758,6 +783,7 @@ class DotParser {
758
783
  * @param options - the resolved common options
759
784
  * @param mismatch - the resolved mismatchedEdgeOperator option
760
785
  * @param positions - whether `pos` goes to the position column
786
+ * @param keepPositionSource - whether `pos` also stays as text
761
787
  */
762
788
  constructor(
763
789
  lexer: DotTokenizer,
@@ -766,6 +792,7 @@ class DotParser {
766
792
  options: ResolvedImportOptions,
767
793
  mismatch: "operator" | "header" | "error",
768
794
  positions: boolean,
795
+ keepPositionSource: boolean,
769
796
  ) {
770
797
  this.lexer = lexer;
771
798
  this.sink = sink;
@@ -773,6 +800,7 @@ class DotParser {
773
800
  this.options = options;
774
801
  this.mismatch = mismatch;
775
802
  this.positions = positions;
803
+ this.keepPositionSource = keepPositionSource;
776
804
  this.ids = new IdCoercer(options.ids);
777
805
  this.resolver = new DirectionResolver(sink, report, options.onMixedDirection);
778
806
  }
@@ -1586,6 +1614,9 @@ class DotParser {
1586
1614
  this.sink.setNodeValue(this.nodeLabel(), index, value);
1587
1615
  } else if (name === POS_ATTRIBUTE && this.positions) {
1588
1616
  this.setPosition(index, value, line, element);
1617
+ if (this.keepPositionSource) {
1618
+ this.textWriter("node", name).write(index, value);
1619
+ }
1589
1620
  } else {
1590
1621
  this.textWriter("node", name).write(index, value);
1591
1622
  }
@@ -1766,7 +1797,7 @@ class DotParser {
1766
1797
  private positionColumn(dims: 2 | 3): ColumnHandle {
1767
1798
  if (this.positionHandle === INVALID_INDEX) {
1768
1799
  this.positionHandle = this.declare("node", {
1769
- name: POS_ATTRIBUTE,
1800
+ name: this.keepPositionSource ? POSITION_COLUMN : POS_ATTRIBUTE,
1770
1801
  dtype: "f64",
1771
1802
  components: 3,
1772
1803
  nullable: true,
@@ -54,6 +54,12 @@ export const LABEL_ATTRIBUTE = "label";
54
54
  */
55
55
  export const POS_ATTRIBUTE = "pos";
56
56
 
57
+ /**
58
+ * The node position column when the import keeps `pos` as text too (the `keepPositionSource` option).
59
+ * @category Plugin helpers
60
+ */
61
+ export const POSITION_COLUMN = "graphty.position";
62
+
57
63
  /**
58
64
  * The edge attribute cgraph uses as an edge's identity within its endpoints, mapped to the edge id role.
59
65
  * @category Plugin helpers
@@ -148,15 +148,15 @@ export class DotTokenizer {
148
148
  const { line } = this;
149
149
  const c = text.charCodeAt(start);
150
150
  switch (c) {
151
- case 0x7b: // {
152
- case 0x7d: // }
153
- case 0x5b: // [
154
- case 0x5d: // ]
155
- case 0x3b: // ;
156
- case 0x2c: // ,
157
- case 0x3d: // =
158
- case 0x3a: // :
159
- case 0x2b: // +
151
+ case 0x7b: // "{"
152
+ case 0x7d: // "}"
153
+ case 0x5b: // "["
154
+ case 0x5d: // "]"
155
+ case 0x3b: // ";"
156
+ case 0x2c: // ","
157
+ case 0x3d: // "="
158
+ case 0x3a: // ":"
159
+ case 0x2b: // "+"
160
160
  this.pos++;
161
161
  return { kind: "punct", text: text[start], quoted: false, html: false, line };
162
162
  case 0x2d: {
@@ -97,6 +97,12 @@ export interface GmlImportOptions extends GraphChoiceOptions, CommonImportOption
97
97
  * @defaultValue true
98
98
  */
99
99
  positions?: boolean | undefined;
100
+ /**
101
+ * With `positions`, also keep the whole `graphics` record, x / y / z included, as the JSON
102
+ * attribute named `graphics`, so a reader gets both the position and the record as written.
103
+ * @defaultValue false
104
+ */
105
+ keepPositionSource?: boolean | undefined;
100
106
  /**
101
107
  * Store a text attribute whose values repeat a lot (fewer distinct values than half the rows)
102
108
  * as a dictionary column, which uses less memory and reads the same. Such a column reports
@@ -378,6 +384,8 @@ class GmlImport {
378
384
 
379
385
  private readonly positions: boolean;
380
386
 
387
+ private readonly keepPositionSource: boolean;
388
+
381
389
  private readonly dictionaries: boolean;
382
390
 
383
391
  private readonly coercer: IdCoercer;
@@ -470,6 +478,7 @@ class GmlImport {
470
478
  this.report = report;
471
479
  this.options = options;
472
480
  this.positions = format?.positions ?? true;
481
+ this.keepPositionSource = format?.keepPositionSource ?? false;
473
482
  this.dictionaries = format?.dictionaries ?? true;
474
483
  this.coercer = new IdCoercer(options.ids);
475
484
  }
@@ -755,7 +764,8 @@ class GmlImport {
755
764
  }
756
765
  const positioned = x && y;
757
766
  entry.position ||= positioned;
758
- entry.rest ||= positioned ? other : true;
767
+ // with keepPositionSource the whole record, x / y / z included, goes to the json column too
768
+ entry.rest ||= positioned ? other || this.keepPositionSource : true;
759
769
  }
760
770
 
761
771
  // ============================================================ pass 2: the push
@@ -1541,7 +1551,8 @@ class GmlImport {
1541
1551
  const positionPlan = plan.position;
1542
1552
  let rest: unknown = first;
1543
1553
  if (isRecord(first) && positionPlan !== null) {
1544
- rest = this.writePosition(positionPlan, index, first, where);
1554
+ const left = this.writePosition(positionPlan, index, this.keepPositionSource ? { ...first } : first, where);
1555
+ rest = this.keepPositionSource ? first : left;
1545
1556
  } else if (!isRecord(first)) {
1546
1557
  this.graphicsWarning("scalar", `node ${where.element}'s graphics is not a record`, where);
1547
1558
  }
@@ -1924,7 +1935,7 @@ function sniffGml(head: Uint8Array): number {
1924
1935
  */
1925
1936
  export const gmlImporter: GraphImporter<GmlImportOptions> = Object.freeze({
1926
1937
  format: "gml",
1927
- options: Object.freeze(["dictionaries", "positions"]),
1938
+ options: Object.freeze(["dictionaries", "keepPositionSource", "positions"]),
1928
1939
  extensions: Object.freeze([".gml"]),
1929
1940
  mimeTypes: Object.freeze(["text/x-gml", "text/plain"]),
1930
1941
  sniff: sniffGml,
@@ -512,16 +512,14 @@ class GraphmlReader implements XmlHandler {
512
512
  const parent = this.ctx.at(-1) ?? null;
513
513
  switch (parent) {
514
514
  case Ctx.Capture:
515
+ case Ctx.Data:
516
+ case Ctx.Default:
515
517
  this.captureStart(name, attrs);
516
518
  return;
517
519
  case Ctx.Skip:
518
520
  case Ctx.Desc:
519
521
  this.ctx.push(Ctx.Skip);
520
522
  return;
521
- case Ctx.Data:
522
- case Ctx.Default:
523
- this.captureStart(name, attrs);
524
- return;
525
523
  case Ctx.Dropped:
526
524
  this.dropStart(localName(name));
527
525
  return;
@@ -1429,7 +1429,8 @@ class OboReader {
1429
1429
  return;
1430
1430
  }
1431
1431
  const map = (record.values.get("obo.qualifiers") as Record<string, unknown[]> | undefined) ?? {};
1432
- (map[tag] ??= []).push({ value, qualifiers });
1432
+ map[tag] ??= [];
1433
+ map[tag].push({ value, qualifiers });
1433
1434
  record.values.set("obo.qualifiers", map);
1434
1435
  }
1435
1436
 
@@ -979,10 +979,12 @@ export const pajekExporter: GraphExporter<PajekExportOptions> = Object.freeze({
979
979
  // keyword and the relation name (dict columns written as keywords)
980
980
  const owned = new Set<string>();
981
981
  for (const { column, slot } of [...nodePlan, ...edgePlan]) {
982
- if (slot === "shape" || slot === "relation") {
983
- owned.add(`${column.meta.domain}:${column.meta.name}`);
984
- } else if (slot === "param" && column.meta.domain === "node" && column.meta.name === SHAPE_COLUMN) {
985
- // the shape-as-parameter note already says the column reads back as string
982
+ // a shape written as a parameter is owned too: its note already says the column reads back as string
983
+ if (
984
+ slot === "shape" ||
985
+ slot === "relation" ||
986
+ (slot === "param" && column.meta.domain === "node" && column.meta.name === SHAPE_COLUMN)
987
+ ) {
986
988
  owned.add(`${column.meta.domain}:${column.meta.name}`);
987
989
  }
988
990
  }
package/src/sniff.ts CHANGED
@@ -557,5 +557,5 @@ function clamp(value: number): number {
557
557
  if (!(value > 0)) {
558
558
  return 0;
559
559
  }
560
- return value > 1 ? 1 : value;
560
+ return Math.min(value, 1);
561
561
  }