@graphty/graph-io 0.3.18 → 0.3.20

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 (235) hide show
  1. package/README.md +80 -2
  2. package/dist/chunks/{escape-D-gZWO26.js → escape-B-tkk_Cl.js} +74 -16
  3. package/dist/chunks/escape-B-tkk_Cl.js.map +1 -0
  4. package/dist/chunks/{writer-GAdltGmC.js → export-Bh60Dv-n.js} +7 -252
  5. package/dist/chunks/export-Bh60Dv-n.js.map +1 -0
  6. package/dist/chunks/exporter-BGrsWamJ.js +736 -0
  7. package/dist/chunks/exporter-BGrsWamJ.js.map +1 -0
  8. package/dist/chunks/exporter-DIeGJXAZ.js +834 -0
  9. package/dist/chunks/exporter-DIeGJXAZ.js.map +1 -0
  10. package/dist/chunks/{importer-Br_QeAeE.js → importer-BWY2FFc5.js} +28 -6
  11. package/dist/chunks/importer-BWY2FFc5.js.map +1 -0
  12. package/dist/chunks/importer-BaQpCEcJ.js +2194 -0
  13. package/dist/chunks/importer-BaQpCEcJ.js.map +1 -0
  14. package/dist/chunks/importer-DD-xv9_Y.js +1471 -0
  15. package/dist/chunks/importer-DD-xv9_Y.js.map +1 -0
  16. package/dist/chunks/{importer-aNJfe0qu.js → importer-DEcKhsmQ.js} +2 -2
  17. package/dist/chunks/{importer-aNJfe0qu.js.map → importer-DEcKhsmQ.js.map} +1 -1
  18. package/dist/chunks/{importer-DHagxvDD.js → importer-DIrbbnAf.js} +6 -4
  19. package/dist/chunks/{importer-DHagxvDD.js.map → importer-DIrbbnAf.js.map} +1 -1
  20. package/dist/chunks/importer-D_e7e7LX.js +3055 -0
  21. package/dist/chunks/importer-D_e7e7LX.js.map +1 -0
  22. package/dist/chunks/{importer-Du5crN9l.js → importer-Wv4C4gaF.js} +278 -82
  23. package/dist/chunks/importer-Wv4C4gaF.js.map +1 -0
  24. package/dist/chunks/importer-vi3bSdtw.js +1713 -0
  25. package/dist/chunks/importer-vi3bSdtw.js.map +1 -0
  26. package/dist/chunks/{importer-d0uQxFp6.js → importer-zGLo8Dg_.js} +6 -4
  27. package/dist/chunks/{importer-d0uQxFp6.js.map → importer-zGLo8Dg_.js.map} +1 -1
  28. package/dist/chunks/json-elements-DDS8N2Dd.js +779 -0
  29. package/dist/chunks/json-elements-DDS8N2Dd.js.map +1 -0
  30. package/dist/chunks/{records-Bk9jgodz.js → records-dbRkxwaq.js} +2 -2
  31. package/dist/chunks/{records-Bk9jgodz.js.map → records-dbRkxwaq.js.map} +1 -1
  32. package/dist/chunks/{report-BOk0p5y8.js → report-B1z4WT9e.js} +143 -111
  33. package/dist/chunks/{report-BOk0p5y8.js.map → report-B1z4WT9e.js.map} +1 -1
  34. package/dist/chunks/weights-Dzba96G3.js +176 -0
  35. package/dist/chunks/weights-Dzba96G3.js.map +1 -0
  36. package/dist/chunks/writer-C7flM-Ih.js +77 -0
  37. package/dist/chunks/writer-C7flM-Ih.js.map +1 -0
  38. package/dist/csv.js +6 -4
  39. package/dist/csv.js.map +1 -1
  40. package/dist/cx.d.ts +1 -0
  41. package/dist/cx.js +6 -0
  42. package/dist/cx.js.map +1 -0
  43. package/dist/cx2.d.ts +1 -0
  44. package/dist/cx2.js +10 -0
  45. package/dist/cx2.js.map +1 -0
  46. package/dist/cys.d.ts +1 -0
  47. package/dist/cys.js +6 -0
  48. package/dist/cys.js.map +1 -0
  49. package/dist/dot.js +1 -1
  50. package/dist/gexf.js +16 -4
  51. package/dist/gexf.js.map +1 -1
  52. package/dist/gml.js +13 -14
  53. package/dist/gml.js.map +1 -1
  54. package/dist/graph-io.js +302 -399
  55. package/dist/graph-io.js.map +1 -1
  56. package/dist/graphml.js +1 -1
  57. package/dist/json.js +1 -1
  58. package/dist/neo4j.js +6 -4
  59. package/dist/neo4j.js.map +1 -1
  60. package/dist/obo.js +1 -1
  61. package/dist/pajek.js +1 -1
  62. package/dist/src/common/cell-budget.d.ts +84 -0
  63. package/dist/src/common/cell-budget.d.ts.map +1 -0
  64. package/dist/src/common/cell-budget.js +138 -0
  65. package/dist/src/common/cell-budget.js.map +1 -0
  66. package/dist/src/common/input.d.ts +10 -0
  67. package/dist/src/common/input.d.ts.map +1 -1
  68. package/dist/src/common/input.js +39 -0
  69. package/dist/src/common/input.js.map +1 -1
  70. package/dist/src/common/json-elements.d.ts +286 -0
  71. package/dist/src/common/json-elements.d.ts.map +1 -0
  72. package/dist/src/common/json-elements.js +926 -0
  73. package/dist/src/common/json-elements.js.map +1 -0
  74. package/dist/src/common/options.d.ts +6 -0
  75. package/dist/src/common/options.d.ts.map +1 -1
  76. package/dist/src/common/options.js +1 -1
  77. package/dist/src/common/options.js.map +1 -1
  78. package/dist/src/common/xml.d.ts +37 -3
  79. package/dist/src/common/xml.d.ts.map +1 -1
  80. package/dist/src/common/xml.js +86 -6
  81. package/dist/src/common/xml.js.map +1 -1
  82. package/dist/src/common/zip.d.ts +92 -0
  83. package/dist/src/common/zip.d.ts.map +1 -0
  84. package/dist/src/common/zip.js +399 -0
  85. package/dist/src/common/zip.js.map +1 -0
  86. package/dist/src/formats/cx/importer.d.ts +133 -0
  87. package/dist/src/formats/cx/importer.d.ts.map +1 -0
  88. package/dist/src/formats/cx/importer.js +2220 -0
  89. package/dist/src/formats/cx/importer.js.map +1 -0
  90. package/dist/src/formats/cx/index.d.ts +7 -0
  91. package/dist/src/formats/cx/index.d.ts.map +1 -0
  92. package/dist/src/formats/cx/index.js +7 -0
  93. package/dist/src/formats/cx/index.js.map +1 -0
  94. package/dist/src/formats/cx2/exporter.d.ts +59 -0
  95. package/dist/src/formats/cx2/exporter.d.ts.map +1 -0
  96. package/dist/src/formats/cx2/exporter.js +864 -0
  97. package/dist/src/formats/cx2/exporter.js.map +1 -0
  98. package/dist/src/formats/cx2/importer.d.ts +169 -0
  99. package/dist/src/formats/cx2/importer.d.ts.map +1 -0
  100. package/dist/src/formats/cx2/importer.js +1652 -0
  101. package/dist/src/formats/cx2/importer.js.map +1 -0
  102. package/dist/src/formats/cx2/index.d.ts +7 -0
  103. package/dist/src/formats/cx2/index.d.ts.map +1 -0
  104. package/dist/src/formats/cx2/index.js +7 -0
  105. package/dist/src/formats/cx2/index.js.map +1 -0
  106. package/dist/src/formats/cys/constants.d.ts +68 -0
  107. package/dist/src/formats/cys/constants.d.ts.map +1 -0
  108. package/dist/src/formats/cys/constants.js +76 -0
  109. package/dist/src/formats/cys/constants.js.map +1 -0
  110. package/dist/src/formats/cys/importer.d.ts +38 -0
  111. package/dist/src/formats/cys/importer.d.ts.map +1 -0
  112. package/dist/src/formats/cys/importer.js +830 -0
  113. package/dist/src/formats/cys/importer.js.map +1 -0
  114. package/dist/src/formats/cys/index.d.ts +7 -0
  115. package/dist/src/formats/cys/index.d.ts.map +1 -0
  116. package/dist/src/formats/cys/index.js +7 -0
  117. package/dist/src/formats/cys/index.js.map +1 -0
  118. package/dist/src/formats/cys/session.d.ts +132 -0
  119. package/dist/src/formats/cys/session.d.ts.map +1 -0
  120. package/dist/src/formats/cys/session.js +315 -0
  121. package/dist/src/formats/cys/session.js.map +1 -0
  122. package/dist/src/formats/cys/tables.d.ts +90 -0
  123. package/dist/src/formats/cys/tables.d.ts.map +1 -0
  124. package/dist/src/formats/cys/tables.js +293 -0
  125. package/dist/src/formats/cys/tables.js.map +1 -0
  126. package/dist/src/formats/dot/exporter.d.ts +2 -0
  127. package/dist/src/formats/dot/exporter.d.ts.map +1 -1
  128. package/dist/src/formats/dot/exporter.js +12 -0
  129. package/dist/src/formats/dot/exporter.js.map +1 -1
  130. package/dist/src/formats/dot/importer.js +6 -2
  131. package/dist/src/formats/dot/importer.js.map +1 -1
  132. package/dist/src/formats/gexf/exporter.d.ts +2 -0
  133. package/dist/src/formats/gexf/exporter.d.ts.map +1 -1
  134. package/dist/src/formats/gexf/exporter.js +6 -0
  135. package/dist/src/formats/gexf/exporter.js.map +1 -1
  136. package/dist/src/formats/gexf/importer.d.ts +0 -2
  137. package/dist/src/formats/gexf/importer.d.ts.map +1 -1
  138. package/dist/src/formats/gexf/importer.js +1 -3
  139. package/dist/src/formats/gexf/importer.js.map +1 -1
  140. package/dist/src/formats/gexf/index.d.ts +1 -1
  141. package/dist/src/formats/gexf/index.js +2 -2
  142. package/dist/src/formats/gexf/index.js.map +1 -1
  143. package/dist/src/formats/gml/exporter.d.ts +0 -8
  144. package/dist/src/formats/gml/exporter.d.ts.map +1 -1
  145. package/dist/src/formats/gml/exporter.js +8 -18
  146. package/dist/src/formats/gml/exporter.js.map +1 -1
  147. package/dist/src/formats/json/importer.d.ts.map +1 -1
  148. package/dist/src/formats/json/importer.js +6 -104
  149. package/dist/src/formats/json/importer.js.map +1 -1
  150. package/dist/src/formats/xgmml/columns.d.ts +152 -0
  151. package/dist/src/formats/xgmml/columns.d.ts.map +1 -0
  152. package/dist/src/formats/xgmml/columns.js +593 -0
  153. package/dist/src/formats/xgmml/columns.js.map +1 -0
  154. package/dist/src/formats/xgmml/constants.d.ts +196 -0
  155. package/dist/src/formats/xgmml/constants.d.ts.map +1 -0
  156. package/dist/src/formats/xgmml/constants.js +197 -0
  157. package/dist/src/formats/xgmml/constants.js.map +1 -0
  158. package/dist/src/formats/xgmml/document.d.ts +361 -0
  159. package/dist/src/formats/xgmml/document.d.ts.map +1 -0
  160. package/dist/src/formats/xgmml/document.js +695 -0
  161. package/dist/src/formats/xgmml/document.js.map +1 -0
  162. package/dist/src/formats/xgmml/emit.d.ts +341 -0
  163. package/dist/src/formats/xgmml/emit.d.ts.map +1 -0
  164. package/dist/src/formats/xgmml/emit.js +1275 -0
  165. package/dist/src/formats/xgmml/emit.js.map +1 -0
  166. package/dist/src/formats/xgmml/exporter.d.ts +24 -0
  167. package/dist/src/formats/xgmml/exporter.d.ts.map +1 -0
  168. package/dist/src/formats/xgmml/exporter.js +999 -0
  169. package/dist/src/formats/xgmml/exporter.js.map +1 -0
  170. package/dist/src/formats/xgmml/importer.d.ts +58 -0
  171. package/dist/src/formats/xgmml/importer.d.ts.map +1 -0
  172. package/dist/src/formats/xgmml/importer.js +360 -0
  173. package/dist/src/formats/xgmml/importer.js.map +1 -0
  174. package/dist/src/formats/xgmml/index.d.ts +8 -0
  175. package/dist/src/formats/xgmml/index.d.ts.map +1 -0
  176. package/dist/src/formats/xgmml/index.js +8 -0
  177. package/dist/src/formats/xgmml/index.js.map +1 -0
  178. package/dist/src/formats/xgmml/values.d.ts +60 -0
  179. package/dist/src/formats/xgmml/values.d.ts.map +1 -0
  180. package/dist/src/formats/xgmml/values.js +148 -0
  181. package/dist/src/formats/xgmml/values.js.map +1 -0
  182. package/dist/src/index.d.ts +4 -0
  183. package/dist/src/index.d.ts.map +1 -1
  184. package/dist/src/index.js +4 -0
  185. package/dist/src/index.js.map +1 -1
  186. package/dist/src/registry.d.ts +7 -0
  187. package/dist/src/registry.d.ts.map +1 -1
  188. package/dist/src/registry.js +30 -10
  189. package/dist/src/registry.js.map +1 -1
  190. package/dist/src/sniff.d.ts +1 -1
  191. package/dist/src/sniff.d.ts.map +1 -1
  192. package/dist/src/sniff.js +4 -0
  193. package/dist/src/sniff.js.map +1 -1
  194. package/dist/xgmml.d.ts +1 -0
  195. package/dist/xgmml.js +9 -0
  196. package/dist/xgmml.js.map +1 -0
  197. package/package.json +25 -2
  198. package/src/common/cell-budget.ts +170 -0
  199. package/src/common/input.ts +40 -0
  200. package/src/common/json-elements.ts +1147 -0
  201. package/src/common/options.ts +1 -1
  202. package/src/common/xml.ts +127 -6
  203. package/src/common/zip.ts +472 -0
  204. package/src/formats/cx/importer.ts +2733 -0
  205. package/src/formats/cx/index.ts +7 -0
  206. package/src/formats/cx2/exporter.ts +1036 -0
  207. package/src/formats/cx2/importer.ts +2187 -0
  208. package/src/formats/cx2/index.ts +7 -0
  209. package/src/formats/cys/constants.ts +99 -0
  210. package/src/formats/cys/importer.ts +1100 -0
  211. package/src/formats/cys/index.ts +7 -0
  212. package/src/formats/cys/session.ts +428 -0
  213. package/src/formats/cys/tables.ts +400 -0
  214. package/src/formats/dot/exporter.ts +17 -0
  215. package/src/formats/dot/importer.ts +6 -2
  216. package/src/formats/gexf/exporter.ts +11 -0
  217. package/src/formats/gexf/importer.ts +1 -2
  218. package/src/formats/gexf/index.ts +1 -1
  219. package/src/formats/gml/exporter.ts +8 -19
  220. package/src/formats/json/importer.ts +6 -105
  221. package/src/formats/xgmml/columns.ts +747 -0
  222. package/src/formats/xgmml/constants.ts +265 -0
  223. package/src/formats/xgmml/document.ts +975 -0
  224. package/src/formats/xgmml/emit.ts +1563 -0
  225. package/src/formats/xgmml/exporter.ts +1215 -0
  226. package/src/formats/xgmml/importer.ts +491 -0
  227. package/src/formats/xgmml/index.ts +8 -0
  228. package/src/formats/xgmml/values.ts +183 -0
  229. package/src/index.ts +19 -0
  230. package/src/registry.ts +46 -15
  231. package/src/sniff.ts +18 -1
  232. package/dist/chunks/escape-D-gZWO26.js.map +0 -1
  233. package/dist/chunks/importer-Br_QeAeE.js.map +0 -1
  234. package/dist/chunks/importer-Du5crN9l.js.map +0 -1
  235. package/dist/chunks/writer-GAdltGmC.js.map +0 -1
@@ -0,0 +1,170 @@
1
+ /**
2
+ * A memory guard for the builder importGraph() fills. graph-format stores every attribute as a dense
3
+ * column, one slot per node (or edge) whether or not that element has a value, so a file whose nodes
4
+ * each carry a differently named attribute holds n values but allocates n x n slots: a few hundred
5
+ * kilobytes of input can need gigabytes. The guard counts the slots that hold no value and stops the
6
+ * import once they pass a limit. A dense file has almost no empty slots, so it is never stopped
7
+ * however large it is.
8
+ */
9
+
10
+ import {
11
+ type ColumnDecl,
12
+ type ColumnHandle,
13
+ GraphBuilder,
14
+ type GraphBuilderOptions,
15
+ GraphFormatError,
16
+ type NodeId,
17
+ } from "@graphty/graph-format";
18
+
19
+ import { describe } from "./options.js";
20
+ import { ImportReportBuilder } from "./report.js";
21
+
22
+ /** The issue code of an import stopped for allocating too many empty attribute slots. */
23
+ export const TOO_MANY_EMPTY_CELLS_CODE = "E_TOO_MANY_EMPTY_CELLS";
24
+
25
+ /** The default limit: 2^24 empty slots, about 130 MB of f64 columns. */
26
+ const DEFAULT_MAX_EMPTY_CELLS = 2 ** 24;
27
+
28
+ /**
29
+ * Resolve the maxEmptyCells option.
30
+ * @param value - the caller's value
31
+ * @returns a non-negative integer or Infinity
32
+ * @throws GraphFormatError E_UNSUPPORTED for anything else
33
+ */
34
+ export function maxEmptyCellsOption(value: unknown): number {
35
+ if (value === undefined) {
36
+ return DEFAULT_MAX_EMPTY_CELLS;
37
+ }
38
+ if (typeof value === "number" && value >= 0 && (Number.isInteger(value) || value === Infinity)) {
39
+ return value;
40
+ }
41
+ throw new GraphFormatError(
42
+ "E_UNSUPPORTED",
43
+ `option maxEmptyCells: ${describe(value)} is not a non-negative integer or Infinity`,
44
+ { option: "maxEmptyCells", found: value },
45
+ );
46
+ }
47
+
48
+ /** A GraphBuilder that throws an ImportError once its attribute columns hold too many empty slots. */
49
+ export class CellBudgetBuilder extends GraphBuilder {
50
+ private readonly nodeColumns = new Set<number>();
51
+ private readonly edgeColumns = new Set<number>();
52
+ private values = 0;
53
+
54
+ /**
55
+ * Create a builder with a limit.
56
+ * @param options - the builder options
57
+ * @param format - the format being read, for the error's report
58
+ * @param maxEmptyCells - the most empty slots allowed
59
+ */
60
+ constructor(
61
+ options: GraphBuilderOptions,
62
+ private readonly format: string,
63
+ private readonly maxEmptyCells: number,
64
+ ) {
65
+ super(options);
66
+ }
67
+
68
+ /**
69
+ * Add a node, then check the limit (its row adds a slot to every node column).
70
+ * @param id - the node id
71
+ * @returns the node index
72
+ */
73
+ override addNode(id: NodeId): number {
74
+ const index = super.addNode(id);
75
+ this.checkBudget();
76
+ return index;
77
+ }
78
+
79
+ /**
80
+ * Add an edge, then check the limit (its row adds a slot to every edge column).
81
+ * @param source - source id
82
+ * @param target - target id
83
+ * @param weight - the weight
84
+ * @returns the edge index
85
+ */
86
+ override addEdge(source: NodeId, target: NodeId, weight?: number): number {
87
+ const edge = super.addEdge(source, target, weight);
88
+ this.checkBudget();
89
+ return edge;
90
+ }
91
+
92
+ /**
93
+ * Declare a node column, then check the limit.
94
+ * @param decl - the declaration
95
+ * @returns the column handle
96
+ */
97
+ override declareNodeColumn(decl: ColumnDecl): ColumnHandle {
98
+ const handle = super.declareNodeColumn(decl);
99
+ this.nodeColumns.add(handle);
100
+ this.checkBudget();
101
+ return handle;
102
+ }
103
+
104
+ /**
105
+ * Declare an edge column, then check the limit.
106
+ * @param decl - the declaration
107
+ * @returns the column handle
108
+ */
109
+ override declareEdgeColumn(decl: ColumnDecl): ColumnHandle {
110
+ const handle = super.declareEdgeColumn(decl);
111
+ this.edgeColumns.add(handle);
112
+ this.checkBudget();
113
+ return handle;
114
+ }
115
+
116
+ /**
117
+ * Set a node cell (a new name declares a column), then check the limit.
118
+ * @param column - the handle or name
119
+ * @param index - the node index
120
+ * @param value - the value
121
+ */
122
+ override setNodeValue(column: ColumnHandle | string, index: number, value: unknown): void {
123
+ super.setNodeValue(column, index, value);
124
+ this.nodeColumns.add(typeof column === "string" ? this.nodeColumn(column) : column);
125
+ this.count(value);
126
+ }
127
+
128
+ /**
129
+ * Set an edge cell (a new name declares a column), then check the limit.
130
+ * @param column - the handle or name
131
+ * @param edge - the edge index
132
+ * @param value - the value
133
+ */
134
+ override setEdgeValue(column: ColumnHandle | string, edge: number, value: unknown): void {
135
+ super.setEdgeValue(column, edge, value);
136
+ this.edgeColumns.add(typeof column === "string" ? this.edgeColumn(column) : column);
137
+ this.count(value);
138
+ }
139
+
140
+ /**
141
+ * Count a written value and check the budget.
142
+ * @param value - the value; null and undefined unset a slot and do not count
143
+ */
144
+ private count(value: unknown): void {
145
+ if (value !== null && value !== undefined) {
146
+ this.values++;
147
+ }
148
+ this.checkBudget();
149
+ }
150
+
151
+ /**
152
+ * Throw when the columns' slots minus the values written pass the limit.
153
+ * @throws ImportError E_TOO_MANY_EMPTY_CELLS
154
+ */
155
+ private checkBudget(): void {
156
+ const slots = this.nodeColumns.size * this.nodeBound + this.edgeColumns.size * this.edgeBound;
157
+ const empty = slots - this.values;
158
+ if (empty > this.maxEmptyCells) {
159
+ new ImportReportBuilder(this.format, Infinity).fail(
160
+ TOO_MANY_EMPTY_CELLS_CODE,
161
+ `the attributes are too sparse: ${this.nodeColumns.size} node and ${this.edgeColumns.size} edge ` +
162
+ `attribute column(s) over ${this.nodeBound} node(s) and ${this.edgeBound} edge(s) would ` +
163
+ `allocate more than ${this.maxEmptyCells} slots that hold no value; pass a larger ` +
164
+ `maxEmptyCells (or Infinity) to read the file anyway`,
165
+ undefined,
166
+ { emptyCells: empty, maxEmptyCells: this.maxEmptyCells },
167
+ );
168
+ }
169
+ }
170
+ }
@@ -529,6 +529,46 @@ async function* streamChunks(
529
529
  }
530
530
  }
531
531
 
532
+ /**
533
+ * Read the whole input as bytes, for a binary format (a zip): nothing is decoded. The signal is
534
+ * checked before every chunk and progress reported after it; a stream is cancelled when the read
535
+ * stops early.
536
+ * @param input - the input
537
+ * @param options - cancellation and progress (the encoding is ignored)
538
+ * @returns the bytes, or null when the input is text (a string, or a chunk that is a string),
539
+ * which a binary format cannot read
540
+ */
541
+ export async function readBytes(input: ImportInput, options: ReadOptions = {}): Promise<Uint8Array | null> {
542
+ const signal = options.signal ?? null;
543
+ throwIfAborted(signal);
544
+ if (typeof input === "string") {
545
+ return null;
546
+ }
547
+ if (input instanceof Uint8Array) {
548
+ options.onProgress?.(input.byteLength, input.byteLength);
549
+ return input;
550
+ }
551
+ const parts: Uint8Array[] = [];
552
+ let done = 0;
553
+ for await (const chunk of isReadableStream(input) ? streamChunks(input, signal) : input) {
554
+ throwIfAborted(signal);
555
+ if (typeof chunk === "string") {
556
+ return null;
557
+ }
558
+ if (!(chunk instanceof Uint8Array)) {
559
+ throw new GraphFormatError("E_UNSUPPORTED", "an input chunk must be a string or a Uint8Array", {
560
+ reason: "chunk type",
561
+ found: typeof chunk,
562
+ });
563
+ }
564
+ parts.push(chunk);
565
+ done += chunk.byteLength;
566
+ options.onProgress?.(done);
567
+ }
568
+ options.onProgress?.(done, done);
569
+ return parts.length === 0 ? new Uint8Array(0) : concatBytes(parts);
570
+ }
571
+
532
572
  /**
533
573
  * Read the whole input as one string (the GML / DOT / JSON path, design section 8.4).
534
574
  * @param input - the input