@graphty/graph-io 0.3.28 → 0.3.30

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 (142) hide show
  1. package/dist/chunks/{choose-DrXtu_96.js → choose-BfOLq6OX.js} +2 -2
  2. package/dist/chunks/{choose-DrXtu_96.js.map → choose-BfOLq6OX.js.map} +1 -1
  3. package/dist/chunks/{constants-ikG85dT8.js → constants-M8Qsjz1C.js} +2 -2
  4. package/dist/chunks/{constants-ikG85dT8.js.map → constants-M8Qsjz1C.js.map} +1 -1
  5. package/dist/chunks/{escape-D1HPTUrP.js → escape-UMMpQZqs.js} +2 -2
  6. package/dist/chunks/{escape-D1HPTUrP.js.map → escape-UMMpQZqs.js.map} +1 -1
  7. package/dist/chunks/{export-CHd4tQE2.js → export-Dq4U8Ubq.js} +165 -148
  8. package/dist/chunks/{export-CHd4tQE2.js.map → export-Dq4U8Ubq.js.map} +1 -1
  9. package/dist/chunks/{exporter-DhtW6FxK.js → exporter-BUosqV0K.js} +34 -34
  10. package/dist/chunks/exporter-BUosqV0K.js.map +1 -0
  11. package/dist/chunks/{exporter-D23CKNqF.js → exporter-Bd_VZ9ph.js} +9 -10
  12. package/dist/chunks/exporter-Bd_VZ9ph.js.map +1 -0
  13. package/dist/chunks/{exporter-DfWTgrti.js → exporter-COgVm-ff.js} +8 -7
  14. package/dist/chunks/{exporter-DfWTgrti.js.map → exporter-COgVm-ff.js.map} +1 -1
  15. package/dist/chunks/{exporter-Cl021ZIE.js → exporter-DEk_XLLs.js} +4 -4
  16. package/dist/chunks/{exporter-Cl021ZIE.js.map → exporter-DEk_XLLs.js.map} +1 -1
  17. package/dist/chunks/{importer-BZB7iP9r.js → importer-AQ3KpNHz.js} +11 -20
  18. package/dist/chunks/importer-AQ3KpNHz.js.map +1 -0
  19. package/dist/chunks/{importer-BVRE--Un.js → importer-BsZa2Phx.js} +5 -5
  20. package/dist/chunks/importer-BsZa2Phx.js.map +1 -0
  21. package/dist/chunks/{importer-DpEW5zeG.js → importer-CV8au8gH.js} +4 -4
  22. package/dist/chunks/{importer-DpEW5zeG.js.map → importer-CV8au8gH.js.map} +1 -1
  23. package/dist/chunks/{importer-BSALvkui.js → importer-Cj4-lXlv.js} +10 -9
  24. package/dist/chunks/importer-Cj4-lXlv.js.map +1 -0
  25. package/dist/chunks/{importer-B2W_58pz.js → importer-DQsgmhxc.js} +5 -5
  26. package/dist/chunks/{importer-B2W_58pz.js.map → importer-DQsgmhxc.js.map} +1 -1
  27. package/dist/chunks/{importer-CIAzt-wo.js → importer-Dkn79TjB.js} +6 -6
  28. package/dist/chunks/importer-Dkn79TjB.js.map +1 -0
  29. package/dist/chunks/{importer-z_FL4VMb.js → importer-DwSZvMDq.js} +10 -19
  30. package/dist/chunks/importer-DwSZvMDq.js.map +1 -0
  31. package/dist/chunks/{json-elements-BAmNBZok.js → json-elements-CreeKoaH.js} +12 -16
  32. package/dist/chunks/{json-elements-BAmNBZok.js.map → json-elements-CreeKoaH.js.map} +1 -1
  33. package/dist/chunks/{ontology-export-Bab4eUA8.js → ontology-export-C5Xd3W-7.js} +2 -2
  34. package/dist/chunks/{ontology-export-Bab4eUA8.js.map → ontology-export-C5Xd3W-7.js.map} +1 -1
  35. package/dist/chunks/{records-CdlvL4RO.js → records-BwaH_2ll.js} +2 -2
  36. package/dist/chunks/{records-CdlvL4RO.js.map → records-BwaH_2ll.js.map} +1 -1
  37. package/dist/chunks/{text-DzXjAiTl.js → text-4HHe6YH3.js} +2 -2
  38. package/dist/chunks/{text-DzXjAiTl.js.map → text-4HHe6YH3.js.map} +1 -1
  39. package/dist/csv.js +22 -15
  40. package/dist/csv.js.map +1 -1
  41. package/dist/cx.js +1 -1
  42. package/dist/cx2.js +2 -2
  43. package/dist/cys.js +1 -1
  44. package/dist/dot.js +1 -1
  45. package/dist/gexf.js +9 -8
  46. package/dist/gexf.js.map +1 -1
  47. package/dist/gml.js +3 -3
  48. package/dist/graph-io.js +69 -69
  49. package/dist/graphml.js +2 -2
  50. package/dist/json.js +1 -1
  51. package/dist/neo4j.js +3 -3
  52. package/dist/obo.js +1 -1
  53. package/dist/pajek.js +1 -1
  54. package/dist/src/common/export.d.ts +6 -0
  55. package/dist/src/common/export.d.ts.map +1 -1
  56. package/dist/src/common/export.js +62 -28
  57. package/dist/src/common/export.js.map +1 -1
  58. package/dist/src/common/format.d.ts +0 -8
  59. package/dist/src/common/format.d.ts.map +1 -1
  60. package/dist/src/common/format.js +0 -10
  61. package/dist/src/common/format.js.map +1 -1
  62. package/dist/src/common/json-elements.d.ts +1 -9
  63. package/dist/src/common/json-elements.d.ts.map +1 -1
  64. package/dist/src/common/json-elements.js +2 -12
  65. package/dist/src/common/json-elements.js.map +1 -1
  66. package/dist/src/formats/csv/exporter.d.ts.map +1 -1
  67. package/dist/src/formats/csv/exporter.js +18 -7
  68. package/dist/src/formats/csv/exporter.js.map +1 -1
  69. package/dist/src/formats/cx/importer.d.ts.map +1 -1
  70. package/dist/src/formats/cx/importer.js +3 -3
  71. package/dist/src/formats/cx/importer.js.map +1 -1
  72. package/dist/src/formats/cx2/importer.d.ts.map +1 -1
  73. package/dist/src/formats/cx2/importer.js +3 -3
  74. package/dist/src/formats/cx2/importer.js.map +1 -1
  75. package/dist/src/formats/cys/exporter.d.ts.map +1 -1
  76. package/dist/src/formats/cys/exporter.js +4 -3
  77. package/dist/src/formats/cys/exporter.js.map +1 -1
  78. package/dist/src/formats/dot/exporter.js +1 -1
  79. package/dist/src/formats/dot/importer.d.ts +2 -2
  80. package/dist/src/formats/dot/importer.d.ts.map +1 -1
  81. package/dist/src/formats/dot/importer.js +7 -11
  82. package/dist/src/formats/dot/importer.js.map +1 -1
  83. package/dist/src/formats/gexf/exporter.d.ts +2 -2
  84. package/dist/src/formats/gexf/exporter.d.ts.map +1 -1
  85. package/dist/src/formats/gexf/exporter.js +7 -5
  86. package/dist/src/formats/gexf/exporter.js.map +1 -1
  87. package/dist/src/formats/gexf/schema.js +1 -1
  88. package/dist/src/formats/json/exporter.js +1 -1
  89. package/dist/src/formats/json/importer.d.ts.map +1 -1
  90. package/dist/src/formats/json/importer.js +4 -6
  91. package/dist/src/formats/json/importer.js.map +1 -1
  92. package/dist/src/formats/obo/syntax.d.ts +4 -0
  93. package/dist/src/formats/obo/syntax.d.ts.map +1 -1
  94. package/dist/src/formats/obo/syntax.js +35 -31
  95. package/dist/src/formats/obo/syntax.js.map +1 -1
  96. package/dist/src/formats/pajek/exporter.d.ts.map +1 -1
  97. package/dist/src/formats/pajek/exporter.js +5 -4
  98. package/dist/src/formats/pajek/exporter.js.map +1 -1
  99. package/dist/src/formats/pajek/importer.d.ts.map +1 -1
  100. package/dist/src/formats/pajek/importer.js +3 -7
  101. package/dist/src/formats/pajek/importer.js.map +1 -1
  102. package/dist/src/formats/pajek/syntax.d.ts +1 -1
  103. package/dist/src/formats/pajek/syntax.js +1 -1
  104. package/dist/src/formats/xgmml/constants.d.ts +1 -1
  105. package/dist/src/formats/xgmml/constants.js +1 -1
  106. package/dist/src/formats/xgmml/emit.js +1 -1
  107. package/dist/src/formats/xgmml/exporter.d.ts.map +1 -1
  108. package/dist/src/formats/xgmml/exporter.js +4 -3
  109. package/dist/src/formats/xgmml/exporter.js.map +1 -1
  110. package/dist/src/types.d.ts +6 -0
  111. package/dist/src/types.d.ts.map +1 -1
  112. package/dist/src/types.js.map +1 -1
  113. package/dist/xgmml.js +2 -2
  114. package/package.json +1 -1
  115. package/src/common/export.ts +105 -62
  116. package/src/common/format.ts +0 -11
  117. package/src/common/json-elements.ts +2 -13
  118. package/src/formats/csv/exporter.ts +19 -15
  119. package/src/formats/cx/importer.ts +2 -3
  120. package/src/formats/cx2/importer.ts +2 -3
  121. package/src/formats/cys/exporter.ts +4 -3
  122. package/src/formats/dot/exporter.ts +1 -1
  123. package/src/formats/dot/importer.ts +7 -17
  124. package/src/formats/gexf/exporter.ts +7 -5
  125. package/src/formats/gexf/schema.ts +1 -1
  126. package/src/formats/json/exporter.ts +1 -1
  127. package/src/formats/json/importer.ts +4 -7
  128. package/src/formats/obo/syntax.ts +35 -31
  129. package/src/formats/pajek/exporter.ts +5 -4
  130. package/src/formats/pajek/importer.ts +3 -13
  131. package/src/formats/pajek/syntax.ts +1 -1
  132. package/src/formats/xgmml/constants.ts +1 -1
  133. package/src/formats/xgmml/emit.ts +1 -1
  134. package/src/formats/xgmml/exporter.ts +4 -3
  135. package/src/types.ts +6 -0
  136. package/dist/chunks/exporter-D23CKNqF.js.map +0 -1
  137. package/dist/chunks/exporter-DhtW6FxK.js.map +0 -1
  138. package/dist/chunks/importer-BSALvkui.js.map +0 -1
  139. package/dist/chunks/importer-BVRE--Un.js.map +0 -1
  140. package/dist/chunks/importer-BZB7iP9r.js.map +0 -1
  141. package/dist/chunks/importer-CIAzt-wo.js.map +0 -1
  142. package/dist/chunks/importer-z_FL4VMb.js.map +0 -1
@@ -6,6 +6,10 @@
6
6
  *
7
7
  * Every function works on the RAW text (escapes still in place) and unescapes only the pieces it
8
8
  * hands back, so an escaped quote, colon, comma, brace or `!` never ends a construct.
9
+ *
10
+ * The scanners read characters with charAt(), never `text[i]`: the importer's linear-time tests
11
+ * count the characters the import reads through the string methods, and an index read is
12
+ * invisible to them, so a quadratic scan written with it would pass unnoticed.
9
13
  */
10
14
 
11
15
  /** The OBO escapes with a meaning of their own; any other `\x` is `x` (the guides). */
@@ -29,14 +33,14 @@ export function unescapeObo(text: string): string {
29
33
  }
30
34
  let out = "";
31
35
  for (let i = 0; i < text.length; i++) {
32
- const ch = text[i];
36
+ const ch = text.charAt(i);
33
37
  if (ch !== "\\") {
34
38
  out += ch;
35
39
  continue;
36
40
  }
37
41
  i++;
38
42
  if (i < text.length) {
39
- const next = text[i];
43
+ const next = text.charAt(i);
40
44
  out += ESCAPES[next] ?? next;
41
45
  }
42
46
  }
@@ -51,7 +55,7 @@ export function unescapeObo(text: string): string {
51
55
  */
52
56
  function isEscaped(text: string, index: number): boolean {
53
57
  let run = 0;
54
- for (let i = index - 1; i >= 0 && text[i] === "\\"; i--) {
58
+ for (let i = index - 1; i >= 0 && text.charAt(i) === "\\"; i--) {
55
59
  run++;
56
60
  }
57
61
  return run % 2 === 1;
@@ -71,8 +75,8 @@ export function splitFormFeeds(line: string): string[] {
71
75
  const pieces: string[] = [];
72
76
  let quoted = false;
73
77
  let start = 0;
74
- for (let i = 0; i < line.length; i += line[i] === "\\" ? 2 : 1) {
75
- const ch = line[i];
78
+ for (let i = 0; i < line.length; i += line.charAt(i) === "\\" ? 2 : 1) {
79
+ const ch = line.charAt(i);
76
80
  if (ch === '"') {
77
81
  quoted = !quoted;
78
82
  } else if (ch === "\f" && !quoted) {
@@ -110,11 +114,11 @@ interface TagValue {
110
114
  */
111
115
  export function splitTagValue(line: string): TagValue | null {
112
116
  for (let i = 0; i < line.length; i++) {
113
- if (line[i] === "\\") {
117
+ if (line.charAt(i) === "\\") {
114
118
  i++;
115
119
  continue;
116
120
  }
117
- if (line[i] === ":") {
121
+ if (line.charAt(i) === ":") {
118
122
  return { tag: unescapeObo(line.slice(0, i).trim()), rest: line.slice(i + 1).trimStart() };
119
123
  }
120
124
  }
@@ -134,12 +138,12 @@ export function splitTagValue(line: string): TagValue | null {
134
138
  export function stripComment(rest: string): string {
135
139
  let quoted = false;
136
140
  for (let i = 0; i < rest.length; i++) {
137
- const ch = rest[i];
141
+ const ch = rest.charAt(i);
138
142
  if (ch === "\\") {
139
143
  i++;
140
144
  continue;
141
145
  }
142
- const atStart = i === 0 || rest[i - 1] === " " || rest[i - 1] === "\t";
146
+ const atStart = i === 0 || rest.charAt(i - 1) === " " || rest.charAt(i - 1) === "\t";
143
147
  if (ch === '"' && (quoted || atStart)) {
144
148
  quoted = !quoted;
145
149
  } else if (ch === "!" && !quoted && atStart) {
@@ -183,7 +187,7 @@ export function splitQualifiers(value: string): QualifiedValue {
183
187
  const parsed: Qualifiers[] = [];
184
188
  let end = value.length;
185
189
  let badBlock: string | null = null;
186
- while (end > 0 && value[end - 1] === "}" && !isEscaped(value, end - 1)) {
190
+ while (end > 0 && value.charAt(end - 1) === "}" && !isEscaped(value, end - 1)) {
187
191
  const open = blocks.get(end - 1) ?? -1;
188
192
  const block = open < 0 ? null : parseQualifiers(value.slice(open + 1, end - 1));
189
193
  if (block === null) {
@@ -192,7 +196,7 @@ export function splitQualifiers(value: string): QualifiedValue {
192
196
  }
193
197
  parsed.push(block);
194
198
  end = open;
195
- while (end > 0 && /\s/.test(value[end - 1])) {
199
+ while (end > 0 && /\s/.test(value.charAt(end - 1))) {
196
200
  end--;
197
201
  }
198
202
  }
@@ -217,7 +221,7 @@ function braceBlocks(value: string): Map<number, number> {
217
221
  let quoted = false;
218
222
  let open = -1;
219
223
  for (let i = 0; i < value.length; i++) {
220
- const ch = value[i];
224
+ const ch = value.charAt(i);
221
225
  if (ch === "\\") {
222
226
  i++;
223
227
  continue;
@@ -244,8 +248,8 @@ function braceBlocks(value: string): Map<number, number> {
244
248
  export function unclosedBlock(value: string): number {
245
249
  let quoted = false;
246
250
  let open = -1;
247
- for (let i = 0; i < value.length; i += value[i] === "\\" ? 2 : 1) {
248
- const ch = value[i];
251
+ for (let i = 0; i < value.length; i += value.charAt(i) === "\\" ? 2 : 1) {
252
+ const ch = value.charAt(i);
249
253
  if (ch === "\\") {
250
254
  continue;
251
255
  }
@@ -297,7 +301,7 @@ export function parseQualifiers(inner: string): Qualifiers | null {
297
301
  const n = inner.length;
298
302
  let any = false;
299
303
  while (i < n) {
300
- while (i < n && (inner[i] === " " || inner[i] === "\t" || inner[i] === ",")) {
304
+ while (i < n && (inner.charAt(i) === " " || inner.charAt(i) === "\t" || inner.charAt(i) === ",")) {
301
305
  i++;
302
306
  }
303
307
  if (i >= n) {
@@ -312,11 +316,11 @@ export function parseQualifiers(inner: string): Qualifiers | null {
312
316
  return null;
313
317
  }
314
318
  i = eq + 1;
315
- while (i < n && (inner[i] === " " || inner[i] === "\t")) {
319
+ while (i < n && (inner.charAt(i) === " " || inner.charAt(i) === "\t")) {
316
320
  i++;
317
321
  }
318
322
  let value: string;
319
- if (inner[i] === '"') {
323
+ if (inner.charAt(i) === '"') {
320
324
  const end = closingQuote(inner, i + 1);
321
325
  if (end < 0) {
322
326
  return null;
@@ -325,8 +329,8 @@ export function parseQualifiers(inner: string): Qualifiers | null {
325
329
  i = end + 1;
326
330
  } else {
327
331
  let end = i;
328
- while (end < n && inner[end] !== ",") {
329
- end += inner[end] === "\\" ? 2 : 1;
332
+ while (end < n && inner.charAt(end) !== ",") {
333
+ end += inner.charAt(end) === "\\" ? 2 : 1;
330
334
  }
331
335
  value = unescapeObo(inner.slice(i, end).trim());
332
336
  i = end;
@@ -345,9 +349,9 @@ export function parseQualifiers(inner: string): Qualifiers | null {
345
349
  */
346
350
  function closingQuote(text: string, from: number): number {
347
351
  for (let i = from; i < text.length; i++) {
348
- if (text[i] === "\\") {
352
+ if (text.charAt(i) === "\\") {
349
353
  i++;
350
- } else if (text[i] === '"') {
354
+ } else if (text.charAt(i) === '"') {
351
355
  return i;
352
356
  }
353
357
  }
@@ -379,7 +383,7 @@ export function tokenize(value: string): Token[] {
379
383
  const n = value.length;
380
384
  let i = 0;
381
385
  while (i < n) {
382
- const ch = value[i];
386
+ const ch = value.charAt(i);
383
387
  if (ch === " " || ch === "\t") {
384
388
  i++;
385
389
  continue;
@@ -390,8 +394,8 @@ export function tokenize(value: string): Token[] {
390
394
  // a 1.4 language tag glued to the closing quote ("chat"@fr) is kept with the text, as an
391
395
  // unquoted chat@fr is (research-obo.md 4.1: no language is split out)
392
396
  let after = stop + 1;
393
- if (end >= 0 && value[after] === "@") {
394
- while (after < n && value[after] !== " " && value[after] !== "\t") {
397
+ if (end >= 0 && value.charAt(after) === "@") {
398
+ while (after < n && value.charAt(after) !== " " && value.charAt(after) !== "\t") {
395
399
  after++;
396
400
  }
397
401
  }
@@ -412,8 +416,8 @@ export function tokenize(value: string): Token[] {
412
416
  continue;
413
417
  }
414
418
  let end = i;
415
- while (end < n && value[end] !== " " && value[end] !== "\t") {
416
- end += value[end] === "\\" ? 2 : 1;
419
+ while (end < n && value.charAt(end) !== " " && value.charAt(end) !== "\t") {
420
+ end += value.charAt(end) === "\\" ? 2 : 1;
417
421
  }
418
422
  tokens.push({ kind: "word", text: unescapeObo(value.slice(i, Math.min(end, n))), unterminated: false });
419
423
  i = end;
@@ -430,7 +434,7 @@ export function tokenize(value: string): Token[] {
430
434
  function closingBracket(text: string, from: number): number {
431
435
  let quoted = false;
432
436
  for (let i = from; i < text.length; i++) {
433
- const ch = text[i];
437
+ const ch = text.charAt(i);
434
438
  if (ch === "\\") {
435
439
  i++;
436
440
  } else if (ch === '"') {
@@ -468,9 +472,9 @@ export function parseXref(raw: string): Xref | null {
468
472
  const { value, qualifiers } = splitQualifiers(raw.trim());
469
473
  let quote = -1;
470
474
  for (let i = 0; i < value.length; i++) {
471
- if (value[i] === "\\") {
475
+ if (value.charAt(i) === "\\") {
472
476
  i++;
473
- } else if (value[i] === '"') {
477
+ } else if (value.charAt(i) === '"') {
474
478
  quote = i;
475
479
  break;
476
480
  }
@@ -508,7 +512,7 @@ export function parseXrefList(inner: string): Xref[] {
508
512
  }
509
513
  };
510
514
  for (let i = 0; i < inner.length; i++) {
511
- const ch = inner[i];
515
+ const ch = inner.charAt(i);
512
516
  if (ch === "\\") {
513
517
  i++;
514
518
  } else if (ch === '"') {
@@ -538,7 +542,7 @@ export function hasStrayBrace(value: string): boolean {
538
542
  let quoted = false;
539
543
  let listed = false;
540
544
  for (let i = 0; i < value.length; i++) {
541
- const ch = value[i];
545
+ const ch = value.charAt(i);
542
546
  if (ch === "\\") {
543
547
  i++;
544
548
  } else if (ch === '"') {
@@ -17,7 +17,7 @@ import { type Column, GraphFormatError, type GraphSnapshot } from "@graphty/grap
17
17
  import { pairFolding } from "../../common/direction.js";
18
18
  import { isPajekLabel, quotePajekLabel } from "../../common/escape.js";
19
19
  import { capabilities, checkCapabilities, LOSS, type SanitizedIds, sanitizeIds } from "../../common/export.js";
20
- import { formatDecimal, formatF32, formatInteger, idText } from "../../common/format.js";
20
+ import { formatDecimal, formatF32, formatInteger, formatNumber, idText } from "../../common/format.js";
21
21
  import { canonicalId } from "../../common/ids.js";
22
22
  import { resolveExportOptions } from "../../common/options.js";
23
23
  import { agree, plural } from "../../common/plural.js";
@@ -586,10 +586,11 @@ function coordinatesText(column: Column, i: number, writeZ: boolean): string | n
586
586
  }
587
587
  const dtype = column.dtype as "f32" | "f64" | "i32" | "u32" | "u8";
588
588
  const vector = column.value(i) as ArrayLike<number>;
589
- const x = numberText(vector[0], dtype);
590
- const y = numberText(vector[1], dtype);
589
+ // the importer reads coordinates by position, so the shortest text of each is enough
590
+ const x = formatNumber(vector[0], dtype);
591
+ const y = formatNumber(vector[1], dtype);
591
592
  if (column.meta.components === 3 && writeZ) {
592
- return `${x} ${y} ${numberText(vector[2], dtype)}`;
593
+ return `${x} ${y} ${formatNumber(vector[2], dtype)}`;
593
594
  }
594
595
  return `${x} ${y}`;
595
596
  }
@@ -46,7 +46,6 @@ import {
46
46
  UNKNOWN_ENCODING_CODE,
47
47
  } from "../../common/codes.js";
48
48
  import { DirectionResolver, type EdgeKind } from "../../common/direction.js";
49
- import { survivesF32 } from "../../common/format.js";
50
49
  import { coerceIdText, ID_MERGED_CODE, IdCoercer } from "../../common/ids.js";
51
50
  import { LineReader, throwIfAborted } from "../../common/input.js";
52
51
  import {
@@ -292,14 +291,14 @@ function spellsDecl(): ColumnDecl {
292
291
  }
293
292
 
294
293
  /**
295
- * The position column declaration (design section 5.2: f32 x 3, role position, units "file").
294
+ * The position column declaration (design section 5.2: f64 x 3, role position, units "file").
296
295
  * @param sourceDims - 2 or 3, the coordinate count of the first vertex line with coordinates
297
296
  * @returns a fresh declaration
298
297
  */
299
298
  function positionDecl(sourceDims: number): ColumnDecl {
300
299
  return {
301
300
  name: POSITION_COLUMN,
302
- dtype: "f32",
301
+ dtype: "f64",
303
302
  components: 3,
304
303
  nullable: true,
305
304
  role: "position",
@@ -1183,7 +1182,7 @@ class PajekParser {
1183
1182
  }
1184
1183
 
1185
1184
  /**
1186
- * Write a vertex's coordinates into the position column (f32 x 3), declared on first use.
1185
+ * Write a vertex's coordinates into the position column (f64 x 3), declared on first use.
1187
1186
  * @param index - the node index
1188
1187
  * @param dims - 2 or 3, the coordinates the line gave
1189
1188
  * @param point - x, y, z (0 when absent)
@@ -1202,15 +1201,6 @@ class PajekParser {
1202
1201
  { line, element: String(k) },
1203
1202
  );
1204
1203
  }
1205
- if (!point.every(survivesF32)) {
1206
- this.report.warnOnce(
1207
- "precision",
1208
- PAJEK_ISSUE.PRECISION,
1209
- `vertex ${k} has a coordinate the f32 position column rounds (warned once)`,
1210
- { line, element: String(k) },
1211
- `${PAJEK_ISSUE.PRECISION}:position`,
1212
- );
1213
- }
1214
1204
  this.sink.setNodeValue(this.positionHandle, index, point);
1215
1205
  }
1216
1206
 
@@ -15,7 +15,7 @@
15
15
  export const LABEL_COLUMN = "label";
16
16
 
17
17
  /**
18
- * The node column holding the vertex coordinates (role position, f32 x 3, units "file").
18
+ * The node column holding the vertex coordinates (role position, f64 x 3, units "file").
19
19
  * @category Plugin helpers
20
20
  */
21
21
  export const POSITION_COLUMN = "position";
@@ -108,7 +108,7 @@ export const LABEL_COLUMN = "label";
108
108
  export const EDGE_ID_COLUMN = "id";
109
109
 
110
110
  /**
111
- * The node position (f32 x3, role position, y up).
111
+ * The node position (f64 x3, role position, y up).
112
112
  * @category Plugin helpers
113
113
  */
114
114
  export const POSITION_COLUMN = "position";
@@ -1430,7 +1430,7 @@ class Positions {
1430
1430
  if (this.values.size > 0) {
1431
1431
  const handle = this.emitter.declare("node", {
1432
1432
  name: POSITION_COLUMN,
1433
- dtype: "f32",
1433
+ dtype: "f64",
1434
1434
  components: 3,
1435
1435
  role: "position",
1436
1436
  nullable: true,
@@ -538,7 +538,7 @@ function planExport(snapshot: GraphSnapshot, options: ResolvedExportOptions, esc
538
538
  const notes = checkCapabilities(snapshot, CAPABILITIES, options, {
539
539
  roles: SLOT_ROLES,
540
540
  roleNames: ROLE_NAMES,
541
- positionDtype: "f32",
541
+ positionDtype: "f64",
542
542
  }).filter((n) => n.code !== LOSS.JSON);
543
543
  const note: NoteFn = (code, message, column = null, count = null): void => {
544
544
  notes.push(Object.freeze({ code, message, column, count }));
@@ -986,10 +986,11 @@ function coordsOf(plan: Plan, zColumn: Column | null, node: number): [string, st
986
986
  const xyz = cellOf(plan.position, node);
987
987
  if (xyz !== null) {
988
988
  const [x, y, z] = Array.from(xyz as ArrayLike<number>);
989
+ const fmt = plan.position?.dtype === "f32" ? formatF32 : formatF64;
989
990
  if (Number.isFinite(x) && Number.isFinite(y)) {
990
- out.push(["x", formatF32(x)], ["y", formatF32(y === 0 ? 0 : -y)]);
991
+ out.push(["x", fmt(x)], ["y", fmt(y === 0 ? 0 : -y)]);
991
992
  if (zColumn === null && z !== undefined && z !== 0 && Number.isFinite(z)) {
992
- out.push(["z", formatF32(z)]);
993
+ out.push(["z", fmt(z)]);
993
994
  }
994
995
  }
995
996
  }
package/src/types.ts CHANGED
@@ -368,6 +368,12 @@ export interface LossNote {
368
368
  readonly column: string | null;
369
369
  /** How many nodes, edges or values are affected, or null when not counted. */
370
370
  readonly count: number | null;
371
+ /**
372
+ * Every column the note is about, when it is about several and `column` is null: the graph
373
+ * attributes a format has no place for, or the node columns a CSV edge table leaves for the node
374
+ * table. Absent on a note about one column or none.
375
+ */
376
+ readonly columns?: readonly string[];
371
377
  }
372
378
 
373
379
  /**