@loaders.gl/graphs 4.5.3

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 (54) hide show
  1. package/LICENSE +41 -0
  2. package/README.md +66 -0
  3. package/dist/dot-loader-types.d.ts +16 -0
  4. package/dist/dot-loader-types.d.ts.map +1 -0
  5. package/dist/dot-loader-types.js +20 -0
  6. package/dist/dot-loader-types.js.map +1 -0
  7. package/dist/dot-loader.cjs +732 -0
  8. package/dist/dot-loader.cjs.map +7 -0
  9. package/dist/dot-loader.d.ts +19 -0
  10. package/dist/dot-loader.d.ts.map +1 -0
  11. package/dist/dot-loader.js +13 -0
  12. package/dist/dot-loader.js.map +1 -0
  13. package/dist/dot-types.d.ts +32 -0
  14. package/dist/dot-types.d.ts.map +1 -0
  15. package/dist/dot-types.js +5 -0
  16. package/dist/dot-types.js.map +1 -0
  17. package/dist/graph-types.d.ts +28 -0
  18. package/dist/graph-types.d.ts.map +1 -0
  19. package/dist/graph-types.js +5 -0
  20. package/dist/graph-types.js.map +1 -0
  21. package/dist/graphml-loader-types.d.ts +16 -0
  22. package/dist/graphml-loader-types.d.ts.map +1 -0
  23. package/dist/graphml-loader-types.js +20 -0
  24. package/dist/graphml-loader-types.js.map +1 -0
  25. package/dist/graphml-loader.cjs +315 -0
  26. package/dist/graphml-loader.cjs.map +7 -0
  27. package/dist/graphml-loader.d.ts +19 -0
  28. package/dist/graphml-loader.d.ts.map +1 -0
  29. package/dist/graphml-loader.js +13 -0
  30. package/dist/graphml-loader.js.map +1 -0
  31. package/dist/index.cjs +1022 -0
  32. package/dist/index.cjs.map +7 -0
  33. package/dist/index.d.ts +5 -0
  34. package/dist/index.d.ts.map +1 -0
  35. package/dist/index.js +6 -0
  36. package/dist/index.js.map +1 -0
  37. package/dist/lib/parse-dot.d.ts +4 -0
  38. package/dist/lib/parse-dot.d.ts.map +1 -0
  39. package/dist/lib/parse-dot.js +724 -0
  40. package/dist/lib/parse-dot.js.map +1 -0
  41. package/dist/lib/parse-graphml.d.ts +6 -0
  42. package/dist/lib/parse-graphml.d.ts.map +1 -0
  43. package/dist/lib/parse-graphml.js +296 -0
  44. package/dist/lib/parse-graphml.js.map +1 -0
  45. package/package.json +58 -0
  46. package/src/dot-loader-types.ts +24 -0
  47. package/src/dot-loader.ts +14 -0
  48. package/src/dot-types.ts +38 -0
  49. package/src/graph-types.ts +33 -0
  50. package/src/graphml-loader-types.ts +24 -0
  51. package/src/graphml-loader.ts +14 -0
  52. package/src/index.ts +8 -0
  53. package/src/lib/parse-dot.ts +924 -0
  54. package/src/lib/parse-graphml.ts +414 -0
@@ -0,0 +1,732 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // dist/dot-loader.js
21
+ var dot_loader_exports = {};
22
+ __export(dot_loader_exports, {
23
+ DOTLoaderWithParser: () => DOTLoaderWithParser
24
+ });
25
+ module.exports = __toCommonJS(dot_loader_exports);
26
+
27
+ // dist/dot-loader-types.js
28
+ var VERSION = true ? "4.5.3" : "latest";
29
+ var DOTLoader = {
30
+ name: "DOT",
31
+ id: "dot",
32
+ module: "graphs",
33
+ version: VERSION,
34
+ extensions: ["dot", "gv"],
35
+ mimeTypes: ["text/vnd.graphviz", "text/x-graphviz", "application/vnd.graphviz"],
36
+ text: true,
37
+ worker: false,
38
+ dataType: null,
39
+ batchType: null,
40
+ options: {}
41
+ };
42
+
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 }
49
+ }));
50
+ return {
51
+ shape: "plain-graph-data",
52
+ nodes: Array.from(parsed.nodes.values(), (node) => ({
53
+ id: node.id,
54
+ ...typeof node.attributes.label === "string" ? { label: node.attributes.label } : {},
55
+ attributes: {
56
+ ...node.attributes,
57
+ ...node.subgraphs.size ? { subgraphs: Array.from(node.subgraphs, (id) => describeSubgraph(id, parsed.subgraphs)) } : {}
58
+ }
59
+ })),
60
+ edges: parsed.edges.map((edge) => ({
61
+ id: edge.id,
62
+ sourceId: edge.sourceId,
63
+ targetId: edge.targetId,
64
+ directed: edge.directed,
65
+ ...typeof edge.attributes.label === "string" ? { label: edge.attributes.label } : {},
66
+ attributes: {
67
+ ...edge.attributes,
68
+ ...edge.subgraphs.length ? { subgraphs: edge.subgraphs.map((id) => describeSubgraph(id, parsed.subgraphs)) } : {}
69
+ }
70
+ })),
71
+ metadata: {
72
+ id: parsed.id,
73
+ directed: parsed.directed,
74
+ strict: parsed.strict,
75
+ attributes: { ...parsed.graphAttributes },
76
+ subgraphs
77
+ }
78
+ };
79
+ }
80
+ function describeSubgraph(id, descriptors) {
81
+ const subgraph = descriptors.get(id);
82
+ return {
83
+ id,
84
+ attributes: { ...subgraph.attributes },
85
+ parentId: subgraph.parentId
86
+ };
87
+ }
88
+ var DOTParser = class {
89
+ /** Tokens for DOT parsing. */
90
+ tokens;
91
+ /** Position for DOT parsing. */
92
+ position = 0;
93
+ /** Accumulated graph records and attributes. */
94
+ result = {
95
+ directed: false,
96
+ strict: false,
97
+ graphAttributes: /* @__PURE__ */ Object.create(null),
98
+ nodes: /* @__PURE__ */ new Map(),
99
+ edges: [],
100
+ subgraphs: /* @__PURE__ */ new Map()
101
+ };
102
+ /** Scopes for DOT parsing. */
103
+ scopes = [
104
+ {
105
+ nodeDefaults: /* @__PURE__ */ Object.create(null),
106
+ edgeDefaults: /* @__PURE__ */ Object.create(null),
107
+ graphAttributes: /* @__PURE__ */ Object.create(null)
108
+ }
109
+ ];
110
+ /** Subgraph counter for DOT parsing. */
111
+ subgraphCounter = 0;
112
+ /** Edge counter for DOT parsing. */
113
+ edgeCounter = 0;
114
+ /** Edge lookup used to coalesce parallel edges in strict graphs. */
115
+ strictEdges = /* @__PURE__ */ new Map();
116
+ /** Persistent attributes and defaults for reopened named subgraphs. */
117
+ subgraphScopes = /* @__PURE__ */ new Map();
118
+ /** Explicit names reserved so anonymous subgraph IDs cannot collide with them. */
119
+ namedSubgraphIds = /* @__PURE__ */ new Set();
120
+ /** Initializes the token stream. */
121
+ constructor(tokens) {
122
+ this.tokens = tokens;
123
+ for (let index = 0; index < tokens.length - 1; index++) {
124
+ if (isKeyword(tokens[index], "subgraph") && isIdentifierLike(tokens[index + 1])) {
125
+ this.namedSubgraphIds.add(tokens[index + 1].value);
126
+ }
127
+ }
128
+ }
129
+ /** Parses one complete DOT document. */
130
+ parse() {
131
+ this.parseGraph();
132
+ this.consumeOptionalSemicolon();
133
+ if (this.peek()) {
134
+ throw new Error("Unexpected content after DOT graph.");
135
+ }
136
+ return this.result;
137
+ }
138
+ /** Reads graph identity, declaration, and statements. */
139
+ parseGraph() {
140
+ const strictToken = this.peek();
141
+ if (strictToken && isKeyword(strictToken, "strict")) {
142
+ this.consume();
143
+ this.result.strict = true;
144
+ }
145
+ const typeToken = this.peek();
146
+ if (!typeToken || !isGraphType(typeToken)) {
147
+ throw new Error("DOT graph must start with graph or digraph keyword.");
148
+ }
149
+ this.consume();
150
+ this.result.directed = isKeyword(typeToken, "digraph");
151
+ const idToken = this.peek();
152
+ if (idToken && isIdentifierLike(idToken)) {
153
+ this.result.id = parseIdentifierValue(this.consume());
154
+ }
155
+ this.expect("lbrace");
156
+ while (!this.match("rbrace")) {
157
+ if (!this.parseStatement()) {
158
+ throw new Error("Expected closing brace in DOT graph.");
159
+ }
160
+ }
161
+ this.result.graphAttributes = { ...this.scopes[0].graphAttributes };
162
+ }
163
+ /** Dispatches a graph statement. */
164
+ parseStatement() {
165
+ if (this.consumeSemicolonIfPresent()) {
166
+ return true;
167
+ }
168
+ const token = this.peek();
169
+ if (!token) {
170
+ return false;
171
+ }
172
+ if (this.tryParseSubgraphStatement(token)) {
173
+ return true;
174
+ }
175
+ if (this.tryParseKeywordStatement(token)) {
176
+ return true;
177
+ }
178
+ if (this.tryParseAssignmentStatement(token)) {
179
+ return true;
180
+ }
181
+ if (isIdentifierLike(token)) {
182
+ this.parseNodeOrEdgeStatement();
183
+ this.consumeOptionalSemicolon();
184
+ return true;
185
+ }
186
+ throw new Error(`Unexpected token: ${token.value}`);
187
+ }
188
+ /** Consumes an empty statement. */
189
+ consumeSemicolonIfPresent() {
190
+ const next = this.peek();
191
+ if ((next == null ? void 0 : next.type) === "semicolon") {
192
+ this.consume();
193
+ return true;
194
+ }
195
+ return false;
196
+ }
197
+ /** Reads a standalone subgraph statement. */
198
+ tryParseSubgraphStatement(token) {
199
+ if (token.type !== "lbrace" && !isKeyword(token, "subgraph")) {
200
+ return false;
201
+ }
202
+ this.parseSubgraph();
203
+ return true;
204
+ }
205
+ /** Applies graph, node, or edge defaults. */
206
+ tryParseKeywordStatement(token) {
207
+ if (!(isKeyword(token, "graph") || isKeyword(token, "node") || isKeyword(token, "edge"))) {
208
+ return false;
209
+ }
210
+ this.consume();
211
+ const explicitAttributes = this.parseAttributeList();
212
+ if (isKeyword(token, "graph")) {
213
+ Object.assign(this.currentScope().graphAttributes, explicitAttributes);
214
+ } else if (isKeyword(token, "node")) {
215
+ Object.assign(this.currentScope().nodeDefaults, explicitAttributes);
216
+ } else {
217
+ Object.assign(this.currentScope().edgeDefaults, explicitAttributes);
218
+ }
219
+ this.consumeOptionalSemicolon();
220
+ return true;
221
+ }
222
+ /** Reads a graph attribute assignment. */
223
+ tryParseAssignmentStatement(token) {
224
+ if (!isIdentifierLike(token)) {
225
+ return false;
226
+ }
227
+ const next = this.peek(1);
228
+ if ((next == null ? void 0 : next.type) !== "equals") {
229
+ return false;
230
+ }
231
+ const key = parseIdentifierValue(this.consume());
232
+ this.consume();
233
+ const valueToken = this.consume();
234
+ const value = parseAttributeValue(valueToken);
235
+ this.currentScope().graphAttributes[key] = value;
236
+ this.consumeOptionalSemicolon();
237
+ return true;
238
+ }
239
+ /** Reads a node statement or chained edges. */
240
+ parseNodeOrEdgeStatement() {
241
+ const first = parseIdentifierValue(this.consume());
242
+ const references = [first];
243
+ const operators = [];
244
+ let operatorToken = this.match("arrow");
245
+ while (operatorToken) {
246
+ operators.push(operatorToken.value);
247
+ const referenceToken = this.consume();
248
+ if (!isIdentifierLike(referenceToken)) {
249
+ throw new Error("Expected node identifier in edge statement.");
250
+ }
251
+ references.push(parseIdentifierValue(referenceToken));
252
+ operatorToken = this.match("arrow");
253
+ }
254
+ if (operators.length === 0) {
255
+ const explicitAttributes2 = this.parseAttributeList();
256
+ this.addNode(first, explicitAttributes2);
257
+ return;
258
+ }
259
+ const explicitAttributes = this.parseAttributeList();
260
+ this.addEdgeChain(references, operators, explicitAttributes);
261
+ }
262
+ /** Merges explicit attributes into a node. */
263
+ addNode(id, explicitAttributes) {
264
+ const membership = this.getCurrentSubgraphChain();
265
+ const node = this.ensureNode(id, membership);
266
+ node.attributes = { ...node.attributes, ...explicitAttributes };
267
+ }
268
+ /** Expands an edge chain into node and edge records. */
269
+ addEdgeChain(nodes, operators, explicitAttributes) {
270
+ const membership = this.getCurrentSubgraphChain();
271
+ const defaults = this.currentScope().edgeDefaults;
272
+ const attributes = { ...defaults, ...explicitAttributes };
273
+ for (let index = 0; index < nodes.length - 1; index++) {
274
+ const sourceId = nodes[index];
275
+ const targetId = nodes[index + 1];
276
+ const operator = operators[index];
277
+ const directed = operator === "->";
278
+ if (directed !== this.result.directed) {
279
+ throw new Error("DOT edge operator must match graph or digraph declaration.");
280
+ }
281
+ const edgeId = deriveEdgeId(attributes, sourceId, targetId, ++this.edgeCounter);
282
+ const edgeAttributes = { ...attributes };
283
+ this.ensureNode(sourceId, membership);
284
+ this.ensureNode(targetId, membership);
285
+ const strictKey = JSON.stringify(directed ? [sourceId, targetId] : [sourceId, targetId].sort());
286
+ const existingEdge = this.result.strict ? this.strictEdges.get(strictKey) : void 0;
287
+ if (existingEdge) {
288
+ existingEdge.attributes = { ...existingEdge.attributes, ...explicitAttributes };
289
+ existingEdge.directed = deriveDirectedFlag(existingEdge.attributes, directed);
290
+ existingEdge.subgraphs = Array.from(/* @__PURE__ */ new Set([...existingEdge.subgraphs, ...membership]));
291
+ continue;
292
+ }
293
+ const directedOverride = deriveDirectedFlag(edgeAttributes, directed);
294
+ const edge = {
295
+ id: edgeId,
296
+ sourceId,
297
+ targetId,
298
+ directed: directedOverride,
299
+ attributes: edgeAttributes,
300
+ subgraphs: membership
301
+ };
302
+ this.result.edges.push(edge);
303
+ if (this.result.strict) {
304
+ this.strictEdges.set(strictKey, edge);
305
+ }
306
+ }
307
+ }
308
+ /** Reads a nested scope with inherited defaults. */
309
+ parseSubgraph() {
310
+ let idToken = this.peek();
311
+ let subgraphId;
312
+ if (idToken && isKeyword(idToken, "subgraph")) {
313
+ this.consume();
314
+ idToken = this.peek();
315
+ }
316
+ if (idToken && isIdentifierLike(idToken)) {
317
+ subgraphId = parseIdentifierValue(this.consume());
318
+ } else {
319
+ do {
320
+ subgraphId = `subgraph_${++this.subgraphCounter}`;
321
+ } while (this.namedSubgraphIds.has(subgraphId));
322
+ }
323
+ this.expect("lbrace");
324
+ const parentId = this.findCurrentSubgraphId();
325
+ let context = this.subgraphScopes.get(subgraphId);
326
+ if (!context) {
327
+ context = {
328
+ id: subgraphId,
329
+ nodeDefaults: Object.assign(/* @__PURE__ */ Object.create(null), this.currentScope().nodeDefaults),
330
+ edgeDefaults: Object.assign(/* @__PURE__ */ Object.create(null), this.currentScope().edgeDefaults),
331
+ graphAttributes: /* @__PURE__ */ Object.create(null)
332
+ };
333
+ this.subgraphScopes.set(subgraphId, context);
334
+ this.result.subgraphs.set(subgraphId, {
335
+ id: subgraphId,
336
+ attributes: context.graphAttributes,
337
+ parentId
338
+ });
339
+ }
340
+ this.scopes.push(context);
341
+ let shouldContinue = true;
342
+ while (shouldContinue) {
343
+ if (this.match("rbrace")) {
344
+ break;
345
+ }
346
+ shouldContinue = this.parseStatement();
347
+ if (!shouldContinue) {
348
+ throw new Error("Expected closing brace in DOT subgraph.");
349
+ }
350
+ }
351
+ this.scopes.pop();
352
+ }
353
+ /** Reads repeated attribute lists. */
354
+ parseAttributeList() {
355
+ var _a, _b;
356
+ const attributes = /* @__PURE__ */ Object.create(null);
357
+ while (this.match("lbrack")) {
358
+ while (!this.match("rbrack")) {
359
+ const keyToken = this.consume();
360
+ if (!isIdentifierLike(keyToken)) {
361
+ throw new Error("Expected attribute name.");
362
+ }
363
+ const key = parseIdentifierValue(keyToken);
364
+ let value = true;
365
+ if (this.match("equals")) {
366
+ const valueToken = this.consume();
367
+ value = parseAttributeValue(valueToken);
368
+ }
369
+ attributes[key] = value;
370
+ if (((_a = this.peek()) == null ? void 0 : _a.type) === "comma" || ((_b = this.peek()) == null ? void 0 : _b.type) === "semicolon") {
371
+ this.consume();
372
+ }
373
+ }
374
+ }
375
+ return attributes;
376
+ }
377
+ /** Creates an implicit node and records its subgraph memberships. */
378
+ ensureNode(id, membership) {
379
+ let node = this.result.nodes.get(id);
380
+ if (!node) {
381
+ const defaults = this.currentScope().nodeDefaults;
382
+ node = { id, attributes: { ...defaults }, subgraphs: /* @__PURE__ */ new Set() };
383
+ this.result.nodes.set(id, node);
384
+ }
385
+ membership.forEach((subgraphId) => node.subgraphs.add(subgraphId));
386
+ return node;
387
+ }
388
+ /** Lists enclosing subgraphs. */
389
+ getCurrentSubgraphChain() {
390
+ const chain = [];
391
+ for (const scope of this.scopes) {
392
+ if (scope.id) {
393
+ chain.push(scope.id);
394
+ }
395
+ }
396
+ return chain;
397
+ }
398
+ /** Finds the nearest enclosing named or generated subgraph. */
399
+ findCurrentSubgraphId() {
400
+ for (let index = this.scopes.length - 1; index >= 0; index--) {
401
+ const scope = this.scopes[index];
402
+ if (scope.id) {
403
+ return scope.id;
404
+ }
405
+ }
406
+ return void 0;
407
+ }
408
+ /** Returns the active attribute scope. */
409
+ currentScope() {
410
+ return this.scopes[this.scopes.length - 1];
411
+ }
412
+ /** Consumes an optional statement terminator. */
413
+ consumeOptionalSemicolon() {
414
+ const next = this.peek();
415
+ if ((next == null ? void 0 : next.type) === "semicolon") {
416
+ this.consume();
417
+ }
418
+ }
419
+ /** Requires the next token to have the requested type. */
420
+ expect(type) {
421
+ const token = this.consume();
422
+ if (!token || token.type !== type) {
423
+ throw new Error(`Expected token ${type}.`);
424
+ }
425
+ return token;
426
+ }
427
+ /** Consumes the next token or reports truncated input. */
428
+ consume() {
429
+ const token = this.tokens[this.position];
430
+ if (!token) {
431
+ throw new Error("Unexpected end of DOT input.");
432
+ }
433
+ this.position++;
434
+ return token;
435
+ }
436
+ /** Consumes a token when its type matches. */
437
+ match(type) {
438
+ const token = this.peek();
439
+ if (token && token.type === type) {
440
+ this.position++;
441
+ return token;
442
+ }
443
+ return null;
444
+ }
445
+ /** Inspects a token without consuming it. */
446
+ peek(offset = 0) {
447
+ return this.tokens[this.position + offset] ?? null;
448
+ }
449
+ };
450
+ function parseDOTDocument(input) {
451
+ const parser = new DOTParser(tokenize(input));
452
+ return parser.parse();
453
+ }
454
+ var IDENTIFIER_TERMINATORS = /* @__PURE__ */ new Set(["{", "}", "[", "]", "=", ";", ",", '"', "<", "#"]);
455
+ function tokenize(input) {
456
+ const tokens = [];
457
+ let index = 0;
458
+ while (index < input.length) {
459
+ const { token, nextIndex } = readNextToken(input, index);
460
+ if (nextIndex <= index) {
461
+ throw new Error(`Tokenizer did not advance at position ${index}.`);
462
+ }
463
+ if (token) {
464
+ tokens.push(token);
465
+ }
466
+ index = nextIndex;
467
+ }
468
+ return tokens;
469
+ }
470
+ function readNextToken(input, index) {
471
+ if (index >= input.length) {
472
+ return { token: null, nextIndex: input.length };
473
+ }
474
+ const character = input[index];
475
+ if (isWhitespace(character)) {
476
+ return { token: null, nextIndex: index + 1 };
477
+ }
478
+ const commentEnd = skipComment(input, index);
479
+ if (commentEnd !== null) {
480
+ return { token: null, nextIndex: commentEnd };
481
+ }
482
+ const arrowToken = readArrowToken(input, index);
483
+ if (arrowToken) {
484
+ return arrowToken;
485
+ }
486
+ const punctuation = readPunctuationToken(character);
487
+ if (punctuation) {
488
+ return { token: punctuation, nextIndex: index + 1 };
489
+ }
490
+ if (character === '"') {
491
+ const { value, nextIndex } = readQuotedString(input, index + 1);
492
+ return { token: { type: "string", value }, nextIndex };
493
+ }
494
+ if (character === "<") {
495
+ const { value, nextIndex } = readHtmlString(input, index + 1);
496
+ return { token: { type: "html", value }, nextIndex };
497
+ }
498
+ const identifier = readIdentifier(input, index);
499
+ if (identifier.value) {
500
+ return {
501
+ token: { type: "identifier", value: identifier.value },
502
+ nextIndex: identifier.nextIndex
503
+ };
504
+ }
505
+ throw new Error(`Unexpected token at position ${index}.`);
506
+ }
507
+ function skipComment(input, index) {
508
+ const character = input[index];
509
+ if (character === "/") {
510
+ const next = input[index + 1];
511
+ if (next === "/") {
512
+ return skipLineComment(input, index + 2);
513
+ }
514
+ if (next === "*") {
515
+ return skipBlockComment(input, index + 2);
516
+ }
517
+ return null;
518
+ }
519
+ if (character === "#") {
520
+ return skipLineComment(input, index + 1);
521
+ }
522
+ return null;
523
+ }
524
+ function skipLineComment(input, startIndex) {
525
+ let cursor = startIndex;
526
+ while (cursor < input.length && !isLineBreak(input[cursor])) {
527
+ cursor++;
528
+ }
529
+ return cursor;
530
+ }
531
+ function skipBlockComment(input, startIndex) {
532
+ let cursor = startIndex;
533
+ while (cursor < input.length) {
534
+ if (input[cursor] === "*" && input[cursor + 1] === "/") {
535
+ return cursor + 2;
536
+ }
537
+ cursor++;
538
+ }
539
+ throw new Error("Unterminated block comment in DOT source.");
540
+ }
541
+ function readArrowToken(input, index) {
542
+ const next = input[index + 1];
543
+ if (input[index] === "-" && next === "-") {
544
+ return { token: { type: "arrow", value: "--" }, nextIndex: index + 2 };
545
+ }
546
+ if (input[index] === "-" && next === ">") {
547
+ return { token: { type: "arrow", value: "->" }, nextIndex: index + 2 };
548
+ }
549
+ return null;
550
+ }
551
+ function readPunctuationToken(character) {
552
+ switch (character) {
553
+ case "{":
554
+ return { type: "lbrace", value: character };
555
+ case "}":
556
+ return { type: "rbrace", value: character };
557
+ case "[":
558
+ return { type: "lbrack", value: character };
559
+ case "]":
560
+ return { type: "rbrack", value: character };
561
+ case "=":
562
+ return { type: "equals", value: character };
563
+ case ",":
564
+ return { type: "comma", value: character };
565
+ case ";":
566
+ return { type: "semicolon", value: character };
567
+ default:
568
+ return null;
569
+ }
570
+ }
571
+ function readQuotedString(input, startIndex) {
572
+ let value = "";
573
+ let index = startIndex;
574
+ while (index < input.length) {
575
+ const character = input[index];
576
+ if (character === '"') {
577
+ return { value, nextIndex: index + 1 };
578
+ }
579
+ if (character === "\\") {
580
+ const escape = readEscapedCharacter(input, index + 1);
581
+ value += escape.value;
582
+ index = escape.nextIndex;
583
+ } else {
584
+ value += character;
585
+ index++;
586
+ }
587
+ }
588
+ throw new Error("Unterminated string literal in DOT source.");
589
+ }
590
+ function readEscapedCharacter(input, startIndex) {
591
+ const next = input[startIndex];
592
+ switch (next) {
593
+ case "n":
594
+ case "l":
595
+ case "L":
596
+ return { value: "\n", nextIndex: startIndex + 1 };
597
+ case "t":
598
+ return { value: " ", nextIndex: startIndex + 1 };
599
+ case "r":
600
+ return { value: "\r", nextIndex: startIndex + 1 };
601
+ case '"':
602
+ return { value: '"', nextIndex: startIndex + 1 };
603
+ case "\\":
604
+ return { value: "\\", nextIndex: startIndex + 1 };
605
+ default: {
606
+ if (typeof next === "undefined") {
607
+ throw new Error("Unterminated escape sequence in DOT source.");
608
+ }
609
+ return { value: next, nextIndex: startIndex + 1 };
610
+ }
611
+ }
612
+ }
613
+ function readHtmlString(input, startIndex) {
614
+ let value = "<";
615
+ let depth = 1;
616
+ let index = startIndex;
617
+ while (index < input.length) {
618
+ const character = input[index];
619
+ value += character;
620
+ if (character === "<") {
621
+ depth++;
622
+ } else if (character === ">") {
623
+ depth--;
624
+ if (depth === 0) {
625
+ return { value, nextIndex: index + 1 };
626
+ }
627
+ }
628
+ index++;
629
+ }
630
+ throw new Error("Unterminated HTML-like string literal in DOT source.");
631
+ }
632
+ function readIdentifier(input, startIndex) {
633
+ let index = startIndex;
634
+ let value = "";
635
+ while (index < input.length && !isIdentifierTerminator(input, index)) {
636
+ value += input[index];
637
+ index++;
638
+ }
639
+ if (value.includes(":")) {
640
+ throw new Error("DOT node ports are not supported; quote identifiers containing colons.");
641
+ }
642
+ return { value, nextIndex: index };
643
+ }
644
+ function isIdentifierTerminator(input, index) {
645
+ const character = input[index];
646
+ if (isWhitespace(character) || IDENTIFIER_TERMINATORS.has(character)) {
647
+ return true;
648
+ }
649
+ if (isArrowOperatorStart(input, index)) {
650
+ return true;
651
+ }
652
+ if (isCommentStart(input, index)) {
653
+ return true;
654
+ }
655
+ return false;
656
+ }
657
+ function isArrowOperatorStart(input, index) {
658
+ if (input[index] !== "-") {
659
+ return false;
660
+ }
661
+ const next = input[index + 1];
662
+ return next === "-" || next === ">";
663
+ }
664
+ function isCommentStart(input, index) {
665
+ if (input[index] !== "/") {
666
+ return false;
667
+ }
668
+ const next = input[index + 1];
669
+ return next === "/" || next === "*";
670
+ }
671
+ function isWhitespace(character) {
672
+ return character === " " || character === "\n" || character === "\r" || character === " " || character === "\f";
673
+ }
674
+ function isLineBreak(character) {
675
+ return character === "\n" || character === "\r";
676
+ }
677
+ function isKeyword(token, keyword) {
678
+ return token.type === "identifier" && token.value.toLowerCase() === keyword.toLowerCase();
679
+ }
680
+ function isGraphType(token) {
681
+ return isKeyword(token, "graph") || isKeyword(token, "digraph");
682
+ }
683
+ function isIdentifierLike(token) {
684
+ return token.type === "identifier" || token.type === "string" || token.type === "html";
685
+ }
686
+ function parseIdentifierValue(token) {
687
+ return token.value;
688
+ }
689
+ function parseAttributeValue(token) {
690
+ if (token.type === "string" || token.type === "html") {
691
+ return token.value;
692
+ }
693
+ if (token.type === "identifier") {
694
+ const numeric = Number(token.value);
695
+ if (!Number.isNaN(numeric)) {
696
+ return numeric;
697
+ }
698
+ return token.value;
699
+ }
700
+ throw new Error("Invalid attribute value in DOT input.");
701
+ }
702
+ function deriveEdgeId(attributes, sourceId, targetId, counter) {
703
+ const candidate = attributes.id ?? attributes.Id ?? attributes.ID;
704
+ if (typeof candidate === "string" || typeof candidate === "number") {
705
+ return String(candidate);
706
+ }
707
+ return `${String(sourceId)}-${String(targetId)}-${counter}`;
708
+ }
709
+ function deriveDirectedFlag(attributes, defaultDirected) {
710
+ const candidate = attributes.directed;
711
+ if (typeof candidate === "boolean") {
712
+ return candidate;
713
+ }
714
+ const directionAttribute = attributes.dir;
715
+ if (typeof directionAttribute === "string") {
716
+ const normalized = directionAttribute.toLowerCase();
717
+ if (normalized === "none") {
718
+ return false;
719
+ }
720
+ return true;
721
+ }
722
+ return defaultDirected;
723
+ }
724
+
725
+ // 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
731
+ };
732
+ //# sourceMappingURL=dot-loader.cjs.map