@loaders.gl/graphs 5.0.0-alpha.9 → 5.0.0-beta.1

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 (78) hide show
  1. package/LICENSE +24 -0
  2. package/README.md +121 -4
  3. package/THIRD-PARTY-NOTICES.md +17 -0
  4. package/dist/dot-loader-types.d.ts +25 -8
  5. package/dist/dot-loader-types.d.ts.map +1 -1
  6. package/dist/dot-loader-types.js +2 -2
  7. package/dist/dot-loader-types.js.map +1 -1
  8. package/dist/dot-loader.cjs +638 -47
  9. package/dist/dot-loader.cjs.map +3 -3
  10. package/dist/dot-loader.d.ts +10 -6
  11. package/dist/dot-loader.d.ts.map +1 -1
  12. package/dist/dot-loader.js +3 -3
  13. package/dist/dot-loader.js.map +1 -1
  14. package/dist/dot-types.d.ts +6 -1
  15. package/dist/dot-types.d.ts.map +1 -1
  16. package/dist/gexf-loader-types.d.ts +53 -0
  17. package/dist/gexf-loader-types.d.ts.map +1 -0
  18. package/dist/gexf-loader-types.js +26 -0
  19. package/dist/gexf-loader-types.js.map +1 -0
  20. package/dist/gexf-loader.cjs +1304 -0
  21. package/dist/gexf-loader.cjs.map +6 -0
  22. package/dist/gexf-loader.d.ts +24 -0
  23. package/dist/gexf-loader.d.ts.map +1 -0
  24. package/dist/gexf-loader.js +13 -0
  25. package/dist/gexf-loader.js.map +1 -0
  26. package/dist/gexf-types.d.ts +16 -0
  27. package/dist/gexf-types.d.ts.map +1 -0
  28. package/dist/gexf-types.js +5 -0
  29. package/dist/gexf-types.js.map +1 -0
  30. package/dist/graph-types.d.ts +28 -0
  31. package/dist/graph-types.d.ts.map +1 -1
  32. package/dist/graphml-loader-types.d.ts +24 -8
  33. package/dist/graphml-loader-types.d.ts.map +1 -1
  34. package/dist/graphml-loader-types.js +2 -2
  35. package/dist/graphml-loader-types.js.map +1 -1
  36. package/dist/graphml-loader.cjs +670 -60
  37. package/dist/graphml-loader.cjs.map +3 -3
  38. package/dist/graphml-loader.d.ts +10 -6
  39. package/dist/graphml-loader.d.ts.map +1 -1
  40. package/dist/graphml-loader.js +3 -3
  41. package/dist/graphml-loader.js.map +1 -1
  42. package/dist/index.cjs +927 -59
  43. package/dist/index.cjs.map +3 -3
  44. package/dist/index.d.ts +7 -0
  45. package/dist/index.d.ts.map +1 -1
  46. package/dist/index.js +1 -0
  47. package/dist/index.js.map +1 -1
  48. package/dist/lib/build-graph-tables.d.ts +4 -0
  49. package/dist/lib/build-graph-tables.d.ts.map +1 -0
  50. package/dist/lib/build-graph-tables.js +143 -0
  51. package/dist/lib/build-graph-tables.js.map +1 -0
  52. package/dist/lib/parse-dot.d.ts +3 -1
  53. package/dist/lib/parse-dot.d.ts.map +1 -1
  54. package/dist/lib/parse-dot.js +38 -21
  55. package/dist/lib/parse-dot.js.map +1 -1
  56. package/dist/lib/parse-gexf.d.ts +5 -0
  57. package/dist/lib/parse-gexf.d.ts.map +1 -0
  58. package/dist/lib/parse-gexf.js +380 -0
  59. package/dist/lib/parse-gexf.js.map +1 -0
  60. package/dist/lib/parse-graphml.d.ts +2 -1
  61. package/dist/lib/parse-graphml.d.ts.map +1 -1
  62. package/dist/lib/parse-graphml.js +50 -27
  63. package/dist/lib/parse-graphml.js.map +1 -1
  64. package/package.json +13 -5
  65. package/src/dot-loader-types.ts +15 -5
  66. package/src/dot-loader.ts +7 -4
  67. package/src/dot-types.ts +7 -1
  68. package/src/gexf-loader-types.ts +41 -0
  69. package/src/gexf-loader.ts +17 -0
  70. package/src/gexf-types.ts +21 -0
  71. package/src/graph-types.ts +35 -0
  72. package/src/graphml-loader-types.ts +14 -5
  73. package/src/graphml-loader.ts +7 -4
  74. package/src/index.ts +9 -0
  75. package/src/lib/build-graph-tables.ts +208 -0
  76. package/src/lib/parse-dot.ts +44 -21
  77. package/src/lib/parse-gexf.ts +388 -0
  78. package/src/lib/parse-graphml.ts +86 -34
@@ -0,0 +1,1304 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
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
+ };
16
+ var __export = (target, all) => {
17
+ for (var name in all)
18
+ __defProp(target, name, { get: all[name], enumerable: true });
19
+ };
20
+ var __copyProps = (to, from, except, desc) => {
21
+ if (from && typeof from === "object" || typeof from === "function") {
22
+ for (let key of __getOwnPropNames(from))
23
+ if (!__hasOwnProp.call(to, key) && key !== except)
24
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
25
+ }
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/gexf-loader-types.ts
39
+ async function preload() {
40
+ const { GEXFLoaderWithParser: GEXFLoaderWithParser3 } = await Promise.resolve().then(() => (init_gexf_loader(), gexf_loader_exports));
41
+ return GEXFLoaderWithParser3;
42
+ }
43
+ var VERSION, GEXFLoader;
44
+ var init_gexf_loader_types = __esm({
45
+ "src/gexf-loader-types.ts"() {
46
+ "use strict";
47
+ VERSION = typeof __VERSION__ !== "undefined" ? __VERSION__ : "latest";
48
+ GEXFLoader = {
49
+ name: "GEXF",
50
+ id: "gexf",
51
+ module: "graphs",
52
+ version: VERSION,
53
+ extensions: ["gexf"],
54
+ mimeTypes: ["application/gexf+xml"],
55
+ text: true,
56
+ worker: false,
57
+ dataType: null,
58
+ batchType: null,
59
+ options: { gexf: { shape: "arrow-table" } },
60
+ preload
61
+ };
62
+ }
63
+ });
64
+
65
+ // ../core/src/schema-utils/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
+ "../core/src/schema-utils/lib/schema/convert-arrow-schema.ts"() {
320
+ "use strict";
321
+ arrow = __toESM(require("apache-arrow"), 1);
322
+ }
323
+ });
324
+
325
+ // ../core/src/schema-utils/index.ts
326
+ var init_schema_utils = __esm({
327
+ "../core/src/schema-utils/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_schema_utils();
475
+ }
476
+ });
477
+
478
+ // src/lib/parse-gexf.ts
479
+ function parseGEXF(input, shape = "arrow-table") {
480
+ const text = typeof input === "string" ? input : new TextDecoder().decode(input);
481
+ const validation = import_fast_xml_parser.XMLValidator.validate(text);
482
+ if (validation !== true) throw new Error(`Invalid GEXF XML: ${validation.err.msg}`);
483
+ if (/<!DOCTYPE\s/i.test(text)) throw new Error("GEXF document types are unsupported.");
484
+ const document = normalizeNamespaces(parser.parse(text), {});
485
+ const root = getElement(document.gexf, "gexf");
486
+ const version = root["@_version"];
487
+ if (version && !["1.2", "1.2draft", "1.3"].includes(version)) {
488
+ throw new Error(`Unsupported GEXF version: ${version}`);
489
+ }
490
+ const graph = getElement(root.graph, "graph");
491
+ const directed = parseDirection(graph["@_defaultedgetype"] ?? "undirected");
492
+ const definitions = {
493
+ nodes: /* @__PURE__ */ new Map(),
494
+ edges: /* @__PURE__ */ new Map()
495
+ };
496
+ for (const attributes of getElements(graph.attributes)) {
497
+ const domain = attributes["@_class"];
498
+ if (domain !== "node" && domain !== "edge")
499
+ throw new Error("GEXF attributes require a node or edge class.");
500
+ const scoped = domain === "node" ? definitions.nodes : definitions.edges;
501
+ const names = new Set(Array.from(scoped.values(), (definition) => definition.name));
502
+ for (const attribute of getElements(attributes.attribute)) {
503
+ const identifier = requireAttribute(attribute, "id");
504
+ const name = requireAttribute(attribute, "title");
505
+ if (name === "gexf" || names.has(name) || scoped.has(identifier)) {
506
+ throw new Error(`Duplicate or reserved GEXF attribute: ${name}`);
507
+ }
508
+ names.add(name);
509
+ const type = parseAttributeType(requireAttribute(attribute, "type"));
510
+ scoped.set(identifier, {
511
+ name,
512
+ type,
513
+ defaultValue: attribute.default === void 0 ? void 0 : castValue(readTextContent(attribute.default), type)
514
+ });
515
+ }
516
+ }
517
+ const nodeElements = getElements(getContainer(graph.nodes).node);
518
+ const edgeElements = getElements(getContainer(graph.edges).edge);
519
+ const nodeIdentifiers = /* @__PURE__ */ new Set();
520
+ for (const node of nodeElements) {
521
+ const identifier = requireAttribute(node, "id");
522
+ if (nodeIdentifiers.has(identifier)) throw new Error(`Duplicate GEXF node ID: ${identifier}`);
523
+ nodeIdentifiers.add(identifier);
524
+ }
525
+ const edgeIdentifiers = new Set(
526
+ edgeElements.map((edge) => edge["@_id"]).filter((identifier) => typeof identifier === "string")
527
+ );
528
+ const seenEdges = /* @__PURE__ */ new Set();
529
+ function* iterateNodes() {
530
+ for (const node of nodeElements) yield parseRecord(node, definitions.nodes);
531
+ }
532
+ function* iterateEdges() {
533
+ for (const [index, edge] of edgeElements.entries()) {
534
+ const sourceId = requireAttribute(edge, "source");
535
+ const targetId = requireAttribute(edge, "target");
536
+ if (!nodeIdentifiers.has(sourceId) || !nodeIdentifiers.has(targetId)) {
537
+ throw new Error("GEXF edge references an undeclared node.");
538
+ }
539
+ let identifier = edge["@_id"] === void 0 ? void 0 : requireAttribute(edge, "id");
540
+ if (identifier === void 0) {
541
+ identifier = `edge-${index}`;
542
+ while (edgeIdentifiers.has(identifier)) identifier = `_${identifier}`;
543
+ edgeIdentifiers.add(identifier);
544
+ }
545
+ if (seenEdges.has(identifier)) throw new Error(`Duplicate GEXF edge ID: ${identifier}`);
546
+ seenEdges.add(identifier);
547
+ yield {
548
+ ...parseRecord(edge, definitions.edges, identifier),
549
+ sourceId,
550
+ targetId,
551
+ directed: edge["@_type"] === void 0 ? directed : parseDirection(edge["@_type"])
552
+ };
553
+ }
554
+ }
555
+ const metadataAttributes = /* @__PURE__ */ Object.create(null);
556
+ const meta = getContainer(root.meta);
557
+ for (const name of ["creator", "description", "keywords"]) {
558
+ if (meta[name] !== void 0) metadataAttributes[name] = readTextContent(meta[name]);
559
+ }
560
+ if (typeof meta["@_lastmodifieddate"] === "string")
561
+ metadataAttributes.lastmodifieddate = meta["@_lastmodifieddate"];
562
+ const declarations = {
563
+ nodes: new Map(
564
+ Array.from(definitions.nodes.values(), (definition) => [definition.name, definition.type])
565
+ ),
566
+ edges: new Map(
567
+ Array.from(definitions.edges.values(), (definition) => [definition.name, definition.type])
568
+ )
569
+ };
570
+ return {
571
+ ...buildGraphTables(iterateNodes(), iterateEdges(), shape, declarations),
572
+ metadata: { version, directed, attributes: metadataAttributes }
573
+ };
574
+ }
575
+ function normalizeNamespaces(element, inherited) {
576
+ const namespaces = Object.assign(/* @__PURE__ */ Object.create(null), inherited);
577
+ for (const [name, value] of Object.entries(element)) {
578
+ if (name === "@_xmlns") namespaces[""] = String(value);
579
+ else if (name.startsWith("@_xmlns:")) namespaces[name.slice(8)] = String(value);
580
+ }
581
+ const normalized = /* @__PURE__ */ Object.create(null);
582
+ for (const [name, value] of Object.entries(element)) {
583
+ if (name.startsWith("@_") || name === "#text" || name.startsWith("?")) {
584
+ normalized[name] = value;
585
+ continue;
586
+ }
587
+ const separator = name.indexOf(":");
588
+ const prefix = separator < 0 ? "" : name.slice(0, separator);
589
+ const localName = name.slice(separator + 1);
590
+ const children = Array.isArray(value) ? value : [value];
591
+ for (const child of children) {
592
+ const object = typeof child === "object" && child !== null ? child : {};
593
+ const namespace = object[prefix ? `@_xmlns:${prefix}` : "@_xmlns"] ?? namespaces[prefix];
594
+ const match = typeof namespace === "string" ? GEXF_NAMESPACE.exec(namespace) : null;
595
+ const key = match ? `${match[1] ? "viz:" : ""}${localName}` : namespace || prefix ? `foreign:${name}` : localName;
596
+ const childValue = typeof child === "object" && child !== null ? match || !namespace && !prefix ? normalizeNamespaces(object, namespaces) : object : child;
597
+ if (normalized[key] === void 0) normalized[key] = childValue;
598
+ else
599
+ normalized[key] = [
600
+ ...Array.isArray(normalized[key]) ? normalized[key] : [normalized[key]],
601
+ childValue
602
+ ];
603
+ }
604
+ }
605
+ assertStaticElement(normalized);
606
+ return normalized;
607
+ }
608
+ function assertStaticElement(element) {
609
+ if (element["@_mode"] !== void 0 && element["@_mode"] !== "static" || TEMPORAL_ATTRIBUTES.some((name) => element[`@_${name}`] !== void 0) || element.spells !== void 0) {
610
+ throw new Error("Dynamic GEXF graphs and temporal values are unsupported.");
611
+ }
612
+ if (element["@_pid"] !== void 0 || element.parents !== void 0 || element["@_id"] !== void 0 && (element.nodes !== void 0 || element.edges !== void 0)) {
613
+ throw new Error("Hierarchical GEXF graphs are unsupported.");
614
+ }
615
+ }
616
+ function getElement(value, name) {
617
+ if (value === "") return {};
618
+ if (value && typeof value === "object" && !Array.isArray(value)) return value;
619
+ throw new Error(`GEXF requires one <${name}> element.`);
620
+ }
621
+ function readTextContent(value) {
622
+ if (typeof value === "string") return value;
623
+ const text = getElement(value, "text")["#text"];
624
+ return typeof text === "string" ? text : "";
625
+ }
626
+ function getContainer(value) {
627
+ return value === void 0 ? {} : getElement(value, "container");
628
+ }
629
+ function getElements(value) {
630
+ if (value === void 0) return [];
631
+ return (Array.isArray(value) ? value : [value]).map((entry) => getElement(entry, "record"));
632
+ }
633
+ function requireAttribute(element, name) {
634
+ const value = element[`@_${name}`];
635
+ if (typeof value !== "string" || value === "")
636
+ throw new Error(`GEXF requires a ${name} attribute.`);
637
+ return value;
638
+ }
639
+ function parseDirection(value) {
640
+ if (value !== "directed" && value !== "undirected")
641
+ throw new Error(`Unsupported GEXF edge type: ${String(value)}`);
642
+ return value === "directed";
643
+ }
644
+ function parseAttributeType(value) {
645
+ if (value.startsWith("list") && !value.slice(4).startsWith("list")) {
646
+ return { list: parseAttributeType(value.slice(4)) };
647
+ }
648
+ if (value === "integer" || value === "byte" || value === "short") return "int";
649
+ if (value === "boolean" || value === "long" || value === "float" || value === "double")
650
+ return value;
651
+ if (["string", "anyURI", "date", "char", "bigdecimal", "biginteger"].includes(value))
652
+ return "string";
653
+ throw new Error(`Unsupported GEXF attribute type: ${value}`);
654
+ }
655
+ function castValue(text, type) {
656
+ if (typeof type === "object") {
657
+ return parseListValues(text).map((value) => castValue(value, type.list));
658
+ }
659
+ if (type === "string") return text;
660
+ const trimmed = text.trim();
661
+ if (type === "boolean") {
662
+ if (trimmed === "true" || trimmed === "1") return true;
663
+ if (trimmed === "false" || trimmed === "0") return false;
664
+ return text;
665
+ }
666
+ if (type === "int" || type === "long") {
667
+ if (!/^[+-]?\d+$/.test(trimmed)) return text;
668
+ return type === "long" ? BigInt(trimmed) : Number.isSafeInteger(Number(trimmed)) ? Number(trimmed) : text;
669
+ }
670
+ if (trimmed === "INF") return Infinity;
671
+ if (trimmed === "-INF") return -Infinity;
672
+ if (trimmed === "NaN") return NaN;
673
+ if (!/^[+-]?(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?$/.test(trimmed)) return text;
674
+ const number = Number(trimmed);
675
+ const represented = type === "float" ? Math.fround(number) : number;
676
+ const nonzero = /[1-9]/.test(trimmed.split(/[eE]/)[0]);
677
+ return Number.isFinite(represented) && (represented !== 0 || !nonzero) ? number : text;
678
+ }
679
+ function parseListValues(text) {
680
+ const trimmed = text.trim();
681
+ const bracketed = trimmed.startsWith("[");
682
+ if (bracketed !== trimmed.endsWith("]")) throw new Error("Invalid GEXF list brackets.");
683
+ const contents = bracketed ? trimmed.slice(1, -1) : trimmed;
684
+ if (!contents.trim()) return [];
685
+ const values = [];
686
+ let value = "";
687
+ let quote = "";
688
+ let quoted = false;
689
+ let closed = false;
690
+ for (let index = 0; index < contents.length; index++) {
691
+ const character = contents[index];
692
+ if (quote) {
693
+ if (character === "\\" && (contents[index + 1] === quote || contents[index + 1] === "\\")) {
694
+ value += contents[++index];
695
+ } else if (character === quote) {
696
+ quote = "";
697
+ closed = true;
698
+ } else value += character;
699
+ } else if (character === "," || !bracketed && (character === "|" || character === ";")) {
700
+ values.push(quoted ? value : value.trim());
701
+ value = "";
702
+ quoted = false;
703
+ closed = false;
704
+ } else if (closed) {
705
+ if (character.trim()) throw new Error("Invalid GEXF list text after a quote.");
706
+ } else if ((character === "'" || character === '"') && !value.trim()) {
707
+ quote = character;
708
+ quoted = true;
709
+ value = "";
710
+ } else value += character;
711
+ }
712
+ if (quote) throw new Error("Unterminated GEXF list quote.");
713
+ values.push(quoted ? value : value.trim());
714
+ return values;
715
+ }
716
+ function parseRecord(element, definitions, identifier) {
717
+ const attributes = /* @__PURE__ */ Object.create(null);
718
+ for (const definition of definitions.values()) {
719
+ if (definition.defaultValue !== void 0)
720
+ attributes[definition.name] = Array.isArray(definition.defaultValue) ? [...definition.defaultValue] : definition.defaultValue;
721
+ }
722
+ for (const attvalue of getElements(getContainer(element.attvalues).attvalue)) {
723
+ const key = requireAttribute(attvalue, "for");
724
+ const definition = definitions.get(key);
725
+ if (!definition) throw new Error(`Undeclared GEXF attribute: ${key}`);
726
+ attributes[definition.name] = castValue(requireValue(attvalue), definition.type);
727
+ }
728
+ const native = /* @__PURE__ */ Object.create(null);
729
+ if (element["@_weight"] !== void 0)
730
+ native.weight = castValue(String(element["@_weight"]), "double");
731
+ if (element["@_kind"] !== void 0) native.kind = element["@_kind"];
732
+ const visualization = /* @__PURE__ */ Object.create(null);
733
+ for (const name of ["color", "position", "size", "shape", "thickness"]) {
734
+ const value = element[`viz:${name}`];
735
+ if (value === void 0) continue;
736
+ const properties = /* @__PURE__ */ Object.create(null);
737
+ for (const [key, property] of Object.entries(getElement(value, `viz:${name}`))) {
738
+ if (key.startsWith("@_") && !key.startsWith("@_xmlns")) {
739
+ const propertyName = key.slice(2);
740
+ properties[propertyName] = ["r", "g", "b", "a", "x", "y", "z"].includes(propertyName) || propertyName === "value" && (name === "size" || name === "thickness") ? castValue(String(property), "double") : property;
741
+ }
742
+ }
743
+ visualization[name] = properties;
744
+ }
745
+ if (Object.keys(visualization).length) native.viz = visualization;
746
+ if (Object.keys(native).length) attributes.gexf = native;
747
+ return {
748
+ id: identifier ?? requireAttribute(element, "id"),
749
+ label: element["@_label"],
750
+ attributes
751
+ };
752
+ }
753
+ function requireValue(element) {
754
+ const value = element["@_value"];
755
+ if (typeof value !== "string") throw new Error("GEXF attvalue requires a value attribute.");
756
+ return value;
757
+ }
758
+ var import_fast_xml_parser, parser, GEXF_NAMESPACE, TEMPORAL_ATTRIBUTES;
759
+ var init_parse_gexf = __esm({
760
+ "src/lib/parse-gexf.ts"() {
761
+ "use strict";
762
+ import_fast_xml_parser = require("fast-xml-parser");
763
+ init_build_graph_tables();
764
+ parser = new import_fast_xml_parser.XMLParser({
765
+ ignoreAttributes: false,
766
+ parseAttributeValue: false,
767
+ parseTagValue: false,
768
+ trimValues: false
769
+ });
770
+ GEXF_NAMESPACE = /^https?:\/\/(?:www\.)?gexf.net\/1\.(?:2(?:draft)?|3)(\/viz)?$/;
771
+ TEMPORAL_ATTRIBUTES = [
772
+ "start",
773
+ "end",
774
+ "startopen",
775
+ "endopen",
776
+ "timestamp",
777
+ "timestamps",
778
+ "intervals"
779
+ ];
780
+ }
781
+ });
782
+
783
+ // src/gexf-loader.ts
784
+ var gexf_loader_exports = {};
785
+ __export(gexf_loader_exports, {
786
+ GEXFLoaderWithParser: () => GEXFLoaderWithParser
787
+ });
788
+ var GEXFLoaderWithParser;
789
+ var init_gexf_loader = __esm({
790
+ "src/gexf-loader.ts"() {
791
+ "use strict";
792
+ init_gexf_loader_types();
793
+ init_parse_gexf();
794
+ GEXFLoaderWithParser = {
795
+ ...GEXFLoader,
796
+ parse: async (data, options) => {
797
+ var _a;
798
+ return parseGEXF(data, ((_a = options == null ? void 0 : options.gexf) == null ? void 0 : _a.shape) ?? "arrow-table");
799
+ },
800
+ parseSync: (data, options) => {
801
+ var _a;
802
+ return parseGEXF(data, ((_a = options == null ? void 0 : options.gexf) == null ? void 0 : _a.shape) ?? "arrow-table");
803
+ },
804
+ parseTextSync: (data, options) => {
805
+ var _a;
806
+ return parseGEXF(data, ((_a = options == null ? void 0 : options.gexf) == null ? void 0 : _a.shape) ?? "arrow-table");
807
+ }
808
+ };
809
+ }
810
+ });
811
+
812
+ // dist/gexf-loader.js
813
+ var gexf_loader_exports2 = {};
814
+ __export(gexf_loader_exports2, {
815
+ GEXFLoaderWithParser: () => GEXFLoaderWithParser2
816
+ });
817
+ module.exports = __toCommonJS(gexf_loader_exports2);
818
+
819
+ // dist/gexf-loader-types.js
820
+ var VERSION2 = true ? "5.0.0-beta.1" : "latest";
821
+ async function preload2() {
822
+ const { GEXFLoaderWithParser: GEXFLoaderWithParser3 } = await Promise.resolve().then(() => (init_gexf_loader(), gexf_loader_exports));
823
+ return GEXFLoaderWithParser3;
824
+ }
825
+ var GEXFLoader2 = {
826
+ name: "GEXF",
827
+ id: "gexf",
828
+ module: "graphs",
829
+ version: VERSION2,
830
+ extensions: ["gexf"],
831
+ mimeTypes: ["application/gexf+xml"],
832
+ text: true,
833
+ worker: false,
834
+ dataType: null,
835
+ batchType: null,
836
+ options: { gexf: { shape: "arrow-table" } },
837
+ preload: preload2
838
+ };
839
+
840
+ // dist/lib/parse-gexf.js
841
+ var import_fast_xml_parser2 = require("fast-xml-parser");
842
+
843
+ // dist/lib/build-graph-tables.js
844
+ var import_apache_arrow2 = require("apache-arrow");
845
+ init_schema_utils();
846
+ function buildGraphTables2(nodes, edges, shape, declarations) {
847
+ if (shape === "plain-graph-data") {
848
+ return { shape, nodes: Array.from(nodes), edges: Array.from(edges) };
849
+ }
850
+ if (shape !== "arrow-table" && shape !== "object-row-table") {
851
+ throw new Error(`Unsupported graph shape: ${shape}`);
852
+ }
853
+ const nodeTable = buildGraphTable2(nodes, false, shape, declarations == null ? void 0 : declarations.nodes);
854
+ const edgeTable = buildGraphTable2(edges, true, shape, declarations == null ? void 0 : declarations.edges);
855
+ return {
856
+ shape: "tables",
857
+ tables: [
858
+ { name: "nodes", table: nodeTable },
859
+ { name: "edges", table: edgeTable }
860
+ ]
861
+ };
862
+ }
863
+ function buildGraphTable2(records, isEdge, shape, declarations) {
864
+ const columnNames = isEdge ? ["id", "sourceId", "targetId", "directed", "label", "attributes"] : ["id", "label", "attributes"];
865
+ const columns = new Map(columnNames.map((name) => [name, []]));
866
+ for (const record of records) {
867
+ for (const name of columnNames) {
868
+ const value = record[name];
869
+ columns.get(name).push(name === "id" || name === "sourceId" || name === "targetId" ? String(value) : value ?? null);
870
+ }
871
+ }
872
+ if (shape === "object-row-table") {
873
+ return {
874
+ shape,
875
+ data: columns.get("id").map((_, index) => Object.fromEntries(columnNames.map((name) => [name, columns.get(name)[index]])))
876
+ };
877
+ }
878
+ const vectors = /* @__PURE__ */ Object.create(null);
879
+ for (const [name, values] of columns) {
880
+ const type = name === "attributes" ? inferAttributeType2(values, declarations) : name === "directed" ? new import_apache_arrow2.Bool() : new import_apache_arrow2.Utf8();
881
+ vectors[name] = (0, import_apache_arrow2.vectorFromArray)(values.map((value) => normalizeValue2(value, type)), type);
882
+ }
883
+ const data = new import_apache_arrow2.Table(vectors);
884
+ return { shape, schema: convertArrowToSchema(data.schema), data };
885
+ }
886
+ function inferAttributeType2(values, declarations) {
887
+ const names = new Set(declarations == null ? void 0 : declarations.keys());
888
+ for (const value of values) {
889
+ if (value && typeof value === "object") {
890
+ for (const name of Object.keys(value)) {
891
+ names.add(name);
892
+ }
893
+ }
894
+ }
895
+ return new import_apache_arrow2.Struct(Array.from(names, (name) => {
896
+ const fieldValues = values.map((value) => (value == null ? void 0 : value[name]) ?? null);
897
+ return new import_apache_arrow2.Field(name, inferValueType2(fieldValues, declarations == null ? void 0 : declarations.get(name)), true);
898
+ }));
899
+ }
900
+ function inferValueType2(values, declaration) {
901
+ const present = values.filter((value) => value !== null && value !== void 0);
902
+ if (declaration && typeof declaration === "object") {
903
+ if (!present.every((value) => Array.isArray(value)))
904
+ return new import_apache_arrow2.Utf8();
905
+ return new import_apache_arrow2.List(new import_apache_arrow2.Field("item", inferValueType2(present.flatMap((value) => value), declaration.list), true));
906
+ }
907
+ if (declaration) {
908
+ const declaredTypes = {
909
+ boolean: new import_apache_arrow2.Bool(),
910
+ int: new import_apache_arrow2.Int32(),
911
+ long: new import_apache_arrow2.Int64(),
912
+ float: new import_apache_arrow2.Float32(),
913
+ double: new import_apache_arrow2.Float64(),
914
+ string: new import_apache_arrow2.Utf8()
915
+ };
916
+ const valid = present.every((value) => {
917
+ switch (declaration) {
918
+ case "boolean":
919
+ return typeof value === "boolean";
920
+ case "int":
921
+ return typeof value === "number" && Number.isInteger(value) && value >= -2147483648 && value <= 2147483647;
922
+ case "long":
923
+ return typeof value === "bigint" && value >= -(2n ** 63n) && value < 2n ** 63n;
924
+ case "float":
925
+ case "double":
926
+ return typeof value === "number";
927
+ case "string":
928
+ return typeof value === "string";
929
+ }
930
+ });
931
+ return valid ? declaredTypes[declaration] : new import_apache_arrow2.Utf8();
932
+ }
933
+ if (present.length && present.every((value) => typeof value === "boolean"))
934
+ return new import_apache_arrow2.Bool();
935
+ if (present.length && present.every((value) => typeof value === "number"))
936
+ return new import_apache_arrow2.Float64();
937
+ if (present.length && present.every((value) => Array.isArray(value))) {
938
+ return new import_apache_arrow2.List(new import_apache_arrow2.Field("item", inferValueType2(present.flatMap((value) => value)), true));
939
+ }
940
+ if (present.length && present.every((value) => typeof value === "object" && !Array.isArray(value))) {
941
+ return inferAttributeType2(present);
942
+ }
943
+ return new import_apache_arrow2.Utf8();
944
+ }
945
+ function normalizeValue2(value, type) {
946
+ if (value === null || value === void 0)
947
+ return null;
948
+ if (type instanceof import_apache_arrow2.Struct) {
949
+ return Object.fromEntries(type.children.map((field) => [
950
+ field.name,
951
+ normalizeValue2(value[field.name], field.type)
952
+ ]));
953
+ }
954
+ if (type instanceof import_apache_arrow2.List)
955
+ return value.map((item) => normalizeValue2(item, type.valueType));
956
+ if (type instanceof import_apache_arrow2.Utf8 && typeof value !== "string") {
957
+ return typeof value === "object" ? JSON.stringify(value) : String(value);
958
+ }
959
+ return value;
960
+ }
961
+
962
+ // dist/lib/parse-gexf.js
963
+ var parser2 = new import_fast_xml_parser2.XMLParser({
964
+ ignoreAttributes: false,
965
+ parseAttributeValue: false,
966
+ parseTagValue: false,
967
+ trimValues: false
968
+ });
969
+ var GEXF_NAMESPACE2 = /^https?:\/\/(?:www\.)?gexf.net\/1\.(?:2(?:draft)?|3)(\/viz)?$/;
970
+ var TEMPORAL_ATTRIBUTES2 = [
971
+ "start",
972
+ "end",
973
+ "startopen",
974
+ "endopen",
975
+ "timestamp",
976
+ "timestamps",
977
+ "intervals"
978
+ ];
979
+ function parseGEXF2(input, shape = "arrow-table") {
980
+ const text = typeof input === "string" ? input : new TextDecoder().decode(input);
981
+ const validation = import_fast_xml_parser2.XMLValidator.validate(text);
982
+ if (validation !== true)
983
+ throw new Error(`Invalid GEXF XML: ${validation.err.msg}`);
984
+ if (/<!DOCTYPE\s/i.test(text))
985
+ throw new Error("GEXF document types are unsupported.");
986
+ const document = normalizeNamespaces2(parser2.parse(text), {});
987
+ const root = getElement2(document.gexf, "gexf");
988
+ const version = root["@_version"];
989
+ if (version && !["1.2", "1.2draft", "1.3"].includes(version)) {
990
+ throw new Error(`Unsupported GEXF version: ${version}`);
991
+ }
992
+ const graph = getElement2(root.graph, "graph");
993
+ const directed = parseDirection2(graph["@_defaultedgetype"] ?? "undirected");
994
+ const definitions = {
995
+ nodes: /* @__PURE__ */ new Map(),
996
+ edges: /* @__PURE__ */ new Map()
997
+ };
998
+ for (const attributes of getElements2(graph.attributes)) {
999
+ const domain = attributes["@_class"];
1000
+ if (domain !== "node" && domain !== "edge")
1001
+ throw new Error("GEXF attributes require a node or edge class.");
1002
+ const scoped = domain === "node" ? definitions.nodes : definitions.edges;
1003
+ const names = new Set(Array.from(scoped.values(), (definition) => definition.name));
1004
+ for (const attribute of getElements2(attributes.attribute)) {
1005
+ const identifier = requireAttribute2(attribute, "id");
1006
+ const name = requireAttribute2(attribute, "title");
1007
+ if (name === "gexf" || names.has(name) || scoped.has(identifier)) {
1008
+ throw new Error(`Duplicate or reserved GEXF attribute: ${name}`);
1009
+ }
1010
+ names.add(name);
1011
+ const type = parseAttributeType2(requireAttribute2(attribute, "type"));
1012
+ scoped.set(identifier, {
1013
+ name,
1014
+ type,
1015
+ defaultValue: attribute.default === void 0 ? void 0 : castValue2(readTextContent2(attribute.default), type)
1016
+ });
1017
+ }
1018
+ }
1019
+ const nodeElements = getElements2(getContainer2(graph.nodes).node);
1020
+ const edgeElements = getElements2(getContainer2(graph.edges).edge);
1021
+ const nodeIdentifiers = /* @__PURE__ */ new Set();
1022
+ for (const node of nodeElements) {
1023
+ const identifier = requireAttribute2(node, "id");
1024
+ if (nodeIdentifiers.has(identifier))
1025
+ throw new Error(`Duplicate GEXF node ID: ${identifier}`);
1026
+ nodeIdentifiers.add(identifier);
1027
+ }
1028
+ const edgeIdentifiers = new Set(edgeElements.map((edge) => edge["@_id"]).filter((identifier) => typeof identifier === "string"));
1029
+ const seenEdges = /* @__PURE__ */ new Set();
1030
+ function* iterateNodes() {
1031
+ for (const node of nodeElements)
1032
+ yield parseRecord2(node, definitions.nodes);
1033
+ }
1034
+ function* iterateEdges() {
1035
+ for (const [index, edge] of edgeElements.entries()) {
1036
+ const sourceId = requireAttribute2(edge, "source");
1037
+ const targetId = requireAttribute2(edge, "target");
1038
+ if (!nodeIdentifiers.has(sourceId) || !nodeIdentifiers.has(targetId)) {
1039
+ throw new Error("GEXF edge references an undeclared node.");
1040
+ }
1041
+ let identifier = edge["@_id"] === void 0 ? void 0 : requireAttribute2(edge, "id");
1042
+ if (identifier === void 0) {
1043
+ identifier = `edge-${index}`;
1044
+ while (edgeIdentifiers.has(identifier))
1045
+ identifier = `_${identifier}`;
1046
+ edgeIdentifiers.add(identifier);
1047
+ }
1048
+ if (seenEdges.has(identifier))
1049
+ throw new Error(`Duplicate GEXF edge ID: ${identifier}`);
1050
+ seenEdges.add(identifier);
1051
+ yield {
1052
+ ...parseRecord2(edge, definitions.edges, identifier),
1053
+ sourceId,
1054
+ targetId,
1055
+ directed: edge["@_type"] === void 0 ? directed : parseDirection2(edge["@_type"])
1056
+ };
1057
+ }
1058
+ }
1059
+ const metadataAttributes = /* @__PURE__ */ Object.create(null);
1060
+ const meta = getContainer2(root.meta);
1061
+ for (const name of ["creator", "description", "keywords"]) {
1062
+ if (meta[name] !== void 0)
1063
+ metadataAttributes[name] = readTextContent2(meta[name]);
1064
+ }
1065
+ if (typeof meta["@_lastmodifieddate"] === "string")
1066
+ metadataAttributes.lastmodifieddate = meta["@_lastmodifieddate"];
1067
+ const declarations = {
1068
+ nodes: new Map(Array.from(definitions.nodes.values(), (definition) => [definition.name, definition.type])),
1069
+ edges: new Map(Array.from(definitions.edges.values(), (definition) => [definition.name, definition.type]))
1070
+ };
1071
+ return {
1072
+ ...buildGraphTables2(iterateNodes(), iterateEdges(), shape, declarations),
1073
+ metadata: { version, directed, attributes: metadataAttributes }
1074
+ };
1075
+ }
1076
+ function normalizeNamespaces2(element, inherited) {
1077
+ const namespaces = Object.assign(/* @__PURE__ */ Object.create(null), inherited);
1078
+ for (const [name, value] of Object.entries(element)) {
1079
+ if (name === "@_xmlns")
1080
+ namespaces[""] = String(value);
1081
+ else if (name.startsWith("@_xmlns:"))
1082
+ namespaces[name.slice(8)] = String(value);
1083
+ }
1084
+ const normalized = /* @__PURE__ */ Object.create(null);
1085
+ for (const [name, value] of Object.entries(element)) {
1086
+ if (name.startsWith("@_") || name === "#text" || name.startsWith("?")) {
1087
+ normalized[name] = value;
1088
+ continue;
1089
+ }
1090
+ const separator = name.indexOf(":");
1091
+ const prefix = separator < 0 ? "" : name.slice(0, separator);
1092
+ const localName = name.slice(separator + 1);
1093
+ const children = Array.isArray(value) ? value : [value];
1094
+ for (const child of children) {
1095
+ const object = typeof child === "object" && child !== null ? child : {};
1096
+ const namespace = object[prefix ? `@_xmlns:${prefix}` : "@_xmlns"] ?? namespaces[prefix];
1097
+ const match = typeof namespace === "string" ? GEXF_NAMESPACE2.exec(namespace) : null;
1098
+ const key = match ? `${match[1] ? "viz:" : ""}${localName}` : namespace || prefix ? `foreign:${name}` : localName;
1099
+ const childValue = typeof child === "object" && child !== null ? match || !namespace && !prefix ? normalizeNamespaces2(object, namespaces) : object : child;
1100
+ if (normalized[key] === void 0)
1101
+ normalized[key] = childValue;
1102
+ else
1103
+ normalized[key] = [
1104
+ ...Array.isArray(normalized[key]) ? normalized[key] : [normalized[key]],
1105
+ childValue
1106
+ ];
1107
+ }
1108
+ }
1109
+ assertStaticElement2(normalized);
1110
+ return normalized;
1111
+ }
1112
+ function assertStaticElement2(element) {
1113
+ if (element["@_mode"] !== void 0 && element["@_mode"] !== "static" || TEMPORAL_ATTRIBUTES2.some((name) => element[`@_${name}`] !== void 0) || element.spells !== void 0) {
1114
+ throw new Error("Dynamic GEXF graphs and temporal values are unsupported.");
1115
+ }
1116
+ if (element["@_pid"] !== void 0 || element.parents !== void 0 || element["@_id"] !== void 0 && (element.nodes !== void 0 || element.edges !== void 0)) {
1117
+ throw new Error("Hierarchical GEXF graphs are unsupported.");
1118
+ }
1119
+ }
1120
+ function getElement2(value, name) {
1121
+ if (value === "")
1122
+ return {};
1123
+ if (value && typeof value === "object" && !Array.isArray(value))
1124
+ return value;
1125
+ throw new Error(`GEXF requires one <${name}> element.`);
1126
+ }
1127
+ function readTextContent2(value) {
1128
+ if (typeof value === "string")
1129
+ return value;
1130
+ const text = getElement2(value, "text")["#text"];
1131
+ return typeof text === "string" ? text : "";
1132
+ }
1133
+ function getContainer2(value) {
1134
+ return value === void 0 ? {} : getElement2(value, "container");
1135
+ }
1136
+ function getElements2(value) {
1137
+ if (value === void 0)
1138
+ return [];
1139
+ return (Array.isArray(value) ? value : [value]).map((entry) => getElement2(entry, "record"));
1140
+ }
1141
+ function requireAttribute2(element, name) {
1142
+ const value = element[`@_${name}`];
1143
+ if (typeof value !== "string" || value === "")
1144
+ throw new Error(`GEXF requires a ${name} attribute.`);
1145
+ return value;
1146
+ }
1147
+ function parseDirection2(value) {
1148
+ if (value !== "directed" && value !== "undirected")
1149
+ throw new Error(`Unsupported GEXF edge type: ${String(value)}`);
1150
+ return value === "directed";
1151
+ }
1152
+ function parseAttributeType2(value) {
1153
+ if (value.startsWith("list") && !value.slice(4).startsWith("list")) {
1154
+ return { list: parseAttributeType2(value.slice(4)) };
1155
+ }
1156
+ if (value === "integer" || value === "byte" || value === "short")
1157
+ return "int";
1158
+ if (value === "boolean" || value === "long" || value === "float" || value === "double")
1159
+ return value;
1160
+ if (["string", "anyURI", "date", "char", "bigdecimal", "biginteger"].includes(value))
1161
+ return "string";
1162
+ throw new Error(`Unsupported GEXF attribute type: ${value}`);
1163
+ }
1164
+ function castValue2(text, type) {
1165
+ if (typeof type === "object") {
1166
+ return parseListValues2(text).map((value) => castValue2(value, type.list));
1167
+ }
1168
+ if (type === "string")
1169
+ return text;
1170
+ const trimmed = text.trim();
1171
+ if (type === "boolean") {
1172
+ if (trimmed === "true" || trimmed === "1")
1173
+ return true;
1174
+ if (trimmed === "false" || trimmed === "0")
1175
+ return false;
1176
+ return text;
1177
+ }
1178
+ if (type === "int" || type === "long") {
1179
+ if (!/^[+-]?\d+$/.test(trimmed))
1180
+ return text;
1181
+ return type === "long" ? BigInt(trimmed) : Number.isSafeInteger(Number(trimmed)) ? Number(trimmed) : text;
1182
+ }
1183
+ if (trimmed === "INF")
1184
+ return Infinity;
1185
+ if (trimmed === "-INF")
1186
+ return -Infinity;
1187
+ if (trimmed === "NaN")
1188
+ return NaN;
1189
+ if (!/^[+-]?(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?$/.test(trimmed))
1190
+ return text;
1191
+ const number = Number(trimmed);
1192
+ const represented = type === "float" ? Math.fround(number) : number;
1193
+ const nonzero = /[1-9]/.test(trimmed.split(/[eE]/)[0]);
1194
+ return Number.isFinite(represented) && (represented !== 0 || !nonzero) ? number : text;
1195
+ }
1196
+ function parseListValues2(text) {
1197
+ const trimmed = text.trim();
1198
+ const bracketed = trimmed.startsWith("[");
1199
+ if (bracketed !== trimmed.endsWith("]"))
1200
+ throw new Error("Invalid GEXF list brackets.");
1201
+ const contents = bracketed ? trimmed.slice(1, -1) : trimmed;
1202
+ if (!contents.trim())
1203
+ return [];
1204
+ const values = [];
1205
+ let value = "";
1206
+ let quote = "";
1207
+ let quoted = false;
1208
+ let closed = false;
1209
+ for (let index = 0; index < contents.length; index++) {
1210
+ const character = contents[index];
1211
+ if (quote) {
1212
+ if (character === "\\" && (contents[index + 1] === quote || contents[index + 1] === "\\")) {
1213
+ value += contents[++index];
1214
+ } else if (character === quote) {
1215
+ quote = "";
1216
+ closed = true;
1217
+ } else
1218
+ value += character;
1219
+ } else if (character === "," || !bracketed && (character === "|" || character === ";")) {
1220
+ values.push(quoted ? value : value.trim());
1221
+ value = "";
1222
+ quoted = false;
1223
+ closed = false;
1224
+ } else if (closed) {
1225
+ if (character.trim())
1226
+ throw new Error("Invalid GEXF list text after a quote.");
1227
+ } else if ((character === "'" || character === '"') && !value.trim()) {
1228
+ quote = character;
1229
+ quoted = true;
1230
+ value = "";
1231
+ } else
1232
+ value += character;
1233
+ }
1234
+ if (quote)
1235
+ throw new Error("Unterminated GEXF list quote.");
1236
+ values.push(quoted ? value : value.trim());
1237
+ return values;
1238
+ }
1239
+ function parseRecord2(element, definitions, identifier) {
1240
+ const attributes = /* @__PURE__ */ Object.create(null);
1241
+ for (const definition of definitions.values()) {
1242
+ if (definition.defaultValue !== void 0)
1243
+ attributes[definition.name] = Array.isArray(definition.defaultValue) ? [...definition.defaultValue] : definition.defaultValue;
1244
+ }
1245
+ for (const attvalue of getElements2(getContainer2(element.attvalues).attvalue)) {
1246
+ const key = requireAttribute2(attvalue, "for");
1247
+ const definition = definitions.get(key);
1248
+ if (!definition)
1249
+ throw new Error(`Undeclared GEXF attribute: ${key}`);
1250
+ attributes[definition.name] = castValue2(requireValue2(attvalue), definition.type);
1251
+ }
1252
+ const native = /* @__PURE__ */ Object.create(null);
1253
+ if (element["@_weight"] !== void 0)
1254
+ native.weight = castValue2(String(element["@_weight"]), "double");
1255
+ if (element["@_kind"] !== void 0)
1256
+ native.kind = element["@_kind"];
1257
+ const visualization = /* @__PURE__ */ Object.create(null);
1258
+ for (const name of ["color", "position", "size", "shape", "thickness"]) {
1259
+ const value = element[`viz:${name}`];
1260
+ if (value === void 0)
1261
+ continue;
1262
+ const properties = /* @__PURE__ */ Object.create(null);
1263
+ for (const [key, property] of Object.entries(getElement2(value, `viz:${name}`))) {
1264
+ if (key.startsWith("@_") && !key.startsWith("@_xmlns")) {
1265
+ const propertyName = key.slice(2);
1266
+ properties[propertyName] = ["r", "g", "b", "a", "x", "y", "z"].includes(propertyName) || propertyName === "value" && (name === "size" || name === "thickness") ? castValue2(String(property), "double") : property;
1267
+ }
1268
+ }
1269
+ visualization[name] = properties;
1270
+ }
1271
+ if (Object.keys(visualization).length)
1272
+ native.viz = visualization;
1273
+ if (Object.keys(native).length)
1274
+ attributes.gexf = native;
1275
+ return {
1276
+ id: identifier ?? requireAttribute2(element, "id"),
1277
+ label: element["@_label"],
1278
+ attributes
1279
+ };
1280
+ }
1281
+ function requireValue2(element) {
1282
+ const value = element["@_value"];
1283
+ if (typeof value !== "string")
1284
+ throw new Error("GEXF attvalue requires a value attribute.");
1285
+ return value;
1286
+ }
1287
+
1288
+ // dist/gexf-loader.js
1289
+ var GEXFLoaderWithParser2 = {
1290
+ ...GEXFLoader2,
1291
+ parse: async (data, options) => {
1292
+ var _a;
1293
+ return parseGEXF2(data, ((_a = options == null ? void 0 : options.gexf) == null ? void 0 : _a.shape) ?? "arrow-table");
1294
+ },
1295
+ parseSync: (data, options) => {
1296
+ var _a;
1297
+ return parseGEXF2(data, ((_a = options == null ? void 0 : options.gexf) == null ? void 0 : _a.shape) ?? "arrow-table");
1298
+ },
1299
+ parseTextSync: (data, options) => {
1300
+ var _a;
1301
+ return parseGEXF2(data, ((_a = options == null ? void 0 : options.gexf) == null ? void 0 : _a.shape) ?? "arrow-table");
1302
+ }
1303
+ };
1304
+ //# sourceMappingURL=gexf-loader.cjs.map