@loaders.gl/graphs 4.5.3 → 5.0.0-alpha.10

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 (77) hide show
  1. package/LICENSE +14 -3
  2. package/README.md +122 -10
  3. package/dist/dot-loader-types.d.ts +40 -3
  4. package/dist/dot-loader-types.d.ts.map +1 -1
  5. package/dist/dot-loader-types.js +8 -2
  6. package/dist/dot-loader-types.js.map +1 -1
  7. package/dist/dot-loader.cjs +1449 -108
  8. package/dist/dot-loader.cjs.map +3 -4
  9. package/dist/dot-loader.d.ts +11 -6
  10. package/dist/dot-loader.d.ts.map +1 -1
  11. package/dist/dot-loader.js +3 -3
  12. package/dist/dot-loader.js.map +1 -1
  13. package/dist/dot-types.d.ts +6 -1
  14. package/dist/dot-types.d.ts.map +1 -1
  15. package/dist/gexf-loader-types.d.ts +53 -0
  16. package/dist/gexf-loader-types.d.ts.map +1 -0
  17. package/dist/gexf-loader-types.js +26 -0
  18. package/dist/gexf-loader-types.js.map +1 -0
  19. package/dist/gexf-loader.cjs +1304 -0
  20. package/dist/gexf-loader.cjs.map +6 -0
  21. package/dist/gexf-loader.d.ts +24 -0
  22. package/dist/gexf-loader.d.ts.map +1 -0
  23. package/dist/gexf-loader.js +13 -0
  24. package/dist/gexf-loader.js.map +1 -0
  25. package/dist/gexf-types.d.ts +16 -0
  26. package/dist/gexf-types.d.ts.map +1 -0
  27. package/dist/gexf-types.js +5 -0
  28. package/dist/gexf-types.js.map +1 -0
  29. package/dist/graph-types.d.ts +28 -0
  30. package/dist/graph-types.d.ts.map +1 -1
  31. package/dist/graphml-loader-types.d.ts +39 -3
  32. package/dist/graphml-loader-types.d.ts.map +1 -1
  33. package/dist/graphml-loader-types.js +8 -2
  34. package/dist/graphml-loader-types.js.map +1 -1
  35. package/dist/graphml-loader.cjs +1006 -61
  36. package/dist/graphml-loader.cjs.map +3 -4
  37. package/dist/graphml-loader.d.ts +11 -6
  38. package/dist/graphml-loader.d.ts.map +1 -1
  39. package/dist/graphml-loader.js +3 -3
  40. package/dist/graphml-loader.js.map +1 -1
  41. package/dist/index.cjs +1452 -470
  42. package/dist/index.cjs.map +3 -4
  43. package/dist/index.d.ts +9 -2
  44. package/dist/index.d.ts.map +1 -1
  45. package/dist/index.js +3 -2
  46. package/dist/index.js.map +1 -1
  47. package/dist/lib/build-graph-tables.d.ts +4 -0
  48. package/dist/lib/build-graph-tables.d.ts.map +1 -0
  49. package/dist/lib/build-graph-tables.js +143 -0
  50. package/dist/lib/build-graph-tables.js.map +1 -0
  51. package/dist/lib/parse-dot.d.ts +3 -1
  52. package/dist/lib/parse-dot.d.ts.map +1 -1
  53. package/dist/lib/parse-dot.js +41 -24
  54. package/dist/lib/parse-dot.js.map +1 -1
  55. package/dist/lib/parse-gexf.d.ts +5 -0
  56. package/dist/lib/parse-gexf.d.ts.map +1 -0
  57. package/dist/lib/parse-gexf.js +380 -0
  58. package/dist/lib/parse-gexf.js.map +1 -0
  59. package/dist/lib/parse-graphml.d.ts +2 -1
  60. package/dist/lib/parse-graphml.d.ts.map +1 -1
  61. package/dist/lib/parse-graphml.js +50 -27
  62. package/dist/lib/parse-graphml.js.map +1 -1
  63. package/package.json +15 -6
  64. package/src/dot-loader-types.ts +21 -4
  65. package/src/dot-loader.ts +7 -4
  66. package/src/dot-types.ts +7 -1
  67. package/src/gexf-loader-types.ts +41 -0
  68. package/src/gexf-loader.ts +17 -0
  69. package/src/gexf-types.ts +21 -0
  70. package/src/graph-types.ts +35 -0
  71. package/src/graphml-loader-types.ts +20 -4
  72. package/src/graphml-loader.ts +7 -4
  73. package/src/index.ts +11 -2
  74. package/src/lib/build-graph-tables.ts +208 -0
  75. package/src/lib/parse-dot.ts +47 -24
  76. package/src/lib/parse-gexf.ts +388 -0
  77. package/src/lib/parse-graphml.ts +86 -34
@@ -1,8 +1,18 @@
1
1
  "use strict";
2
+ var __create = Object.create;
2
3
  var __defProp = Object.defineProperty;
3
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
5
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __esm = (fn, res, err) => function __init() {
9
+ if (err) throw err[0];
10
+ try {
11
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
12
+ } catch (e) {
13
+ throw err = [e], e;
14
+ }
15
+ };
6
16
  var __export = (target, all) => {
7
17
  for (var name in all)
8
18
  __defProp(target, name, { get: all[name], enumerable: true });
@@ -13,51 +23,1372 @@ var __copyProps = (to, from, except, desc) => {
13
23
  if (!__hasOwnProp.call(to, key) && key !== except)
14
24
  __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
25
  }
16
- return to;
17
- };
18
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
26
+ return to;
27
+ };
28
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
29
+ // If the importer is in node compatibility mode or this is not an ESM
30
+ // file that has been converted to a CommonJS file using a Babel-
31
+ // compatible transform (i.e. "__esModule" has not been set), then set
32
+ // "default" to the CommonJS "module.exports" for node compatibility.
33
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
34
+ mod
35
+ ));
36
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
37
+
38
+ // src/dot-loader-types.ts
39
+ async function preload() {
40
+ const { DOTLoaderWithParser: DOTLoaderWithParser3 } = await Promise.resolve().then(() => (init_dot_loader(), dot_loader_exports));
41
+ return DOTLoaderWithParser3;
42
+ }
43
+ var VERSION, DOTLoader;
44
+ var init_dot_loader_types = __esm({
45
+ "src/dot-loader-types.ts"() {
46
+ "use strict";
47
+ VERSION = typeof __VERSION__ !== "undefined" ? __VERSION__ : "latest";
48
+ DOTLoader = {
49
+ name: "DOT",
50
+ id: "dot",
51
+ module: "graphs",
52
+ version: VERSION,
53
+ extensions: ["dot", "gv"],
54
+ mimeTypes: ["text/vnd.graphviz", "text/x-graphviz", "application/vnd.graphviz"],
55
+ text: true,
56
+ worker: false,
57
+ dataType: null,
58
+ batchType: null,
59
+ options: { dot: { shape: "arrow-table" } },
60
+ preload
61
+ };
62
+ }
63
+ });
64
+
65
+ // ../schema-utils/src/lib/schema/convert-arrow-schema.ts
66
+ function convertArrowToSchema(arrowSchema) {
67
+ return serializeArrowSchema(arrowSchema);
68
+ }
69
+ function serializeArrowSchema(arrowSchema) {
70
+ return {
71
+ fields: arrowSchema.fields.map((arrowField) => serializeArrowField(arrowField)),
72
+ metadata: serializeArrowMetadata(arrowSchema.metadata)
73
+ };
74
+ }
75
+ function serializeArrowMetadata(arrowMetadata) {
76
+ return Object.fromEntries(arrowMetadata);
77
+ }
78
+ function serializeArrowField(field) {
79
+ return {
80
+ name: field.name,
81
+ type: serializeArrowType(field.type),
82
+ nullable: field.nullable,
83
+ metadata: serializeArrowMetadata(field.metadata)
84
+ };
85
+ }
86
+ function serializeArrowType(arrowType) {
87
+ if (isArrowViewType(arrowType, "BinaryView")) {
88
+ return "binary-view";
89
+ }
90
+ if (isArrowViewType(arrowType, "Utf8View")) {
91
+ return "utf8-view";
92
+ }
93
+ if (isOptionalArrowType(arrowType, "LargeList")) {
94
+ const largeListType = arrowType;
95
+ return {
96
+ type: "large-list",
97
+ children: [serializeArrowField(largeListType.valueField)]
98
+ };
99
+ }
100
+ switch (arrowType.constructor) {
101
+ case arrow.Null:
102
+ return "null";
103
+ case arrow.Binary:
104
+ return "binary";
105
+ case arrow.FixedSizeBinary:
106
+ return {
107
+ type: "fixed-size-binary",
108
+ byteWidth: arrowType.byteWidth
109
+ };
110
+ case arrow.Bool:
111
+ return "bool";
112
+ case arrow.Int:
113
+ const intType = arrowType;
114
+ return `${intType.isSigned ? "" : "u"}int${intType.bitWidth}`;
115
+ case arrow.Int8:
116
+ return "int8";
117
+ case arrow.Int16:
118
+ return "int16";
119
+ case arrow.Int32:
120
+ return "int32";
121
+ case arrow.Int64:
122
+ return "int64";
123
+ case arrow.Uint8:
124
+ return "uint8";
125
+ case arrow.Uint16:
126
+ return "uint16";
127
+ case arrow.Uint32:
128
+ return "uint32";
129
+ case arrow.Uint64:
130
+ return "uint64";
131
+ case arrow.Float:
132
+ const precision = arrowType.precision;
133
+ switch (precision) {
134
+ case arrow.Precision.HALF:
135
+ return "float16";
136
+ case arrow.Precision.SINGLE:
137
+ return "float32";
138
+ case arrow.Precision.DOUBLE:
139
+ return "float64";
140
+ default:
141
+ return "float16";
142
+ }
143
+ case arrow.Float16:
144
+ return "float16";
145
+ case arrow.Float32:
146
+ return "float32";
147
+ case arrow.Float64:
148
+ return "float64";
149
+ case arrow.Utf8:
150
+ return "utf8";
151
+ case arrow.Decimal:
152
+ const decimal = arrowType;
153
+ return {
154
+ type: "decimal",
155
+ bitWidth: decimal.bitWidth,
156
+ precision: decimal.precision,
157
+ scale: decimal.scale
158
+ };
159
+ case arrow.Date_:
160
+ const dateUnit = arrowType.unit;
161
+ return dateUnit === arrow.DateUnit.DAY ? "date-day" : "date-millisecond";
162
+ case arrow.DateDay:
163
+ return "date-day";
164
+ case arrow.DateMillisecond:
165
+ return "date-millisecond";
166
+ case arrow.Time:
167
+ const timeUnit = arrowType.unit;
168
+ switch (timeUnit) {
169
+ case arrow.TimeUnit.SECOND:
170
+ return "time-second";
171
+ case arrow.TimeUnit.MILLISECOND:
172
+ return "time-millisecond";
173
+ case arrow.TimeUnit.MICROSECOND:
174
+ return "time-microsecond";
175
+ case arrow.TimeUnit.NANOSECOND:
176
+ return "time-nanosecond";
177
+ default:
178
+ return "time-second";
179
+ }
180
+ case arrow.TimeMillisecond:
181
+ return "time-millisecond";
182
+ case arrow.TimeSecond:
183
+ return "time-second";
184
+ case arrow.TimeMicrosecond:
185
+ return "time-microsecond";
186
+ case arrow.TimeNanosecond:
187
+ return "time-nanosecond";
188
+ case arrow.Timestamp:
189
+ const timeStampUnit = arrowType.unit;
190
+ switch (timeStampUnit) {
191
+ case arrow.TimeUnit.SECOND:
192
+ return "timestamp-second";
193
+ case arrow.TimeUnit.MILLISECOND:
194
+ return "timestamp-millisecond";
195
+ case arrow.TimeUnit.MICROSECOND:
196
+ return "timestamp-microsecond";
197
+ case arrow.TimeUnit.NANOSECOND:
198
+ return "timestamp-nanosecond";
199
+ default:
200
+ return "timestamp-second";
201
+ }
202
+ case arrow.TimestampSecond:
203
+ return "timestamp-second";
204
+ case arrow.TimestampMillisecond:
205
+ return "timestamp-millisecond";
206
+ case arrow.TimestampMicrosecond:
207
+ return "timestamp-microsecond";
208
+ case arrow.TimestampNanosecond:
209
+ return "timestamp-nanosecond";
210
+ case arrow.Interval:
211
+ const intervalUnit = arrowType.unit;
212
+ switch (intervalUnit) {
213
+ case arrow.IntervalUnit.DAY_TIME:
214
+ return "interval-daytime";
215
+ case arrow.IntervalUnit.YEAR_MONTH:
216
+ return "interval-yearmonth";
217
+ default:
218
+ return "interval-daytime";
219
+ }
220
+ case arrow.IntervalDayTime:
221
+ return "interval-daytime";
222
+ case arrow.IntervalYearMonth:
223
+ return "interval-yearmonth";
224
+ case arrow.Map_:
225
+ const mapType = arrowType;
226
+ return {
227
+ type: "map",
228
+ keysSorted: mapType.keysSorted,
229
+ children: mapType.children.map((arrowField) => serializeArrowField(arrowField))
230
+ };
231
+ case arrow.List:
232
+ const listType = arrowType;
233
+ const listField = listType.valueField;
234
+ return {
235
+ type: "list",
236
+ children: [serializeArrowField(listField)]
237
+ };
238
+ case arrow.FixedSizeList:
239
+ const fixedSizeList = arrowType;
240
+ return {
241
+ type: "fixed-size-list",
242
+ listSize: fixedSizeList.listSize,
243
+ children: [serializeArrowField(fixedSizeList.children[0])]
244
+ };
245
+ case arrow.Struct:
246
+ const structType = arrowType;
247
+ return {
248
+ type: "struct",
249
+ children: structType.children.map((arrowField) => serializeArrowField(arrowField))
250
+ };
251
+ case arrow.SparseUnion:
252
+ case arrow.DenseUnion:
253
+ const unionType = arrowType;
254
+ return {
255
+ type: unionType instanceof arrow.DenseUnion ? "dense-union" : "sparse-union",
256
+ typeIds: unionType.typeIds,
257
+ children: unionType.children.map((arrowField) => serializeArrowField(arrowField)),
258
+ typeIdToChildIndex: { ...unionType.typeIdToChildIndex }
259
+ };
260
+ case arrow.Dictionary:
261
+ const dictionaryType = arrowType;
262
+ return {
263
+ type: "dictionary",
264
+ id: dictionaryType.id,
265
+ indices: serializeArrowDictionaryKeyType(dictionaryType.indices),
266
+ dictionary: serializeArrowType(dictionaryType.dictionary),
267
+ isOrdered: dictionaryType.isOrdered
268
+ };
269
+ default:
270
+ throw new Error(`arrow type not supported: ${arrowType.constructor.name}`);
271
+ }
272
+ }
273
+ function getOptionalArrowConstructor(typeName) {
274
+ return arrow[typeName];
275
+ }
276
+ function isArrowViewType(arrowType, viewTypeName) {
277
+ const constructor = getOptionalArrowConstructor(viewTypeName);
278
+ if (constructor && arrowType instanceof constructor) {
279
+ return true;
280
+ }
281
+ const guards = arrow.DataType;
282
+ const guard = viewTypeName === "BinaryView" ? guards.isBinaryView : guards.isUtf8View;
283
+ return Boolean(guard == null ? void 0 : guard(arrowType));
284
+ }
285
+ function isOptionalArrowType(arrowType, typeName) {
286
+ const constructor = getOptionalArrowConstructor(typeName);
287
+ return Boolean(constructor && arrowType instanceof constructor);
288
+ }
289
+ function serializeArrowDictionaryKeyType(arrowType) {
290
+ if (arrowType instanceof arrow.Int) {
291
+ const prefix = arrowType.isSigned ? "int" : "uint";
292
+ const keyType = `${prefix}${arrowType.bitWidth}`;
293
+ if (isSchemaDictionaryKeyType(keyType)) {
294
+ return keyType;
295
+ }
296
+ }
297
+ switch (arrowType.constructor) {
298
+ case arrow.Int8:
299
+ return "int8";
300
+ case arrow.Int16:
301
+ return "int16";
302
+ case arrow.Int32:
303
+ return "int32";
304
+ case arrow.Uint8:
305
+ return "uint8";
306
+ case arrow.Uint16:
307
+ return "uint16";
308
+ case arrow.Uint32:
309
+ return "uint32";
310
+ default:
311
+ throw new Error(`arrow dictionary index type not supported: ${arrowType.constructor.name}`);
312
+ }
313
+ }
314
+ function isSchemaDictionaryKeyType(keyType) {
315
+ return ["int8", "int16", "int32", "uint8", "uint16", "uint32"].includes(keyType);
316
+ }
317
+ var arrow;
318
+ var init_convert_arrow_schema = __esm({
319
+ "../schema-utils/src/lib/schema/convert-arrow-schema.ts"() {
320
+ "use strict";
321
+ arrow = __toESM(require("apache-arrow"), 1);
322
+ }
323
+ });
324
+
325
+ // ../schema-utils/src/index.ts
326
+ var init_src = __esm({
327
+ "../schema-utils/src/index.ts"() {
328
+ "use strict";
329
+ init_convert_arrow_schema();
330
+ }
331
+ });
332
+
333
+ // src/lib/build-graph-tables.ts
334
+ function buildGraphTables(nodes, edges, shape, declarations) {
335
+ if (shape === "plain-graph-data") {
336
+ return { shape, nodes: Array.from(nodes), edges: Array.from(edges) };
337
+ }
338
+ if (shape !== "arrow-table" && shape !== "object-row-table") {
339
+ throw new Error(`Unsupported graph shape: ${shape}`);
340
+ }
341
+ const nodeTable = buildGraphTable(nodes, false, shape, declarations == null ? void 0 : declarations.nodes);
342
+ const edgeTable = buildGraphTable(edges, true, shape, declarations == null ? void 0 : declarations.edges);
343
+ return {
344
+ shape: "tables",
345
+ tables: [
346
+ { name: "nodes", table: nodeTable },
347
+ { name: "edges", table: edgeTable }
348
+ ]
349
+ };
350
+ }
351
+ function buildGraphTable(records, isEdge, shape, declarations) {
352
+ const columnNames = isEdge ? ["id", "sourceId", "targetId", "directed", "label", "attributes"] : ["id", "label", "attributes"];
353
+ const columns = new Map(columnNames.map((name) => [name, []]));
354
+ for (const record of records) {
355
+ for (const name of columnNames) {
356
+ const value = record[name];
357
+ columns.get(name).push(
358
+ name === "id" || name === "sourceId" || name === "targetId" ? String(value) : value ?? null
359
+ );
360
+ }
361
+ }
362
+ if (shape === "object-row-table") {
363
+ return {
364
+ shape,
365
+ data: columns.get("id").map(
366
+ (_, index) => Object.fromEntries(columnNames.map((name) => [name, columns.get(name)[index]]))
367
+ )
368
+ };
369
+ }
370
+ const vectors = /* @__PURE__ */ Object.create(null);
371
+ for (const [name, values] of columns) {
372
+ const type = name === "attributes" ? inferAttributeType(values, declarations) : name === "directed" ? new import_apache_arrow.Bool() : new import_apache_arrow.Utf8();
373
+ vectors[name] = (0, import_apache_arrow.vectorFromArray)(
374
+ values.map((value) => normalizeValue(value, type)),
375
+ type
376
+ );
377
+ }
378
+ const data = new import_apache_arrow.Table(vectors);
379
+ return { shape, schema: convertArrowToSchema(data.schema), data };
380
+ }
381
+ function inferAttributeType(values, declarations) {
382
+ const names = new Set(declarations == null ? void 0 : declarations.keys());
383
+ for (const value of values) {
384
+ if (value && typeof value === "object") {
385
+ for (const name of Object.keys(value)) {
386
+ names.add(name);
387
+ }
388
+ }
389
+ }
390
+ return new import_apache_arrow.Struct(
391
+ Array.from(names, (name) => {
392
+ const fieldValues = values.map(
393
+ (value) => (value == null ? void 0 : value[name]) ?? null
394
+ );
395
+ return new import_apache_arrow.Field(name, inferValueType(fieldValues, declarations == null ? void 0 : declarations.get(name)), true);
396
+ })
397
+ );
398
+ }
399
+ function inferValueType(values, declaration) {
400
+ const present = values.filter((value) => value !== null && value !== void 0);
401
+ if (declaration && typeof declaration === "object") {
402
+ if (!present.every((value) => Array.isArray(value))) return new import_apache_arrow.Utf8();
403
+ return new import_apache_arrow.List(
404
+ new import_apache_arrow.Field(
405
+ "item",
406
+ inferValueType(
407
+ present.flatMap((value) => value),
408
+ declaration.list
409
+ ),
410
+ true
411
+ )
412
+ );
413
+ }
414
+ if (declaration) {
415
+ const declaredTypes = {
416
+ boolean: new import_apache_arrow.Bool(),
417
+ int: new import_apache_arrow.Int32(),
418
+ long: new import_apache_arrow.Int64(),
419
+ float: new import_apache_arrow.Float32(),
420
+ double: new import_apache_arrow.Float64(),
421
+ string: new import_apache_arrow.Utf8()
422
+ };
423
+ const valid = present.every((value) => {
424
+ switch (declaration) {
425
+ case "boolean":
426
+ return typeof value === "boolean";
427
+ case "int":
428
+ return typeof value === "number" && Number.isInteger(value) && value >= -2147483648 && value <= 2147483647;
429
+ case "long":
430
+ return typeof value === "bigint" && value >= -(2n ** 63n) && value < 2n ** 63n;
431
+ case "float":
432
+ case "double":
433
+ return typeof value === "number";
434
+ case "string":
435
+ return typeof value === "string";
436
+ }
437
+ });
438
+ return valid ? declaredTypes[declaration] : new import_apache_arrow.Utf8();
439
+ }
440
+ if (present.length && present.every((value) => typeof value === "boolean")) return new import_apache_arrow.Bool();
441
+ if (present.length && present.every((value) => typeof value === "number")) return new import_apache_arrow.Float64();
442
+ if (present.length && present.every((value) => Array.isArray(value))) {
443
+ return new import_apache_arrow.List(
444
+ new import_apache_arrow.Field("item", inferValueType(present.flatMap((value) => value)), true)
445
+ );
446
+ }
447
+ if (present.length && present.every((value) => typeof value === "object" && !Array.isArray(value))) {
448
+ return inferAttributeType(present);
449
+ }
450
+ return new import_apache_arrow.Utf8();
451
+ }
452
+ function normalizeValue(value, type) {
453
+ if (value === null || value === void 0) return null;
454
+ if (type instanceof import_apache_arrow.Struct) {
455
+ return Object.fromEntries(
456
+ type.children.map((field) => [
457
+ field.name,
458
+ normalizeValue(value[field.name], field.type)
459
+ ])
460
+ );
461
+ }
462
+ if (type instanceof import_apache_arrow.List)
463
+ return value.map((item) => normalizeValue(item, type.valueType));
464
+ if (type instanceof import_apache_arrow.Utf8 && typeof value !== "string") {
465
+ return typeof value === "object" ? JSON.stringify(value) : String(value);
466
+ }
467
+ return value;
468
+ }
469
+ var import_apache_arrow;
470
+ var init_build_graph_tables = __esm({
471
+ "src/lib/build-graph-tables.ts"() {
472
+ "use strict";
473
+ import_apache_arrow = require("apache-arrow");
474
+ init_src();
475
+ }
476
+ });
477
+
478
+ // src/lib/parse-dot.ts
479
+ function parseDOT(input, shape = "plain-graph-data") {
480
+ const parsed = parseDOTDocument(input);
481
+ return {
482
+ ...buildGraphTables(iterateNodes(parsed), iterateEdges(parsed), shape),
483
+ metadata: {
484
+ id: parsed.id,
485
+ directed: parsed.directed,
486
+ strict: parsed.strict,
487
+ attributes: { ...parsed.graphAttributes },
488
+ subgraphs: Array.from(parsed.subgraphs.values(), (subgraph) => ({
489
+ ...subgraph,
490
+ attributes: { ...subgraph.attributes }
491
+ }))
492
+ }
493
+ };
494
+ }
495
+ function* iterateNodes(parsed) {
496
+ for (const node of parsed.nodes.values()) {
497
+ yield {
498
+ id: node.id,
499
+ ...typeof node.attributes.label === "string" ? { label: node.attributes.label } : {},
500
+ attributes: {
501
+ ...node.attributes,
502
+ ...node.subgraphs.size ? { subgraphs: Array.from(node.subgraphs, (id) => describeSubgraph(id, parsed.subgraphs)) } : {}
503
+ }
504
+ };
505
+ }
506
+ }
507
+ function* iterateEdges(parsed) {
508
+ for (const edge of parsed.edges) {
509
+ yield {
510
+ id: edge.id,
511
+ sourceId: edge.sourceId,
512
+ targetId: edge.targetId,
513
+ directed: edge.directed,
514
+ ...typeof edge.attributes.label === "string" ? { label: edge.attributes.label } : {},
515
+ attributes: {
516
+ ...edge.attributes,
517
+ ...edge.subgraphs.length ? { subgraphs: edge.subgraphs.map((id) => describeSubgraph(id, parsed.subgraphs)) } : {}
518
+ }
519
+ };
520
+ }
521
+ }
522
+ function describeSubgraph(id, descriptors) {
523
+ const subgraph = descriptors.get(id);
524
+ return {
525
+ id,
526
+ attributes: { ...subgraph.attributes },
527
+ parentId: subgraph.parentId
528
+ };
529
+ }
530
+ function parseDOTDocument(input) {
531
+ const parser = new DOTParser(tokenize(input));
532
+ return parser.parse();
533
+ }
534
+ function tokenize(input) {
535
+ const tokens = [];
536
+ let index = 0;
537
+ while (index < input.length) {
538
+ const { token, nextIndex } = readNextToken(input, index);
539
+ if (nextIndex <= index) {
540
+ throw new Error(`Tokenizer did not advance at position ${index}.`);
541
+ }
542
+ if (token) {
543
+ tokens.push(token);
544
+ }
545
+ index = nextIndex;
546
+ }
547
+ return tokens;
548
+ }
549
+ function readNextToken(input, index) {
550
+ if (index >= input.length) {
551
+ return { token: null, nextIndex: input.length };
552
+ }
553
+ const character = input[index];
554
+ if (isWhitespace(character)) {
555
+ return { token: null, nextIndex: index + 1 };
556
+ }
557
+ const commentEnd = skipComment(input, index);
558
+ if (commentEnd !== null) {
559
+ return { token: null, nextIndex: commentEnd };
560
+ }
561
+ const arrowToken = readArrowToken(input, index);
562
+ if (arrowToken) {
563
+ return arrowToken;
564
+ }
565
+ const punctuation = readPunctuationToken(character);
566
+ if (punctuation) {
567
+ return { token: punctuation, nextIndex: index + 1 };
568
+ }
569
+ if (character === '"') {
570
+ const { value, nextIndex } = readQuotedString(input, index + 1);
571
+ return { token: { type: "string", value }, nextIndex };
572
+ }
573
+ if (character === "<") {
574
+ const { value, nextIndex } = readHtmlString(input, index + 1);
575
+ return { token: { type: "html", value }, nextIndex };
576
+ }
577
+ const identifier = readIdentifier(input, index);
578
+ if (identifier.value) {
579
+ return {
580
+ token: { type: "identifier", value: identifier.value },
581
+ nextIndex: identifier.nextIndex
582
+ };
583
+ }
584
+ throw new Error(`Unexpected token at position ${index}.`);
585
+ }
586
+ function skipComment(input, index) {
587
+ const character = input[index];
588
+ if (character === "/") {
589
+ const next = input[index + 1];
590
+ if (next === "/") {
591
+ return skipLineComment(input, index + 2);
592
+ }
593
+ if (next === "*") {
594
+ return skipBlockComment(input, index + 2);
595
+ }
596
+ return null;
597
+ }
598
+ if (character === "#") {
599
+ return skipLineComment(input, index + 1);
600
+ }
601
+ return null;
602
+ }
603
+ function skipLineComment(input, startIndex) {
604
+ let cursor = startIndex;
605
+ while (cursor < input.length && !isLineBreak(input[cursor])) {
606
+ cursor++;
607
+ }
608
+ return cursor;
609
+ }
610
+ function skipBlockComment(input, startIndex) {
611
+ let cursor = startIndex;
612
+ while (cursor < input.length) {
613
+ if (input[cursor] === "*" && input[cursor + 1] === "/") {
614
+ return cursor + 2;
615
+ }
616
+ cursor++;
617
+ }
618
+ throw new Error("Unterminated block comment in DOT source.");
619
+ }
620
+ function readArrowToken(input, index) {
621
+ const next = input[index + 1];
622
+ if (input[index] === "-" && next === "-") {
623
+ return { token: { type: "arrow", value: "--" }, nextIndex: index + 2 };
624
+ }
625
+ if (input[index] === "-" && next === ">") {
626
+ return { token: { type: "arrow", value: "->" }, nextIndex: index + 2 };
627
+ }
628
+ return null;
629
+ }
630
+ function readPunctuationToken(character) {
631
+ switch (character) {
632
+ case "{":
633
+ return { type: "lbrace", value: character };
634
+ case "}":
635
+ return { type: "rbrace", value: character };
636
+ case "[":
637
+ return { type: "lbrack", value: character };
638
+ case "]":
639
+ return { type: "rbrack", value: character };
640
+ case "=":
641
+ return { type: "equals", value: character };
642
+ case ",":
643
+ return { type: "comma", value: character };
644
+ case ";":
645
+ return { type: "semicolon", value: character };
646
+ default:
647
+ return null;
648
+ }
649
+ }
650
+ function readQuotedString(input, startIndex) {
651
+ let value = "";
652
+ let index = startIndex;
653
+ while (index < input.length) {
654
+ const character = input[index];
655
+ if (character === '"') {
656
+ return { value, nextIndex: index + 1 };
657
+ }
658
+ if (character === "\\") {
659
+ const escape = readEscapedCharacter(input, index + 1);
660
+ value += escape.value;
661
+ index = escape.nextIndex;
662
+ } else {
663
+ value += character;
664
+ index++;
665
+ }
666
+ }
667
+ throw new Error("Unterminated string literal in DOT source.");
668
+ }
669
+ function readEscapedCharacter(input, startIndex) {
670
+ const next = input[startIndex];
671
+ switch (next) {
672
+ case "\n":
673
+ return { value: "", nextIndex: startIndex + 1 };
674
+ case "\r":
675
+ return { value: "", nextIndex: startIndex + (input[startIndex + 1] === "\n" ? 2 : 1) };
676
+ case "n":
677
+ case "l":
678
+ case "L":
679
+ return { value: "\n", nextIndex: startIndex + 1 };
680
+ case "t":
681
+ return { value: " ", nextIndex: startIndex + 1 };
682
+ case "r":
683
+ return { value: "\r", nextIndex: startIndex + 1 };
684
+ case '"':
685
+ return { value: '"', nextIndex: startIndex + 1 };
686
+ case "\\":
687
+ return { value: "\\", nextIndex: startIndex + 1 };
688
+ default: {
689
+ if (typeof next === "undefined") {
690
+ throw new Error("Unterminated escape sequence in DOT source.");
691
+ }
692
+ return { value: `\\${next}`, nextIndex: startIndex + 1 };
693
+ }
694
+ }
695
+ }
696
+ function readHtmlString(input, startIndex) {
697
+ let value = "<";
698
+ let depth = 1;
699
+ let index = startIndex;
700
+ while (index < input.length) {
701
+ const character = input[index];
702
+ value += character;
703
+ if (character === "<") {
704
+ depth++;
705
+ } else if (character === ">") {
706
+ depth--;
707
+ if (depth === 0) {
708
+ return { value, nextIndex: index + 1 };
709
+ }
710
+ }
711
+ index++;
712
+ }
713
+ throw new Error("Unterminated HTML-like string literal in DOT source.");
714
+ }
715
+ function readIdentifier(input, startIndex) {
716
+ let index = startIndex;
717
+ let value = "";
718
+ while (index < input.length && !isIdentifierTerminator(input, index)) {
719
+ value += input[index];
720
+ index++;
721
+ }
722
+ if (value.includes(":")) {
723
+ throw new Error("DOT node ports are not supported; quote identifiers containing colons.");
724
+ }
725
+ return { value, nextIndex: index };
726
+ }
727
+ function isIdentifierTerminator(input, index) {
728
+ const character = input[index];
729
+ if (isWhitespace(character) || IDENTIFIER_TERMINATORS.has(character)) {
730
+ return true;
731
+ }
732
+ if (isArrowOperatorStart(input, index)) {
733
+ return true;
734
+ }
735
+ if (isCommentStart(input, index)) {
736
+ return true;
737
+ }
738
+ return false;
739
+ }
740
+ function isArrowOperatorStart(input, index) {
741
+ if (input[index] !== "-") {
742
+ return false;
743
+ }
744
+ const next = input[index + 1];
745
+ return next === "-" || next === ">";
746
+ }
747
+ function isCommentStart(input, index) {
748
+ if (input[index] !== "/") {
749
+ return false;
750
+ }
751
+ const next = input[index + 1];
752
+ return next === "/" || next === "*";
753
+ }
754
+ function isWhitespace(character) {
755
+ return character === " " || character === "\n" || character === "\r" || character === " " || character === "\f";
756
+ }
757
+ function isLineBreak(character) {
758
+ return character === "\n" || character === "\r";
759
+ }
760
+ function isKeyword(token, keyword) {
761
+ return token.type === "identifier" && token.value.toLowerCase() === keyword.toLowerCase();
762
+ }
763
+ function isGraphType(token) {
764
+ return isKeyword(token, "graph") || isKeyword(token, "digraph");
765
+ }
766
+ function isIdentifierLike(token) {
767
+ return token.type === "identifier" || token.type === "string" || token.type === "html";
768
+ }
769
+ function parseIdentifierValue(token) {
770
+ return token.value;
771
+ }
772
+ function parseAttributeValue(token) {
773
+ if (token.type === "string" || token.type === "html") {
774
+ return token.value;
775
+ }
776
+ if (token.type === "identifier") {
777
+ const numeric = Number(token.value);
778
+ if (!Number.isNaN(numeric)) {
779
+ return numeric;
780
+ }
781
+ return token.value;
782
+ }
783
+ throw new Error("Invalid attribute value in DOT input.");
784
+ }
785
+ function deriveEdgeId(attributes, sourceId, targetId, counter) {
786
+ const candidate = attributes.id ?? attributes.Id ?? attributes.ID;
787
+ if (typeof candidate === "string" || typeof candidate === "number") {
788
+ return String(candidate);
789
+ }
790
+ return `${String(sourceId)}-${String(targetId)}-${counter}`;
791
+ }
792
+ function deriveDirectedFlag(attributes, defaultDirected) {
793
+ const candidate = attributes.directed;
794
+ if (typeof candidate === "boolean") {
795
+ return candidate;
796
+ }
797
+ const directionAttribute = attributes.dir;
798
+ if (typeof directionAttribute === "string") {
799
+ const normalized = directionAttribute.toLowerCase();
800
+ if (normalized === "none") {
801
+ return false;
802
+ }
803
+ return true;
804
+ }
805
+ return defaultDirected;
806
+ }
807
+ var DOTParser, IDENTIFIER_TERMINATORS;
808
+ var init_parse_dot = __esm({
809
+ "src/lib/parse-dot.ts"() {
810
+ "use strict";
811
+ init_build_graph_tables();
812
+ DOTParser = class {
813
+ /** Tokens for DOT parsing. */
814
+ tokens;
815
+ /** Position for DOT parsing. */
816
+ position = 0;
817
+ /** Accumulated graph records and attributes. */
818
+ result = {
819
+ directed: false,
820
+ strict: false,
821
+ graphAttributes: /* @__PURE__ */ Object.create(null),
822
+ nodes: /* @__PURE__ */ new Map(),
823
+ edges: [],
824
+ subgraphs: /* @__PURE__ */ new Map()
825
+ };
826
+ /** Scopes for DOT parsing. */
827
+ scopes = [
828
+ {
829
+ nodeDefaults: /* @__PURE__ */ Object.create(null),
830
+ edgeDefaults: /* @__PURE__ */ Object.create(null),
831
+ graphAttributes: /* @__PURE__ */ Object.create(null)
832
+ }
833
+ ];
834
+ /** Subgraph counter for DOT parsing. */
835
+ subgraphCounter = 0;
836
+ /** Edge counter for DOT parsing. */
837
+ edgeCounter = 0;
838
+ /** Edge lookup used to coalesce parallel edges in strict graphs. */
839
+ strictEdges = /* @__PURE__ */ new Map();
840
+ /** Persistent attributes and defaults for reopened named subgraphs. */
841
+ subgraphScopes = /* @__PURE__ */ new Map();
842
+ /** Explicit names reserved so anonymous subgraph IDs cannot collide with them. */
843
+ namedSubgraphIds = /* @__PURE__ */ new Set();
844
+ /** Initializes the token stream. */
845
+ constructor(tokens) {
846
+ this.tokens = tokens;
847
+ for (let index = 0; index < tokens.length - 1; index++) {
848
+ if (isKeyword(tokens[index], "subgraph") && isIdentifierLike(tokens[index + 1])) {
849
+ this.namedSubgraphIds.add(tokens[index + 1].value);
850
+ }
851
+ }
852
+ }
853
+ /** Parses one complete DOT document. */
854
+ parse() {
855
+ this.parseGraph();
856
+ this.consumeOptionalSemicolon();
857
+ if (this.peek()) {
858
+ throw new Error("Unexpected content after DOT graph.");
859
+ }
860
+ return this.result;
861
+ }
862
+ /** Reads graph identity, declaration, and statements. */
863
+ parseGraph() {
864
+ const strictToken = this.peek();
865
+ if (strictToken && isKeyword(strictToken, "strict")) {
866
+ this.consume();
867
+ this.result.strict = true;
868
+ }
869
+ const typeToken = this.peek();
870
+ if (!typeToken || !isGraphType(typeToken)) {
871
+ throw new Error("DOT graph must start with graph or digraph keyword.");
872
+ }
873
+ this.consume();
874
+ this.result.directed = isKeyword(typeToken, "digraph");
875
+ const idToken = this.peek();
876
+ if (idToken && isIdentifierLike(idToken)) {
877
+ this.result.id = parseIdentifierValue(this.consume());
878
+ }
879
+ this.expect("lbrace");
880
+ while (!this.match("rbrace")) {
881
+ if (!this.parseStatement()) {
882
+ throw new Error("Expected closing brace in DOT graph.");
883
+ }
884
+ }
885
+ this.result.graphAttributes = { ...this.scopes[0].graphAttributes };
886
+ }
887
+ /** Dispatches a graph statement. */
888
+ parseStatement() {
889
+ if (this.consumeSemicolonIfPresent()) {
890
+ return true;
891
+ }
892
+ const token = this.peek();
893
+ if (!token) {
894
+ return false;
895
+ }
896
+ if (this.tryParseSubgraphStatement(token)) {
897
+ return true;
898
+ }
899
+ if (this.tryParseKeywordStatement(token)) {
900
+ return true;
901
+ }
902
+ if (this.tryParseAssignmentStatement(token)) {
903
+ return true;
904
+ }
905
+ if (isIdentifierLike(token)) {
906
+ this.parseNodeOrEdgeStatement();
907
+ this.consumeOptionalSemicolon();
908
+ return true;
909
+ }
910
+ throw new Error(`Unexpected token: ${token.value}`);
911
+ }
912
+ /** Consumes an empty statement. */
913
+ consumeSemicolonIfPresent() {
914
+ const next = this.peek();
915
+ if ((next == null ? void 0 : next.type) === "semicolon") {
916
+ this.consume();
917
+ return true;
918
+ }
919
+ return false;
920
+ }
921
+ /** Reads a standalone subgraph statement. */
922
+ tryParseSubgraphStatement(token) {
923
+ if (token.type !== "lbrace" && !isKeyword(token, "subgraph")) {
924
+ return false;
925
+ }
926
+ this.parseSubgraph();
927
+ return true;
928
+ }
929
+ /** Applies graph, node, or edge defaults. */
930
+ tryParseKeywordStatement(token) {
931
+ if (!(isKeyword(token, "graph") || isKeyword(token, "node") || isKeyword(token, "edge"))) {
932
+ return false;
933
+ }
934
+ this.consume();
935
+ const explicitAttributes = this.parseAttributeList();
936
+ if (isKeyword(token, "graph")) {
937
+ Object.assign(this.currentScope().graphAttributes, explicitAttributes);
938
+ } else if (isKeyword(token, "node")) {
939
+ Object.assign(this.currentScope().nodeDefaults, explicitAttributes);
940
+ } else {
941
+ Object.assign(this.currentScope().edgeDefaults, explicitAttributes);
942
+ }
943
+ this.consumeOptionalSemicolon();
944
+ return true;
945
+ }
946
+ /** Reads a graph attribute assignment. */
947
+ tryParseAssignmentStatement(token) {
948
+ if (!isIdentifierLike(token)) {
949
+ return false;
950
+ }
951
+ const next = this.peek(1);
952
+ if ((next == null ? void 0 : next.type) !== "equals") {
953
+ return false;
954
+ }
955
+ const key = parseIdentifierValue(this.consume());
956
+ this.consume();
957
+ const valueToken = this.consume();
958
+ const value = parseAttributeValue(valueToken);
959
+ this.currentScope().graphAttributes[key] = value;
960
+ this.consumeOptionalSemicolon();
961
+ return true;
962
+ }
963
+ /** Reads a node statement or chained edges. */
964
+ parseNodeOrEdgeStatement() {
965
+ const first = parseIdentifierValue(this.consume());
966
+ const references = [first];
967
+ const operators = [];
968
+ let operatorToken = this.match("arrow");
969
+ while (operatorToken) {
970
+ operators.push(operatorToken.value);
971
+ const referenceToken = this.consume();
972
+ if (!isIdentifierLike(referenceToken)) {
973
+ throw new Error("Expected node identifier in edge statement.");
974
+ }
975
+ references.push(parseIdentifierValue(referenceToken));
976
+ operatorToken = this.match("arrow");
977
+ }
978
+ if (operators.length === 0) {
979
+ const explicitAttributes2 = this.parseAttributeList();
980
+ this.addNode(first, explicitAttributes2);
981
+ return;
982
+ }
983
+ const explicitAttributes = this.parseAttributeList();
984
+ this.addEdgeChain(references, operators, explicitAttributes);
985
+ }
986
+ /** Merges explicit attributes into a node. */
987
+ addNode(id, explicitAttributes) {
988
+ const membership = this.getCurrentSubgraphChain();
989
+ const node = this.ensureNode(id, membership);
990
+ node.attributes = { ...node.attributes, ...explicitAttributes };
991
+ }
992
+ /** Expands an edge chain into node and edge records. */
993
+ addEdgeChain(nodes, operators, explicitAttributes) {
994
+ const membership = this.getCurrentSubgraphChain();
995
+ const defaults = this.currentScope().edgeDefaults;
996
+ const attributes = { ...defaults, ...explicitAttributes };
997
+ for (let index = 0; index < nodes.length - 1; index++) {
998
+ const sourceId = nodes[index];
999
+ const targetId = nodes[index + 1];
1000
+ const operator = operators[index];
1001
+ const directed = operator === "->";
1002
+ if (directed !== this.result.directed) {
1003
+ throw new Error("DOT edge operator must match graph or digraph declaration.");
1004
+ }
1005
+ const edgeId = deriveEdgeId(attributes, sourceId, targetId, ++this.edgeCounter);
1006
+ const edgeAttributes = { ...attributes };
1007
+ this.ensureNode(sourceId, membership);
1008
+ this.ensureNode(targetId, membership);
1009
+ const strictKey = JSON.stringify(
1010
+ directed ? [sourceId, targetId] : [sourceId, targetId].sort()
1011
+ );
1012
+ const existingEdge = this.result.strict ? this.strictEdges.get(strictKey) : void 0;
1013
+ if (existingEdge) {
1014
+ existingEdge.attributes = { ...existingEdge.attributes, ...explicitAttributes };
1015
+ const explicitId = explicitAttributes.id ?? explicitAttributes.Id ?? explicitAttributes.ID;
1016
+ if (typeof explicitId === "string" || typeof explicitId === "number") {
1017
+ existingEdge.id = String(explicitId);
1018
+ }
1019
+ existingEdge.directed = deriveDirectedFlag(existingEdge.attributes, directed);
1020
+ existingEdge.subgraphs = Array.from(/* @__PURE__ */ new Set([...existingEdge.subgraphs, ...membership]));
1021
+ continue;
1022
+ }
1023
+ const directedOverride = deriveDirectedFlag(edgeAttributes, directed);
1024
+ const edge = {
1025
+ id: edgeId,
1026
+ sourceId,
1027
+ targetId,
1028
+ directed: directedOverride,
1029
+ attributes: edgeAttributes,
1030
+ subgraphs: membership
1031
+ };
1032
+ this.result.edges.push(edge);
1033
+ if (this.result.strict) {
1034
+ this.strictEdges.set(strictKey, edge);
1035
+ }
1036
+ }
1037
+ }
1038
+ /** Reads a nested scope with inherited defaults. */
1039
+ parseSubgraph() {
1040
+ let idToken = this.peek();
1041
+ let subgraphId;
1042
+ if (idToken && isKeyword(idToken, "subgraph")) {
1043
+ this.consume();
1044
+ idToken = this.peek();
1045
+ }
1046
+ if (idToken && isIdentifierLike(idToken)) {
1047
+ subgraphId = parseIdentifierValue(this.consume());
1048
+ } else {
1049
+ do {
1050
+ subgraphId = `subgraph_${++this.subgraphCounter}`;
1051
+ } while (this.namedSubgraphIds.has(subgraphId));
1052
+ }
1053
+ this.expect("lbrace");
1054
+ const parentId = this.findCurrentSubgraphId();
1055
+ let context = this.subgraphScopes.get(subgraphId);
1056
+ if (!context) {
1057
+ context = {
1058
+ id: subgraphId,
1059
+ nodeDefaults: Object.assign(/* @__PURE__ */ Object.create(null), this.currentScope().nodeDefaults),
1060
+ edgeDefaults: Object.assign(/* @__PURE__ */ Object.create(null), this.currentScope().edgeDefaults),
1061
+ graphAttributes: /* @__PURE__ */ Object.create(null)
1062
+ };
1063
+ this.subgraphScopes.set(subgraphId, context);
1064
+ this.result.subgraphs.set(subgraphId, {
1065
+ id: subgraphId,
1066
+ attributes: context.graphAttributes,
1067
+ parentId
1068
+ });
1069
+ }
1070
+ this.scopes.push(context);
1071
+ let shouldContinue = true;
1072
+ while (shouldContinue) {
1073
+ if (this.match("rbrace")) {
1074
+ break;
1075
+ }
1076
+ shouldContinue = this.parseStatement();
1077
+ if (!shouldContinue) {
1078
+ throw new Error("Expected closing brace in DOT subgraph.");
1079
+ }
1080
+ }
1081
+ this.scopes.pop();
1082
+ }
1083
+ /** Reads repeated attribute lists. */
1084
+ parseAttributeList() {
1085
+ var _a, _b;
1086
+ const attributes = /* @__PURE__ */ Object.create(null);
1087
+ while (this.match("lbrack")) {
1088
+ while (!this.match("rbrack")) {
1089
+ const keyToken = this.consume();
1090
+ if (!isIdentifierLike(keyToken)) {
1091
+ throw new Error("Expected attribute name.");
1092
+ }
1093
+ const key = parseIdentifierValue(keyToken);
1094
+ let value = true;
1095
+ if (this.match("equals")) {
1096
+ const valueToken = this.consume();
1097
+ value = parseAttributeValue(valueToken);
1098
+ }
1099
+ attributes[key] = value;
1100
+ if (((_a = this.peek()) == null ? void 0 : _a.type) === "comma" || ((_b = this.peek()) == null ? void 0 : _b.type) === "semicolon") {
1101
+ this.consume();
1102
+ }
1103
+ }
1104
+ }
1105
+ return attributes;
1106
+ }
1107
+ /** Creates an implicit node and records its subgraph memberships. */
1108
+ ensureNode(id, membership) {
1109
+ let node = this.result.nodes.get(id);
1110
+ if (!node) {
1111
+ const defaults = this.currentScope().nodeDefaults;
1112
+ node = { id, attributes: { ...defaults }, subgraphs: /* @__PURE__ */ new Set() };
1113
+ this.result.nodes.set(id, node);
1114
+ }
1115
+ membership.forEach((subgraphId) => node.subgraphs.add(subgraphId));
1116
+ return node;
1117
+ }
1118
+ /** Lists enclosing subgraphs. */
1119
+ getCurrentSubgraphChain() {
1120
+ const chain = [];
1121
+ for (const scope of this.scopes) {
1122
+ if (scope.id) {
1123
+ chain.push(scope.id);
1124
+ }
1125
+ }
1126
+ return chain;
1127
+ }
1128
+ /** Finds the nearest enclosing named or generated subgraph. */
1129
+ findCurrentSubgraphId() {
1130
+ for (let index = this.scopes.length - 1; index >= 0; index--) {
1131
+ const scope = this.scopes[index];
1132
+ if (scope.id) {
1133
+ return scope.id;
1134
+ }
1135
+ }
1136
+ return void 0;
1137
+ }
1138
+ /** Returns the active attribute scope. */
1139
+ currentScope() {
1140
+ return this.scopes[this.scopes.length - 1];
1141
+ }
1142
+ /** Consumes an optional statement terminator. */
1143
+ consumeOptionalSemicolon() {
1144
+ const next = this.peek();
1145
+ if ((next == null ? void 0 : next.type) === "semicolon") {
1146
+ this.consume();
1147
+ }
1148
+ }
1149
+ /** Requires the next token to have the requested type. */
1150
+ expect(type) {
1151
+ const token = this.consume();
1152
+ if (!token || token.type !== type) {
1153
+ throw new Error(`Expected token ${type}.`);
1154
+ }
1155
+ return token;
1156
+ }
1157
+ /** Consumes the next token or reports truncated input. */
1158
+ consume() {
1159
+ const token = this.tokens[this.position];
1160
+ if (!token) {
1161
+ throw new Error("Unexpected end of DOT input.");
1162
+ }
1163
+ this.position++;
1164
+ return token;
1165
+ }
1166
+ /** Consumes a token when its type matches. */
1167
+ match(type) {
1168
+ const token = this.peek();
1169
+ if (token && token.type === type) {
1170
+ this.position++;
1171
+ return token;
1172
+ }
1173
+ return null;
1174
+ }
1175
+ /** Inspects a token without consuming it. */
1176
+ peek(offset = 0) {
1177
+ return this.tokens[this.position + offset] ?? null;
1178
+ }
1179
+ };
1180
+ IDENTIFIER_TERMINATORS = /* @__PURE__ */ new Set(["{", "}", "[", "]", "=", ";", ",", '"', "<", "#"]);
1181
+ }
1182
+ });
19
1183
 
20
- // dist/dot-loader.js
1184
+ // src/dot-loader.ts
21
1185
  var dot_loader_exports = {};
22
1186
  __export(dot_loader_exports, {
23
1187
  DOTLoaderWithParser: () => DOTLoaderWithParser
24
1188
  });
25
- module.exports = __toCommonJS(dot_loader_exports);
1189
+ var DOTLoaderWithParser;
1190
+ var init_dot_loader = __esm({
1191
+ "src/dot-loader.ts"() {
1192
+ "use strict";
1193
+ init_dot_loader_types();
1194
+ init_parse_dot();
1195
+ DOTLoaderWithParser = {
1196
+ ...DOTLoader,
1197
+ parse: async (data, options) => {
1198
+ var _a;
1199
+ return parseDOT(new TextDecoder().decode(data), ((_a = options == null ? void 0 : options.dot) == null ? void 0 : _a.shape) ?? "arrow-table");
1200
+ },
1201
+ parseSync: (data, options) => {
1202
+ var _a;
1203
+ return parseDOT(new TextDecoder().decode(data), ((_a = options == null ? void 0 : options.dot) == null ? void 0 : _a.shape) ?? "arrow-table");
1204
+ },
1205
+ parseTextSync: (data, options) => {
1206
+ var _a;
1207
+ return parseDOT(data, ((_a = options == null ? void 0 : options.dot) == null ? void 0 : _a.shape) ?? "arrow-table");
1208
+ }
1209
+ };
1210
+ }
1211
+ });
1212
+
1213
+ // dist/dot-loader.js
1214
+ var dot_loader_exports2 = {};
1215
+ __export(dot_loader_exports2, {
1216
+ DOTLoaderWithParser: () => DOTLoaderWithParser2
1217
+ });
1218
+ module.exports = __toCommonJS(dot_loader_exports2);
26
1219
 
27
1220
  // dist/dot-loader-types.js
28
- var VERSION = true ? "4.5.3" : "latest";
29
- var DOTLoader = {
1221
+ var VERSION2 = true ? "5.0.0-alpha.10" : "latest";
1222
+ async function preload2() {
1223
+ const { DOTLoaderWithParser: DOTLoaderWithParser3 } = await Promise.resolve().then(() => (init_dot_loader(), dot_loader_exports));
1224
+ return DOTLoaderWithParser3;
1225
+ }
1226
+ var DOTLoader2 = {
30
1227
  name: "DOT",
31
1228
  id: "dot",
32
1229
  module: "graphs",
33
- version: VERSION,
1230
+ version: VERSION2,
34
1231
  extensions: ["dot", "gv"],
35
1232
  mimeTypes: ["text/vnd.graphviz", "text/x-graphviz", "application/vnd.graphviz"],
36
1233
  text: true,
37
1234
  worker: false,
38
1235
  dataType: null,
39
1236
  batchType: null,
40
- options: {}
1237
+ options: { dot: { shape: "arrow-table" } },
1238
+ preload: preload2
41
1239
  };
42
1240
 
43
- // dist/lib/parse-dot.js
44
- function parseDOT(input) {
45
- const parsed = parseDOTDocument(input);
46
- const subgraphs = Array.from(parsed.subgraphs.values(), (subgraph) => ({
47
- ...subgraph,
48
- attributes: { ...subgraph.attributes }
1241
+ // dist/lib/build-graph-tables.js
1242
+ var import_apache_arrow2 = require("apache-arrow");
1243
+ init_src();
1244
+ function buildGraphTables2(nodes, edges, shape, declarations) {
1245
+ if (shape === "plain-graph-data") {
1246
+ return { shape, nodes: Array.from(nodes), edges: Array.from(edges) };
1247
+ }
1248
+ if (shape !== "arrow-table" && shape !== "object-row-table") {
1249
+ throw new Error(`Unsupported graph shape: ${shape}`);
1250
+ }
1251
+ const nodeTable = buildGraphTable2(nodes, false, shape, declarations == null ? void 0 : declarations.nodes);
1252
+ const edgeTable = buildGraphTable2(edges, true, shape, declarations == null ? void 0 : declarations.edges);
1253
+ return {
1254
+ shape: "tables",
1255
+ tables: [
1256
+ { name: "nodes", table: nodeTable },
1257
+ { name: "edges", table: edgeTable }
1258
+ ]
1259
+ };
1260
+ }
1261
+ function buildGraphTable2(records, isEdge, shape, declarations) {
1262
+ const columnNames = isEdge ? ["id", "sourceId", "targetId", "directed", "label", "attributes"] : ["id", "label", "attributes"];
1263
+ const columns = new Map(columnNames.map((name) => [name, []]));
1264
+ for (const record of records) {
1265
+ for (const name of columnNames) {
1266
+ const value = record[name];
1267
+ columns.get(name).push(name === "id" || name === "sourceId" || name === "targetId" ? String(value) : value ?? null);
1268
+ }
1269
+ }
1270
+ if (shape === "object-row-table") {
1271
+ return {
1272
+ shape,
1273
+ data: columns.get("id").map((_, index) => Object.fromEntries(columnNames.map((name) => [name, columns.get(name)[index]])))
1274
+ };
1275
+ }
1276
+ const vectors = /* @__PURE__ */ Object.create(null);
1277
+ for (const [name, values] of columns) {
1278
+ const type = name === "attributes" ? inferAttributeType2(values, declarations) : name === "directed" ? new import_apache_arrow2.Bool() : new import_apache_arrow2.Utf8();
1279
+ vectors[name] = (0, import_apache_arrow2.vectorFromArray)(values.map((value) => normalizeValue2(value, type)), type);
1280
+ }
1281
+ const data = new import_apache_arrow2.Table(vectors);
1282
+ return { shape, schema: convertArrowToSchema(data.schema), data };
1283
+ }
1284
+ function inferAttributeType2(values, declarations) {
1285
+ const names = new Set(declarations == null ? void 0 : declarations.keys());
1286
+ for (const value of values) {
1287
+ if (value && typeof value === "object") {
1288
+ for (const name of Object.keys(value)) {
1289
+ names.add(name);
1290
+ }
1291
+ }
1292
+ }
1293
+ return new import_apache_arrow2.Struct(Array.from(names, (name) => {
1294
+ const fieldValues = values.map((value) => (value == null ? void 0 : value[name]) ?? null);
1295
+ return new import_apache_arrow2.Field(name, inferValueType2(fieldValues, declarations == null ? void 0 : declarations.get(name)), true);
49
1296
  }));
1297
+ }
1298
+ function inferValueType2(values, declaration) {
1299
+ const present = values.filter((value) => value !== null && value !== void 0);
1300
+ if (declaration && typeof declaration === "object") {
1301
+ if (!present.every((value) => Array.isArray(value)))
1302
+ return new import_apache_arrow2.Utf8();
1303
+ return new import_apache_arrow2.List(new import_apache_arrow2.Field("item", inferValueType2(present.flatMap((value) => value), declaration.list), true));
1304
+ }
1305
+ if (declaration) {
1306
+ const declaredTypes = {
1307
+ boolean: new import_apache_arrow2.Bool(),
1308
+ int: new import_apache_arrow2.Int32(),
1309
+ long: new import_apache_arrow2.Int64(),
1310
+ float: new import_apache_arrow2.Float32(),
1311
+ double: new import_apache_arrow2.Float64(),
1312
+ string: new import_apache_arrow2.Utf8()
1313
+ };
1314
+ const valid = present.every((value) => {
1315
+ switch (declaration) {
1316
+ case "boolean":
1317
+ return typeof value === "boolean";
1318
+ case "int":
1319
+ return typeof value === "number" && Number.isInteger(value) && value >= -2147483648 && value <= 2147483647;
1320
+ case "long":
1321
+ return typeof value === "bigint" && value >= -(2n ** 63n) && value < 2n ** 63n;
1322
+ case "float":
1323
+ case "double":
1324
+ return typeof value === "number";
1325
+ case "string":
1326
+ return typeof value === "string";
1327
+ }
1328
+ });
1329
+ return valid ? declaredTypes[declaration] : new import_apache_arrow2.Utf8();
1330
+ }
1331
+ if (present.length && present.every((value) => typeof value === "boolean"))
1332
+ return new import_apache_arrow2.Bool();
1333
+ if (present.length && present.every((value) => typeof value === "number"))
1334
+ return new import_apache_arrow2.Float64();
1335
+ if (present.length && present.every((value) => Array.isArray(value))) {
1336
+ return new import_apache_arrow2.List(new import_apache_arrow2.Field("item", inferValueType2(present.flatMap((value) => value)), true));
1337
+ }
1338
+ if (present.length && present.every((value) => typeof value === "object" && !Array.isArray(value))) {
1339
+ return inferAttributeType2(present);
1340
+ }
1341
+ return new import_apache_arrow2.Utf8();
1342
+ }
1343
+ function normalizeValue2(value, type) {
1344
+ if (value === null || value === void 0)
1345
+ return null;
1346
+ if (type instanceof import_apache_arrow2.Struct) {
1347
+ return Object.fromEntries(type.children.map((field) => [
1348
+ field.name,
1349
+ normalizeValue2(value[field.name], field.type)
1350
+ ]));
1351
+ }
1352
+ if (type instanceof import_apache_arrow2.List)
1353
+ return value.map((item) => normalizeValue2(item, type.valueType));
1354
+ if (type instanceof import_apache_arrow2.Utf8 && typeof value !== "string") {
1355
+ return typeof value === "object" ? JSON.stringify(value) : String(value);
1356
+ }
1357
+ return value;
1358
+ }
1359
+
1360
+ // dist/lib/parse-dot.js
1361
+ function parseDOT2(input, shape = "plain-graph-data") {
1362
+ const parsed = parseDOTDocument2(input);
50
1363
  return {
51
- shape: "plain-graph-data",
52
- nodes: Array.from(parsed.nodes.values(), (node) => ({
1364
+ ...buildGraphTables2(iterateNodes2(parsed), iterateEdges2(parsed), shape),
1365
+ metadata: {
1366
+ id: parsed.id,
1367
+ directed: parsed.directed,
1368
+ strict: parsed.strict,
1369
+ attributes: { ...parsed.graphAttributes },
1370
+ subgraphs: Array.from(parsed.subgraphs.values(), (subgraph) => ({
1371
+ ...subgraph,
1372
+ attributes: { ...subgraph.attributes }
1373
+ }))
1374
+ }
1375
+ };
1376
+ }
1377
+ function* iterateNodes2(parsed) {
1378
+ for (const node of parsed.nodes.values()) {
1379
+ yield {
53
1380
  id: node.id,
54
1381
  ...typeof node.attributes.label === "string" ? { label: node.attributes.label } : {},
55
1382
  attributes: {
56
1383
  ...node.attributes,
57
- ...node.subgraphs.size ? { subgraphs: Array.from(node.subgraphs, (id) => describeSubgraph(id, parsed.subgraphs)) } : {}
1384
+ ...node.subgraphs.size ? { subgraphs: Array.from(node.subgraphs, (id) => describeSubgraph2(id, parsed.subgraphs)) } : {}
58
1385
  }
59
- })),
60
- edges: parsed.edges.map((edge) => ({
1386
+ };
1387
+ }
1388
+ }
1389
+ function* iterateEdges2(parsed) {
1390
+ for (const edge of parsed.edges) {
1391
+ yield {
61
1392
  id: edge.id,
62
1393
  sourceId: edge.sourceId,
63
1394
  targetId: edge.targetId,
@@ -65,19 +1396,12 @@ function parseDOT(input) {
65
1396
  ...typeof edge.attributes.label === "string" ? { label: edge.attributes.label } : {},
66
1397
  attributes: {
67
1398
  ...edge.attributes,
68
- ...edge.subgraphs.length ? { subgraphs: edge.subgraphs.map((id) => describeSubgraph(id, parsed.subgraphs)) } : {}
1399
+ ...edge.subgraphs.length ? { subgraphs: edge.subgraphs.map((id) => describeSubgraph2(id, parsed.subgraphs)) } : {}
69
1400
  }
70
- })),
71
- metadata: {
72
- id: parsed.id,
73
- directed: parsed.directed,
74
- strict: parsed.strict,
75
- attributes: { ...parsed.graphAttributes },
76
- subgraphs
77
- }
78
- };
1401
+ };
1402
+ }
79
1403
  }
80
- function describeSubgraph(id, descriptors) {
1404
+ function describeSubgraph2(id, descriptors) {
81
1405
  const subgraph = descriptors.get(id);
82
1406
  return {
83
1407
  id,
@@ -85,7 +1409,7 @@ function describeSubgraph(id, descriptors) {
85
1409
  parentId: subgraph.parentId
86
1410
  };
87
1411
  }
88
- var DOTParser = class {
1412
+ var DOTParser2 = class {
89
1413
  /** Tokens for DOT parsing. */
90
1414
  tokens;
91
1415
  /** Position for DOT parsing. */
@@ -121,7 +1445,7 @@ var DOTParser = class {
121
1445
  constructor(tokens) {
122
1446
  this.tokens = tokens;
123
1447
  for (let index = 0; index < tokens.length - 1; index++) {
124
- if (isKeyword(tokens[index], "subgraph") && isIdentifierLike(tokens[index + 1])) {
1448
+ if (isKeyword2(tokens[index], "subgraph") && isIdentifierLike2(tokens[index + 1])) {
125
1449
  this.namedSubgraphIds.add(tokens[index + 1].value);
126
1450
  }
127
1451
  }
@@ -138,19 +1462,19 @@ var DOTParser = class {
138
1462
  /** Reads graph identity, declaration, and statements. */
139
1463
  parseGraph() {
140
1464
  const strictToken = this.peek();
141
- if (strictToken && isKeyword(strictToken, "strict")) {
1465
+ if (strictToken && isKeyword2(strictToken, "strict")) {
142
1466
  this.consume();
143
1467
  this.result.strict = true;
144
1468
  }
145
1469
  const typeToken = this.peek();
146
- if (!typeToken || !isGraphType(typeToken)) {
1470
+ if (!typeToken || !isGraphType2(typeToken)) {
147
1471
  throw new Error("DOT graph must start with graph or digraph keyword.");
148
1472
  }
149
1473
  this.consume();
150
- this.result.directed = isKeyword(typeToken, "digraph");
1474
+ this.result.directed = isKeyword2(typeToken, "digraph");
151
1475
  const idToken = this.peek();
152
- if (idToken && isIdentifierLike(idToken)) {
153
- this.result.id = parseIdentifierValue(this.consume());
1476
+ if (idToken && isIdentifierLike2(idToken)) {
1477
+ this.result.id = parseIdentifierValue2(this.consume());
154
1478
  }
155
1479
  this.expect("lbrace");
156
1480
  while (!this.match("rbrace")) {
@@ -178,7 +1502,7 @@ var DOTParser = class {
178
1502
  if (this.tryParseAssignmentStatement(token)) {
179
1503
  return true;
180
1504
  }
181
- if (isIdentifierLike(token)) {
1505
+ if (isIdentifierLike2(token)) {
182
1506
  this.parseNodeOrEdgeStatement();
183
1507
  this.consumeOptionalSemicolon();
184
1508
  return true;
@@ -196,7 +1520,7 @@ var DOTParser = class {
196
1520
  }
197
1521
  /** Reads a standalone subgraph statement. */
198
1522
  tryParseSubgraphStatement(token) {
199
- if (token.type !== "lbrace" && !isKeyword(token, "subgraph")) {
1523
+ if (token.type !== "lbrace" && !isKeyword2(token, "subgraph")) {
200
1524
  return false;
201
1525
  }
202
1526
  this.parseSubgraph();
@@ -204,14 +1528,14 @@ var DOTParser = class {
204
1528
  }
205
1529
  /** Applies graph, node, or edge defaults. */
206
1530
  tryParseKeywordStatement(token) {
207
- if (!(isKeyword(token, "graph") || isKeyword(token, "node") || isKeyword(token, "edge"))) {
1531
+ if (!(isKeyword2(token, "graph") || isKeyword2(token, "node") || isKeyword2(token, "edge"))) {
208
1532
  return false;
209
1533
  }
210
1534
  this.consume();
211
1535
  const explicitAttributes = this.parseAttributeList();
212
- if (isKeyword(token, "graph")) {
1536
+ if (isKeyword2(token, "graph")) {
213
1537
  Object.assign(this.currentScope().graphAttributes, explicitAttributes);
214
- } else if (isKeyword(token, "node")) {
1538
+ } else if (isKeyword2(token, "node")) {
215
1539
  Object.assign(this.currentScope().nodeDefaults, explicitAttributes);
216
1540
  } else {
217
1541
  Object.assign(this.currentScope().edgeDefaults, explicitAttributes);
@@ -221,34 +1545,34 @@ var DOTParser = class {
221
1545
  }
222
1546
  /** Reads a graph attribute assignment. */
223
1547
  tryParseAssignmentStatement(token) {
224
- if (!isIdentifierLike(token)) {
1548
+ if (!isIdentifierLike2(token)) {
225
1549
  return false;
226
1550
  }
227
1551
  const next = this.peek(1);
228
1552
  if ((next == null ? void 0 : next.type) !== "equals") {
229
1553
  return false;
230
1554
  }
231
- const key = parseIdentifierValue(this.consume());
1555
+ const key = parseIdentifierValue2(this.consume());
232
1556
  this.consume();
233
1557
  const valueToken = this.consume();
234
- const value = parseAttributeValue(valueToken);
1558
+ const value = parseAttributeValue2(valueToken);
235
1559
  this.currentScope().graphAttributes[key] = value;
236
1560
  this.consumeOptionalSemicolon();
237
1561
  return true;
238
1562
  }
239
1563
  /** Reads a node statement or chained edges. */
240
1564
  parseNodeOrEdgeStatement() {
241
- const first = parseIdentifierValue(this.consume());
1565
+ const first = parseIdentifierValue2(this.consume());
242
1566
  const references = [first];
243
1567
  const operators = [];
244
1568
  let operatorToken = this.match("arrow");
245
1569
  while (operatorToken) {
246
1570
  operators.push(operatorToken.value);
247
1571
  const referenceToken = this.consume();
248
- if (!isIdentifierLike(referenceToken)) {
1572
+ if (!isIdentifierLike2(referenceToken)) {
249
1573
  throw new Error("Expected node identifier in edge statement.");
250
1574
  }
251
- references.push(parseIdentifierValue(referenceToken));
1575
+ references.push(parseIdentifierValue2(referenceToken));
252
1576
  operatorToken = this.match("arrow");
253
1577
  }
254
1578
  if (operators.length === 0) {
@@ -278,7 +1602,7 @@ var DOTParser = class {
278
1602
  if (directed !== this.result.directed) {
279
1603
  throw new Error("DOT edge operator must match graph or digraph declaration.");
280
1604
  }
281
- const edgeId = deriveEdgeId(attributes, sourceId, targetId, ++this.edgeCounter);
1605
+ const edgeId = deriveEdgeId2(attributes, sourceId, targetId, ++this.edgeCounter);
282
1606
  const edgeAttributes = { ...attributes };
283
1607
  this.ensureNode(sourceId, membership);
284
1608
  this.ensureNode(targetId, membership);
@@ -286,11 +1610,15 @@ var DOTParser = class {
286
1610
  const existingEdge = this.result.strict ? this.strictEdges.get(strictKey) : void 0;
287
1611
  if (existingEdge) {
288
1612
  existingEdge.attributes = { ...existingEdge.attributes, ...explicitAttributes };
289
- existingEdge.directed = deriveDirectedFlag(existingEdge.attributes, directed);
1613
+ const explicitId = explicitAttributes.id ?? explicitAttributes.Id ?? explicitAttributes.ID;
1614
+ if (typeof explicitId === "string" || typeof explicitId === "number") {
1615
+ existingEdge.id = String(explicitId);
1616
+ }
1617
+ existingEdge.directed = deriveDirectedFlag2(existingEdge.attributes, directed);
290
1618
  existingEdge.subgraphs = Array.from(/* @__PURE__ */ new Set([...existingEdge.subgraphs, ...membership]));
291
1619
  continue;
292
1620
  }
293
- const directedOverride = deriveDirectedFlag(edgeAttributes, directed);
1621
+ const directedOverride = deriveDirectedFlag2(edgeAttributes, directed);
294
1622
  const edge = {
295
1623
  id: edgeId,
296
1624
  sourceId,
@@ -309,12 +1637,12 @@ var DOTParser = class {
309
1637
  parseSubgraph() {
310
1638
  let idToken = this.peek();
311
1639
  let subgraphId;
312
- if (idToken && isKeyword(idToken, "subgraph")) {
1640
+ if (idToken && isKeyword2(idToken, "subgraph")) {
313
1641
  this.consume();
314
1642
  idToken = this.peek();
315
1643
  }
316
- if (idToken && isIdentifierLike(idToken)) {
317
- subgraphId = parseIdentifierValue(this.consume());
1644
+ if (idToken && isIdentifierLike2(idToken)) {
1645
+ subgraphId = parseIdentifierValue2(this.consume());
318
1646
  } else {
319
1647
  do {
320
1648
  subgraphId = `subgraph_${++this.subgraphCounter}`;
@@ -357,14 +1685,14 @@ var DOTParser = class {
357
1685
  while (this.match("lbrack")) {
358
1686
  while (!this.match("rbrack")) {
359
1687
  const keyToken = this.consume();
360
- if (!isIdentifierLike(keyToken)) {
1688
+ if (!isIdentifierLike2(keyToken)) {
361
1689
  throw new Error("Expected attribute name.");
362
1690
  }
363
- const key = parseIdentifierValue(keyToken);
1691
+ const key = parseIdentifierValue2(keyToken);
364
1692
  let value = true;
365
1693
  if (this.match("equals")) {
366
1694
  const valueToken = this.consume();
367
- value = parseAttributeValue(valueToken);
1695
+ value = parseAttributeValue2(valueToken);
368
1696
  }
369
1697
  attributes[key] = value;
370
1698
  if (((_a = this.peek()) == null ? void 0 : _a.type) === "comma" || ((_b = this.peek()) == null ? void 0 : _b.type) === "semicolon") {
@@ -447,16 +1775,16 @@ var DOTParser = class {
447
1775
  return this.tokens[this.position + offset] ?? null;
448
1776
  }
449
1777
  };
450
- function parseDOTDocument(input) {
451
- const parser = new DOTParser(tokenize(input));
1778
+ function parseDOTDocument2(input) {
1779
+ const parser = new DOTParser2(tokenize2(input));
452
1780
  return parser.parse();
453
1781
  }
454
- var IDENTIFIER_TERMINATORS = /* @__PURE__ */ new Set(["{", "}", "[", "]", "=", ";", ",", '"', "<", "#"]);
455
- function tokenize(input) {
1782
+ var IDENTIFIER_TERMINATORS2 = /* @__PURE__ */ new Set(["{", "}", "[", "]", "=", ";", ",", '"', "<", "#"]);
1783
+ function tokenize2(input) {
456
1784
  const tokens = [];
457
1785
  let index = 0;
458
1786
  while (index < input.length) {
459
- const { token, nextIndex } = readNextToken(input, index);
1787
+ const { token, nextIndex } = readNextToken2(input, index);
460
1788
  if (nextIndex <= index) {
461
1789
  throw new Error(`Tokenizer did not advance at position ${index}.`);
462
1790
  }
@@ -467,35 +1795,35 @@ function tokenize(input) {
467
1795
  }
468
1796
  return tokens;
469
1797
  }
470
- function readNextToken(input, index) {
1798
+ function readNextToken2(input, index) {
471
1799
  if (index >= input.length) {
472
1800
  return { token: null, nextIndex: input.length };
473
1801
  }
474
1802
  const character = input[index];
475
- if (isWhitespace(character)) {
1803
+ if (isWhitespace2(character)) {
476
1804
  return { token: null, nextIndex: index + 1 };
477
1805
  }
478
- const commentEnd = skipComment(input, index);
1806
+ const commentEnd = skipComment2(input, index);
479
1807
  if (commentEnd !== null) {
480
1808
  return { token: null, nextIndex: commentEnd };
481
1809
  }
482
- const arrowToken = readArrowToken(input, index);
1810
+ const arrowToken = readArrowToken2(input, index);
483
1811
  if (arrowToken) {
484
1812
  return arrowToken;
485
1813
  }
486
- const punctuation = readPunctuationToken(character);
1814
+ const punctuation = readPunctuationToken2(character);
487
1815
  if (punctuation) {
488
1816
  return { token: punctuation, nextIndex: index + 1 };
489
1817
  }
490
1818
  if (character === '"') {
491
- const { value, nextIndex } = readQuotedString(input, index + 1);
1819
+ const { value, nextIndex } = readQuotedString2(input, index + 1);
492
1820
  return { token: { type: "string", value }, nextIndex };
493
1821
  }
494
1822
  if (character === "<") {
495
- const { value, nextIndex } = readHtmlString(input, index + 1);
1823
+ const { value, nextIndex } = readHtmlString2(input, index + 1);
496
1824
  return { token: { type: "html", value }, nextIndex };
497
1825
  }
498
- const identifier = readIdentifier(input, index);
1826
+ const identifier = readIdentifier2(input, index);
499
1827
  if (identifier.value) {
500
1828
  return {
501
1829
  token: { type: "identifier", value: identifier.value },
@@ -504,31 +1832,31 @@ function readNextToken(input, index) {
504
1832
  }
505
1833
  throw new Error(`Unexpected token at position ${index}.`);
506
1834
  }
507
- function skipComment(input, index) {
1835
+ function skipComment2(input, index) {
508
1836
  const character = input[index];
509
1837
  if (character === "/") {
510
1838
  const next = input[index + 1];
511
1839
  if (next === "/") {
512
- return skipLineComment(input, index + 2);
1840
+ return skipLineComment2(input, index + 2);
513
1841
  }
514
1842
  if (next === "*") {
515
- return skipBlockComment(input, index + 2);
1843
+ return skipBlockComment2(input, index + 2);
516
1844
  }
517
1845
  return null;
518
1846
  }
519
1847
  if (character === "#") {
520
- return skipLineComment(input, index + 1);
1848
+ return skipLineComment2(input, index + 1);
521
1849
  }
522
1850
  return null;
523
1851
  }
524
- function skipLineComment(input, startIndex) {
1852
+ function skipLineComment2(input, startIndex) {
525
1853
  let cursor = startIndex;
526
- while (cursor < input.length && !isLineBreak(input[cursor])) {
1854
+ while (cursor < input.length && !isLineBreak2(input[cursor])) {
527
1855
  cursor++;
528
1856
  }
529
1857
  return cursor;
530
1858
  }
531
- function skipBlockComment(input, startIndex) {
1859
+ function skipBlockComment2(input, startIndex) {
532
1860
  let cursor = startIndex;
533
1861
  while (cursor < input.length) {
534
1862
  if (input[cursor] === "*" && input[cursor + 1] === "/") {
@@ -538,7 +1866,7 @@ function skipBlockComment(input, startIndex) {
538
1866
  }
539
1867
  throw new Error("Unterminated block comment in DOT source.");
540
1868
  }
541
- function readArrowToken(input, index) {
1869
+ function readArrowToken2(input, index) {
542
1870
  const next = input[index + 1];
543
1871
  if (input[index] === "-" && next === "-") {
544
1872
  return { token: { type: "arrow", value: "--" }, nextIndex: index + 2 };
@@ -548,7 +1876,7 @@ function readArrowToken(input, index) {
548
1876
  }
549
1877
  return null;
550
1878
  }
551
- function readPunctuationToken(character) {
1879
+ function readPunctuationToken2(character) {
552
1880
  switch (character) {
553
1881
  case "{":
554
1882
  return { type: "lbrace", value: character };
@@ -568,7 +1896,7 @@ function readPunctuationToken(character) {
568
1896
  return null;
569
1897
  }
570
1898
  }
571
- function readQuotedString(input, startIndex) {
1899
+ function readQuotedString2(input, startIndex) {
572
1900
  let value = "";
573
1901
  let index = startIndex;
574
1902
  while (index < input.length) {
@@ -577,7 +1905,7 @@ function readQuotedString(input, startIndex) {
577
1905
  return { value, nextIndex: index + 1 };
578
1906
  }
579
1907
  if (character === "\\") {
580
- const escape = readEscapedCharacter(input, index + 1);
1908
+ const escape = readEscapedCharacter2(input, index + 1);
581
1909
  value += escape.value;
582
1910
  index = escape.nextIndex;
583
1911
  } else {
@@ -587,9 +1915,13 @@ function readQuotedString(input, startIndex) {
587
1915
  }
588
1916
  throw new Error("Unterminated string literal in DOT source.");
589
1917
  }
590
- function readEscapedCharacter(input, startIndex) {
1918
+ function readEscapedCharacter2(input, startIndex) {
591
1919
  const next = input[startIndex];
592
1920
  switch (next) {
1921
+ case "\n":
1922
+ return { value: "", nextIndex: startIndex + 1 };
1923
+ case "\r":
1924
+ return { value: "", nextIndex: startIndex + (input[startIndex + 1] === "\n" ? 2 : 1) };
593
1925
  case "n":
594
1926
  case "l":
595
1927
  case "L":
@@ -606,11 +1938,11 @@ function readEscapedCharacter(input, startIndex) {
606
1938
  if (typeof next === "undefined") {
607
1939
  throw new Error("Unterminated escape sequence in DOT source.");
608
1940
  }
609
- return { value: next, nextIndex: startIndex + 1 };
1941
+ return { value: `\\${next}`, nextIndex: startIndex + 1 };
610
1942
  }
611
1943
  }
612
1944
  }
613
- function readHtmlString(input, startIndex) {
1945
+ function readHtmlString2(input, startIndex) {
614
1946
  let value = "<";
615
1947
  let depth = 1;
616
1948
  let index = startIndex;
@@ -629,10 +1961,10 @@ function readHtmlString(input, startIndex) {
629
1961
  }
630
1962
  throw new Error("Unterminated HTML-like string literal in DOT source.");
631
1963
  }
632
- function readIdentifier(input, startIndex) {
1964
+ function readIdentifier2(input, startIndex) {
633
1965
  let index = startIndex;
634
1966
  let value = "";
635
- while (index < input.length && !isIdentifierTerminator(input, index)) {
1967
+ while (index < input.length && !isIdentifierTerminator2(input, index)) {
636
1968
  value += input[index];
637
1969
  index++;
638
1970
  }
@@ -641,52 +1973,52 @@ function readIdentifier(input, startIndex) {
641
1973
  }
642
1974
  return { value, nextIndex: index };
643
1975
  }
644
- function isIdentifierTerminator(input, index) {
1976
+ function isIdentifierTerminator2(input, index) {
645
1977
  const character = input[index];
646
- if (isWhitespace(character) || IDENTIFIER_TERMINATORS.has(character)) {
1978
+ if (isWhitespace2(character) || IDENTIFIER_TERMINATORS2.has(character)) {
647
1979
  return true;
648
1980
  }
649
- if (isArrowOperatorStart(input, index)) {
1981
+ if (isArrowOperatorStart2(input, index)) {
650
1982
  return true;
651
1983
  }
652
- if (isCommentStart(input, index)) {
1984
+ if (isCommentStart2(input, index)) {
653
1985
  return true;
654
1986
  }
655
1987
  return false;
656
1988
  }
657
- function isArrowOperatorStart(input, index) {
1989
+ function isArrowOperatorStart2(input, index) {
658
1990
  if (input[index] !== "-") {
659
1991
  return false;
660
1992
  }
661
1993
  const next = input[index + 1];
662
1994
  return next === "-" || next === ">";
663
1995
  }
664
- function isCommentStart(input, index) {
1996
+ function isCommentStart2(input, index) {
665
1997
  if (input[index] !== "/") {
666
1998
  return false;
667
1999
  }
668
2000
  const next = input[index + 1];
669
2001
  return next === "/" || next === "*";
670
2002
  }
671
- function isWhitespace(character) {
2003
+ function isWhitespace2(character) {
672
2004
  return character === " " || character === "\n" || character === "\r" || character === " " || character === "\f";
673
2005
  }
674
- function isLineBreak(character) {
2006
+ function isLineBreak2(character) {
675
2007
  return character === "\n" || character === "\r";
676
2008
  }
677
- function isKeyword(token, keyword) {
2009
+ function isKeyword2(token, keyword) {
678
2010
  return token.type === "identifier" && token.value.toLowerCase() === keyword.toLowerCase();
679
2011
  }
680
- function isGraphType(token) {
681
- return isKeyword(token, "graph") || isKeyword(token, "digraph");
2012
+ function isGraphType2(token) {
2013
+ return isKeyword2(token, "graph") || isKeyword2(token, "digraph");
682
2014
  }
683
- function isIdentifierLike(token) {
2015
+ function isIdentifierLike2(token) {
684
2016
  return token.type === "identifier" || token.type === "string" || token.type === "html";
685
2017
  }
686
- function parseIdentifierValue(token) {
2018
+ function parseIdentifierValue2(token) {
687
2019
  return token.value;
688
2020
  }
689
- function parseAttributeValue(token) {
2021
+ function parseAttributeValue2(token) {
690
2022
  if (token.type === "string" || token.type === "html") {
691
2023
  return token.value;
692
2024
  }
@@ -699,14 +2031,14 @@ function parseAttributeValue(token) {
699
2031
  }
700
2032
  throw new Error("Invalid attribute value in DOT input.");
701
2033
  }
702
- function deriveEdgeId(attributes, sourceId, targetId, counter) {
2034
+ function deriveEdgeId2(attributes, sourceId, targetId, counter) {
703
2035
  const candidate = attributes.id ?? attributes.Id ?? attributes.ID;
704
2036
  if (typeof candidate === "string" || typeof candidate === "number") {
705
2037
  return String(candidate);
706
2038
  }
707
2039
  return `${String(sourceId)}-${String(targetId)}-${counter}`;
708
2040
  }
709
- function deriveDirectedFlag(attributes, defaultDirected) {
2041
+ function deriveDirectedFlag2(attributes, defaultDirected) {
710
2042
  const candidate = attributes.directed;
711
2043
  if (typeof candidate === "boolean") {
712
2044
  return candidate;
@@ -723,10 +2055,19 @@ function deriveDirectedFlag(attributes, defaultDirected) {
723
2055
  }
724
2056
 
725
2057
  // dist/dot-loader.js
726
- var DOTLoaderWithParser = {
727
- ...DOTLoader,
728
- parse: async (data) => parseDOT(new TextDecoder().decode(data)),
729
- parseSync: (data) => parseDOT(new TextDecoder().decode(data)),
730
- parseTextSync: parseDOT
2058
+ var DOTLoaderWithParser2 = {
2059
+ ...DOTLoader2,
2060
+ parse: async (data, options) => {
2061
+ var _a;
2062
+ return parseDOT2(new TextDecoder().decode(data), ((_a = options == null ? void 0 : options.dot) == null ? void 0 : _a.shape) ?? "arrow-table");
2063
+ },
2064
+ parseSync: (data, options) => {
2065
+ var _a;
2066
+ return parseDOT2(new TextDecoder().decode(data), ((_a = options == null ? void 0 : options.dot) == null ? void 0 : _a.shape) ?? "arrow-table");
2067
+ },
2068
+ parseTextSync: (data, options) => {
2069
+ var _a;
2070
+ return parseDOT2(data, ((_a = options == null ? void 0 : options.dot) == null ? void 0 : _a.shape) ?? "arrow-table");
2071
+ }
731
2072
  };
732
2073
  //# sourceMappingURL=dot-loader.cjs.map