@graphty/graph-io 0.3.40 → 0.3.41

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 (189) hide show
  1. package/dist/chunks/{choose-CS3fvGT1.js → choose-CwFQamH9.js} +2 -2
  2. package/dist/chunks/{choose-CS3fvGT1.js.map → choose-CwFQamH9.js.map} +1 -1
  3. package/dist/chunks/{constants-DqKZT6cH.js → constants-Cf4Nn6tw.js} +2 -2
  4. package/dist/chunks/{constants-DqKZT6cH.js.map → constants-Cf4Nn6tw.js.map} +1 -1
  5. package/dist/chunks/{escape-BJRLd3vJ.js → escape-DBb8zuNE.js} +2 -2
  6. package/dist/chunks/{escape-BJRLd3vJ.js.map → escape-DBb8zuNE.js.map} +1 -1
  7. package/dist/chunks/{export-B-aVCwyG.js → export-DD3Lvw-F.js} +173 -116
  8. package/dist/chunks/export-DD3Lvw-F.js.map +1 -0
  9. package/dist/chunks/{exporter-Bcp-l4Bo.js → exporter-BqtmlxNr.js} +545 -459
  10. package/dist/chunks/exporter-BqtmlxNr.js.map +1 -0
  11. package/dist/chunks/{exporter-6ocL_9x_.js → exporter-CS35R6Fg.js} +4 -4
  12. package/dist/chunks/{exporter-6ocL_9x_.js.map → exporter-CS35R6Fg.js.map} +1 -1
  13. package/dist/chunks/{exporter-BVXnV9-9.js → exporter-D8r1N2dU.js} +28 -16
  14. package/dist/chunks/exporter-D8r1N2dU.js.map +1 -0
  15. package/dist/chunks/{exporter-SFYkDzD0.js → exporter-NMplSnYn.js} +23 -20
  16. package/dist/chunks/{exporter-SFYkDzD0.js.map → exporter-NMplSnYn.js.map} +1 -1
  17. package/dist/chunks/{importer-CPqnIY8m.js → importer-BKC7AmCA.js} +42 -29
  18. package/dist/chunks/importer-BKC7AmCA.js.map +1 -0
  19. package/dist/chunks/{importer-D_srHyj6.js → importer-BdWHmlmG.js} +4 -4
  20. package/dist/chunks/{importer-D_srHyj6.js.map → importer-BdWHmlmG.js.map} +1 -1
  21. package/dist/chunks/{importer-AjwOJrn2.js → importer-BfbzWk6k.js} +202 -181
  22. package/dist/chunks/importer-BfbzWk6k.js.map +1 -0
  23. package/dist/chunks/{importer-BpuS3J8C.js → importer-BmaZcskq.js} +73 -60
  24. package/dist/chunks/importer-BmaZcskq.js.map +1 -0
  25. package/dist/chunks/{importer-DEp_fYjf.js → importer-DviEsHy4.js} +92 -64
  26. package/dist/chunks/importer-DviEsHy4.js.map +1 -0
  27. package/dist/chunks/{importer-DcKB97kW.js → importer-S-abxJHn.js} +5 -5
  28. package/dist/chunks/{importer-DcKB97kW.js.map → importer-S-abxJHn.js.map} +1 -1
  29. package/dist/chunks/{importer-BJlGAOht.js → importer-r29cWnEf.js} +3 -3
  30. package/dist/chunks/{importer-BJlGAOht.js.map → importer-r29cWnEf.js.map} +1 -1
  31. package/dist/chunks/{json-elements-DpO6AXIc.js → json-elements-DdF-etPT.js} +3 -3
  32. package/dist/chunks/{json-elements-DpO6AXIc.js.map → json-elements-DdF-etPT.js.map} +1 -1
  33. package/dist/chunks/{ontology-export-50L9DOV4.js → ontology-export-BC0zyPhj.js} +2 -2
  34. package/dist/chunks/{ontology-export-50L9DOV4.js.map → ontology-export-BC0zyPhj.js.map} +1 -1
  35. package/dist/chunks/{records-r3SFHz11.js → records-Uc3LkABx.js} +15 -12
  36. package/dist/chunks/records-Uc3LkABx.js.map +1 -0
  37. package/dist/chunks/{text-Bjfa1xYL.js → text-Bh9SaAob.js} +20 -11
  38. package/dist/chunks/text-Bh9SaAob.js.map +1 -0
  39. package/dist/csv.js +67 -49
  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 +195 -97
  46. package/dist/gexf.js.map +1 -1
  47. package/dist/gml.js +170 -149
  48. package/dist/gml.js.map +1 -1
  49. package/dist/graph-io.js +26 -26
  50. package/dist/graphml.js +2 -2
  51. package/dist/json.js +1 -1
  52. package/dist/neo4j.js +103 -65
  53. package/dist/neo4j.js.map +1 -1
  54. package/dist/obo.js +1 -1
  55. package/dist/pajek.js +1 -1
  56. package/dist/src/common/attributes.d.ts.map +1 -1
  57. package/dist/src/common/attributes.js +34 -9
  58. package/dist/src/common/attributes.js.map +1 -1
  59. package/dist/src/common/input.d.ts.map +1 -1
  60. package/dist/src/common/input.js +180 -102
  61. package/dist/src/common/input.js.map +1 -1
  62. package/dist/src/common/text.d.ts +7 -0
  63. package/dist/src/common/text.d.ts.map +1 -1
  64. package/dist/src/common/text.js +15 -7
  65. package/dist/src/common/text.js.map +1 -1
  66. package/dist/src/common/zip.d.ts.map +1 -1
  67. package/dist/src/common/zip.js +36 -19
  68. package/dist/src/common/zip.js.map +1 -1
  69. package/dist/src/formats/csv/exporter.d.ts.map +1 -1
  70. package/dist/src/formats/csv/exporter.js +77 -25
  71. package/dist/src/formats/csv/exporter.js.map +1 -1
  72. package/dist/src/formats/csv/importer.d.ts.map +1 -1
  73. package/dist/src/formats/csv/importer.js +16 -6
  74. package/dist/src/formats/csv/importer.js.map +1 -1
  75. package/dist/src/formats/csv/records.d.ts.map +1 -1
  76. package/dist/src/formats/csv/records.js +18 -10
  77. package/dist/src/formats/csv/records.js.map +1 -1
  78. package/dist/src/formats/cys/tables.d.ts.map +1 -1
  79. package/dist/src/formats/cys/tables.js +11 -8
  80. package/dist/src/formats/cys/tables.js.map +1 -1
  81. package/dist/src/formats/gexf/exporter.d.ts.map +1 -1
  82. package/dist/src/formats/gexf/exporter.js +65 -37
  83. package/dist/src/formats/gexf/exporter.js.map +1 -1
  84. package/dist/src/formats/gexf/importer.d.ts.map +1 -1
  85. package/dist/src/formats/gexf/importer.js +138 -50
  86. package/dist/src/formats/gexf/importer.js.map +1 -1
  87. package/dist/src/formats/gml/exporter.d.ts.map +1 -1
  88. package/dist/src/formats/gml/exporter.js +51 -35
  89. package/dist/src/formats/gml/exporter.js.map +1 -1
  90. package/dist/src/formats/gml/importer.d.ts.map +1 -1
  91. package/dist/src/formats/gml/importer.js +103 -58
  92. package/dist/src/formats/gml/importer.js.map +1 -1
  93. package/dist/src/formats/gml/syntax.d.ts.map +1 -1
  94. package/dist/src/formats/gml/syntax.js +17 -8
  95. package/dist/src/formats/gml/syntax.js.map +1 -1
  96. package/dist/src/formats/graphml/exporter.d.ts.map +1 -1
  97. package/dist/src/formats/graphml/exporter.js +34 -24
  98. package/dist/src/formats/graphml/exporter.js.map +1 -1
  99. package/dist/src/formats/graphml/importer.d.ts.map +1 -1
  100. package/dist/src/formats/graphml/importer.js +17 -13
  101. package/dist/src/formats/graphml/importer.js.map +1 -1
  102. package/dist/src/formats/graphml/tree.js +23 -14
  103. package/dist/src/formats/graphml/tree.js.map +1 -1
  104. package/dist/src/formats/graphml/yfiles.d.ts.map +1 -1
  105. package/dist/src/formats/graphml/yfiles.js +22 -10
  106. package/dist/src/formats/graphml/yfiles.js.map +1 -1
  107. package/dist/src/formats/json/exporter.d.ts.map +1 -1
  108. package/dist/src/formats/json/exporter.js +38 -21
  109. package/dist/src/formats/json/exporter.js.map +1 -1
  110. package/dist/src/formats/json/importer.d.ts.map +1 -1
  111. package/dist/src/formats/json/importer.js +536 -343
  112. package/dist/src/formats/json/importer.js.map +1 -1
  113. package/dist/src/formats/json/obographs.js +29 -17
  114. package/dist/src/formats/json/obographs.js.map +1 -1
  115. package/dist/src/formats/neo4j/exporter.d.ts.map +1 -1
  116. package/dist/src/formats/neo4j/exporter.js +73 -43
  117. package/dist/src/formats/neo4j/exporter.js.map +1 -1
  118. package/dist/src/formats/neo4j/header.d.ts.map +1 -1
  119. package/dist/src/formats/neo4j/header.js +37 -16
  120. package/dist/src/formats/neo4j/header.js.map +1 -1
  121. package/dist/src/formats/neo4j/importer.d.ts.map +1 -1
  122. package/dist/src/formats/neo4j/importer.js +21 -11
  123. package/dist/src/formats/neo4j/importer.js.map +1 -1
  124. package/dist/src/formats/obo/exporter.d.ts.map +1 -1
  125. package/dist/src/formats/obo/exporter.js +18 -7
  126. package/dist/src/formats/obo/exporter.js.map +1 -1
  127. package/dist/src/formats/pajek/exporter.d.ts.map +1 -1
  128. package/dist/src/formats/pajek/exporter.js +142 -73
  129. package/dist/src/formats/pajek/exporter.js.map +1 -1
  130. package/dist/src/formats/pajek/importer.d.ts.map +1 -1
  131. package/dist/src/formats/pajek/importer.js +26 -15
  132. package/dist/src/formats/pajek/importer.js.map +1 -1
  133. package/dist/src/formats/pajek/syntax.d.ts.map +1 -1
  134. package/dist/src/formats/pajek/syntax.js +85 -58
  135. package/dist/src/formats/pajek/syntax.js.map +1 -1
  136. package/dist/src/formats/xgmml/emit.d.ts +7 -0
  137. package/dist/src/formats/xgmml/emit.d.ts.map +1 -1
  138. package/dist/src/formats/xgmml/emit.js +79 -40
  139. package/dist/src/formats/xgmml/emit.js.map +1 -1
  140. package/dist/src/formats/xgmml/exporter.d.ts.map +1 -1
  141. package/dist/src/formats/xgmml/exporter.js +38 -12
  142. package/dist/src/formats/xgmml/exporter.js.map +1 -1
  143. package/dist/src/formats/xgmml/importer.d.ts.map +1 -1
  144. package/dist/src/formats/xgmml/importer.js +38 -18
  145. package/dist/src/formats/xgmml/importer.js.map +1 -1
  146. package/dist/src/sniff.js +109 -57
  147. package/dist/src/sniff.js.map +1 -1
  148. package/dist/xgmml.js +2 -2
  149. package/package.json +2 -2
  150. package/src/common/attributes.ts +59 -19
  151. package/src/common/input.ts +216 -102
  152. package/src/common/text.ts +24 -15
  153. package/src/common/zip.ts +47 -18
  154. package/src/formats/csv/exporter.ts +103 -39
  155. package/src/formats/csv/importer.ts +17 -6
  156. package/src/formats/csv/records.ts +19 -10
  157. package/src/formats/cys/tables.ts +11 -10
  158. package/src/formats/gexf/exporter.ts +67 -36
  159. package/src/formats/gexf/importer.ts +173 -63
  160. package/src/formats/gml/exporter.ts +78 -82
  161. package/src/formats/gml/importer.ts +119 -68
  162. package/src/formats/gml/syntax.ts +18 -8
  163. package/src/formats/graphml/exporter.ts +44 -24
  164. package/src/formats/graphml/importer.ts +18 -11
  165. package/src/formats/graphml/tree.ts +22 -12
  166. package/src/formats/graphml/yfiles.ts +23 -10
  167. package/src/formats/json/exporter.ts +40 -21
  168. package/src/formats/json/importer.ts +701 -385
  169. package/src/formats/json/obographs.ts +35 -15
  170. package/src/formats/neo4j/exporter.ts +79 -41
  171. package/src/formats/neo4j/header.ts +50 -16
  172. package/src/formats/neo4j/importer.ts +21 -10
  173. package/src/formats/obo/exporter.ts +34 -17
  174. package/src/formats/pajek/exporter.ts +180 -117
  175. package/src/formats/pajek/importer.ts +27 -15
  176. package/src/formats/pajek/syntax.ts +99 -58
  177. package/src/formats/xgmml/emit.ts +88 -40
  178. package/src/formats/xgmml/exporter.ts +40 -12
  179. package/src/formats/xgmml/importer.ts +45 -23
  180. package/src/sniff.ts +115 -59
  181. package/dist/chunks/export-B-aVCwyG.js.map +0 -1
  182. package/dist/chunks/exporter-BVXnV9-9.js.map +0 -1
  183. package/dist/chunks/exporter-Bcp-l4Bo.js.map +0 -1
  184. package/dist/chunks/importer-AjwOJrn2.js.map +0 -1
  185. package/dist/chunks/importer-BpuS3J8C.js.map +0 -1
  186. package/dist/chunks/importer-CPqnIY8m.js.map +0 -1
  187. package/dist/chunks/importer-DEp_fYjf.js.map +0 -1
  188. package/dist/chunks/records-r3SFHz11.js.map +0 -1
  189. package/dist/chunks/text-Bjfa1xYL.js.map +0 -1
package/dist/csv.js CHANGED
@@ -1,8 +1,8 @@
1
- import { b as plural, bU as DICT_SAMPLE_ROWS, ac as DictHeuristic, R as ROLE_TAKEN_CODE$1, I as ID_MERGED_CODE$1, m as DUPLICATE_EDGE_ID_CODE$1, n as DUPLICATE_NODE_CODE$1, t as MISSING_ID_CODE$1, s as MISSING_ENDPOINT_CODE$1, E as EMPTY_INPUT_CODE$1, al as resolveImportOptions, a8 as ImportReportBuilder, ao as reportSinkOptions, an as reportUnusedOptions, aq as DirectionResolver, ar as IdCoercer, am as throwIfAborted, O as OPTION_IGNORED_CODE, aK as parseWeightText, a0 as uniqueColumnName, ay as RENAMED_CODE, a1 as declareResolved, c as capabilities, L as LOSS, a as checkCapabilities, r as resolveExportOptions, p as pairFolding, bD as countMixedEdges, $ as agree, e as explicitWeights, b_ as otherFormatDialect, bS as joinListText, aG as formatInteger, aF as formatDecimal, aH as canonicalId, M as MIXED_DIRECTION_CODE, D as DIRECTION_FORCED_CODE, d as DIRECTION_REFUSED_CODE, S as SINK_OPTION_CODE, C as COLUMN_RENAMED_CODE, w as UNKNOWN_ENCODING_CODE, x as ENCODING_FALLBACK_CODE, y as INVALID_ENCODING_CODE, z as INVALID_UTF8_CODE, P as PRECISION_CODE, F as ELEMENT_ISSUE, G as INPUT_ISSUE } from "./chunks/export-B-aVCwyG.js";
2
- import { i as inferTextDtype, T as TextCellWriter, p as parseTextCell, W as WIDENING_UNSUPPORTED_CODE } from "./chunks/text-Bjfa1xYL.js";
1
+ import { b as plural, bU as DICT_SAMPLE_ROWS, ac as DictHeuristic, R as ROLE_TAKEN_CODE$1, I as ID_MERGED_CODE$1, m as DUPLICATE_EDGE_ID_CODE$1, n as DUPLICATE_NODE_CODE$1, t as MISSING_ID_CODE$1, s as MISSING_ENDPOINT_CODE$1, E as EMPTY_INPUT_CODE$1, al as resolveImportOptions, a8 as ImportReportBuilder, ao as reportSinkOptions, an as reportUnusedOptions, aq as DirectionResolver, ar as IdCoercer, am as throwIfAborted, O as OPTION_IGNORED_CODE, aK as parseWeightText, a0 as uniqueColumnName, ay as RENAMED_CODE, a1 as declareResolved, c as capabilities, L as LOSS, a as checkCapabilities, r as resolveExportOptions, p as pairFolding, bD as countMixedEdges, $ as agree, e as explicitWeights, b_ as otherFormatDialect, bS as joinListText, aG as formatInteger, aF as formatDecimal, aH as canonicalId, M as MIXED_DIRECTION_CODE, D as DIRECTION_FORCED_CODE, d as DIRECTION_REFUSED_CODE, S as SINK_OPTION_CODE, C as COLUMN_RENAMED_CODE, w as UNKNOWN_ENCODING_CODE, x as ENCODING_FALLBACK_CODE, y as INVALID_ENCODING_CODE, z as INVALID_UTF8_CODE, P as PRECISION_CODE, F as ELEMENT_ISSUE, G as INPUT_ISSUE } from "./chunks/export-DD3Lvw-F.js";
2
+ import { i as inferTextDtype, T as TextCellWriter, p as parseTextCell, W as WIDENING_UNSUPPORTED_CODE } from "./chunks/text-Bh9SaAob.js";
3
3
  import { GraphFormatError, INVALID_INDEX } from "@graphty/graph-format";
4
- import { s as stripLeadingComments, a as sniffNewline, b as sniffDelimiter, D as DELIMITER_CANDIDATES, c as checkRecordSyntax, C as CsvRecordReader, d as splitRecords, B as BAD_QUOTE_CODE, U as UNCLOSED_QUOTE_CODE } from "./chunks/records-r3SFHz11.js";
5
- import { o as quoteCsvCell } from "./chunks/escape-BJRLd3vJ.js";
4
+ import { s as stripLeadingComments, a as sniffNewline, b as sniffDelimiter, D as DELIMITER_CANDIDATES, c as checkRecordSyntax, C as CsvRecordReader, d as splitRecords, B as BAD_QUOTE_CODE, U as UNCLOSED_QUOTE_CODE } from "./chunks/records-Uc3LkABx.js";
5
+ import { o as quoteCsvCell } from "./chunks/escape-DBb8zuNE.js";
6
6
  import { j as joinText, e as encodeChunks } from "./chunks/writer-DxjgHwSe.js";
7
7
  const SOURCE_NAMES = Object.freeze([
8
8
  "source",
@@ -433,6 +433,15 @@ function isBlank(text) {
433
433
  function isUnset(text, quoted) {
434
434
  return quoted !== true && isBlank(text);
435
435
  }
436
+ function setNeighborCells(row, quoted) {
437
+ let neighbors = 0;
438
+ for (let k = 1; k < row.length; k++) {
439
+ if (!isUnset(row[k], quoted[k])) {
440
+ neighbors++;
441
+ }
442
+ }
443
+ return neighbors;
444
+ }
436
445
  const ABORT_CHECK_INTERVAL = 64;
437
446
  function uniqueNames(names, report, line) {
438
447
  const seen = /* @__PURE__ */ new Set();
@@ -1199,12 +1208,7 @@ class TableReader {
1199
1208
  const { where } = this;
1200
1209
  where.line = line;
1201
1210
  where.element = null;
1202
- let neighbors = 0;
1203
- for (let k = 1; k < row.length; k++) {
1204
- if (!isUnset(row[k], quoted[k])) {
1205
- neighbors++;
1206
- }
1207
- }
1211
+ const neighbors = setNeighborCells(row, quoted);
1208
1212
  if (isUnset(row[0], quoted[0])) {
1209
1213
  report.error("missing-value", MISSING_ID_CODE, `blank node cell`, { line });
1210
1214
  counts.skippedNodes++;
@@ -1926,19 +1930,23 @@ function nodeTableNote(names, table, notes) {
1926
1930
  );
1927
1931
  }
1928
1932
  }
1933
+ function idTextCollisions(ids) {
1934
+ const seen = /* @__PURE__ */ new Set();
1935
+ let collisions = 0;
1936
+ for (let i = 0; i < ids.size; i++) {
1937
+ const text = String(ids.idOf(i));
1938
+ if (seen.has(text)) {
1939
+ collisions++;
1940
+ } else {
1941
+ seen.add(text);
1942
+ }
1943
+ }
1944
+ return collisions;
1945
+ }
1929
1946
  function idNotes(snapshot, values, note) {
1930
1947
  const { ids } = snapshot;
1931
1948
  if (ids.kind === "mixed") {
1932
- const seen = /* @__PURE__ */ new Set();
1933
- let collisions = 0;
1934
- for (let i = 0; i < ids.size; i++) {
1935
- const text = String(ids.idOf(i));
1936
- if (seen.has(text)) {
1937
- collisions++;
1938
- } else {
1939
- seen.add(text);
1940
- }
1941
- }
1949
+ const collisions = idTextCollisions(ids);
1942
1950
  if (collisions > 0) {
1943
1951
  note(
1944
1952
  CSV_LOSS.ID_TEXT_COLLISION,
@@ -2152,39 +2160,44 @@ function attributeColumns(table, domain, reserved, idColumn, labelColumn, note)
2152
2160
  if (role !== null && SKIPPED_ROLES.has(role)) {
2153
2161
  continue;
2154
2162
  }
2155
- const low = lower(name);
2156
2163
  const set = column.length - column.nullCount;
2157
- const isIdName = domain === "edge" ? findColumn([name], EDGE_ID_NAMES) >= 0 : false;
2158
- if (reserved.has(low) || isIdName || idColumn !== null && lower(idColumn.meta.name) === low) {
2159
- note?.(
2160
- CSV_LOSS.RESERVED_NAME,
2161
- `${domain} column "${name}" is not written: the name is reserved for the ${isIdName ? "edge id" : low} column`,
2162
- name,
2163
- set
2164
- );
2164
+ if (isReservedName(name, domain, reserved, idColumn, set, note)) {
2165
2165
  continue;
2166
2166
  }
2167
- if (findColumn([name], LABEL_NAMES) >= 0) {
2168
- if (labelColumn !== null) {
2169
- note?.(
2170
- CSV_LOSS.RESERVED_NAME,
2171
- `${domain} column "${name}" is not written: the name is reserved for the label column`,
2172
- name,
2173
- set
2174
- );
2175
- continue;
2176
- }
2177
- note?.(
2178
- CSV_LOSS.ROLE_ASSUMED,
2179
- `${domain} column "${name}" reads back with the label role (string)`,
2180
- name,
2181
- set
2182
- );
2167
+ if (findColumn([name], LABEL_NAMES) >= 0 && !labelNameWritten(name, domain, labelColumn, set, note)) {
2168
+ continue;
2183
2169
  }
2184
2170
  out.push({ column, header: name });
2185
2171
  }
2186
2172
  return out;
2187
2173
  }
2174
+ function isReservedName(name, domain, reserved, idColumn, set, note) {
2175
+ const low = lower(name);
2176
+ const isIdName = domain === "edge" ? findColumn([name], EDGE_ID_NAMES) >= 0 : false;
2177
+ if (reserved.has(low) || isIdName || idColumn !== null && lower(idColumn.meta.name) === low) {
2178
+ note?.(
2179
+ CSV_LOSS.RESERVED_NAME,
2180
+ `${domain} column "${name}" is not written: the name is reserved for the ${isIdName ? "edge id" : low} column`,
2181
+ name,
2182
+ set
2183
+ );
2184
+ return true;
2185
+ }
2186
+ return false;
2187
+ }
2188
+ function labelNameWritten(name, domain, labelColumn, set, note) {
2189
+ if (labelColumn !== null) {
2190
+ note?.(
2191
+ CSV_LOSS.RESERVED_NAME,
2192
+ `${domain} column "${name}" is not written: the name is reserved for the label column`,
2193
+ name,
2194
+ set
2195
+ );
2196
+ return false;
2197
+ }
2198
+ note?.(CSV_LOSS.ROLE_ASSUMED, `${domain} column "${name}" reads back with the label role (string)`, name, set);
2199
+ return true;
2200
+ }
2188
2201
  function checkRoleColumn(column, role, names, domain, rows, note) {
2189
2202
  if (column === null) {
2190
2203
  return;
@@ -2303,6 +2316,14 @@ function neighbourCell(id, weight) {
2303
2316
  }
2304
2317
  return id.includes(":") ? `${id}:` : id;
2305
2318
  }
2319
+ function sourceRunEnd(src, edgeRows, r) {
2320
+ const source = src[edgeRows[r]];
2321
+ let end = r;
2322
+ while (end < edgeRows.length && src[edgeRows[end]] === source) {
2323
+ end++;
2324
+ }
2325
+ return end;
2326
+ }
2306
2327
  function* adjacencyLines(snapshot, plan) {
2307
2328
  const { delimiter, newline } = plan.csv;
2308
2329
  const forced = (text) => `"${text.replaceAll('"', '""')}"`;
@@ -2329,10 +2350,7 @@ function* adjacencyLines(snapshot, plan) {
2329
2350
  let r = 0;
2330
2351
  while (r < edgeRows.length) {
2331
2352
  const source = list.src[edgeRows[r]];
2332
- let end = r;
2333
- while (end < edgeRows.length && list.src[edgeRows[end]] === source) {
2334
- end++;
2335
- }
2353
+ const end = sourceRunEnd(list.src, edgeRows, r);
2336
2354
  const fresh = [];
2337
2355
  let highest = -1;
2338
2356
  let inOrder = true;