@graphty/graph-io 0.2.4 → 0.3.0

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 (180) hide show
  1. package/README.md +29 -7
  2. package/dist/chunks/{escape-DyI8JofU.js → escape-CKied3Ri.js} +16 -10
  3. package/dist/chunks/escape-CKied3Ri.js.map +1 -0
  4. package/dist/chunks/{importer-DbnGYr3_.js → importer-C6QcIRIb.js} +129 -39
  5. package/dist/chunks/importer-C6QcIRIb.js.map +1 -0
  6. package/dist/chunks/{importer-CpCpfbxr.js → importer-D5pAsweZ.js} +136 -31
  7. package/dist/chunks/importer-D5pAsweZ.js.map +1 -0
  8. package/dist/chunks/{importer-GozH8DkN.js → importer-DbMrAR_w.js} +10 -4
  9. package/dist/chunks/importer-DbMrAR_w.js.map +1 -0
  10. package/dist/chunks/{importer-CQnJuWJw.js → importer-DkzjTvHc.js} +82 -40
  11. package/dist/chunks/importer-DkzjTvHc.js.map +1 -0
  12. package/dist/chunks/{records-CGpxszm1.js → records-BKSMowhR.js} +3 -3
  13. package/dist/chunks/{records-CGpxszm1.js.map → records-BKSMowhR.js.map} +1 -1
  14. package/dist/chunks/{text-CajMdVFy.js → text-Dr0Ifpag.js} +2 -2
  15. package/dist/chunks/{text-CajMdVFy.js.map → text-Dr0Ifpag.js.map} +1 -1
  16. package/dist/chunks/{writer-DxSKC7TL.js → writer-BdMak4_J.js} +341 -112
  17. package/dist/chunks/writer-BdMak4_J.js.map +1 -0
  18. package/dist/csv.js +24 -6
  19. package/dist/csv.js.map +1 -1
  20. package/dist/dot.js +1 -1
  21. package/dist/gexf.js +42 -10
  22. package/dist/gexf.js.map +1 -1
  23. package/dist/gml.js +69 -25
  24. package/dist/gml.js.map +1 -1
  25. package/dist/graph-io.js +186 -129
  26. package/dist/graph-io.js.map +1 -1
  27. package/dist/graphml.js +1 -1
  28. package/dist/json.js +1 -1
  29. package/dist/neo4j.js +10 -4
  30. package/dist/neo4j.js.map +1 -1
  31. package/dist/pajek.js +1 -1
  32. package/dist/src/common/codes.d.ts +6 -0
  33. package/dist/src/common/codes.d.ts.map +1 -1
  34. package/dist/src/common/codes.js +6 -0
  35. package/dist/src/common/codes.js.map +1 -1
  36. package/dist/src/common/escape.d.ts +5 -4
  37. package/dist/src/common/escape.d.ts.map +1 -1
  38. package/dist/src/common/escape.js +6 -5
  39. package/dist/src/common/escape.js.map +1 -1
  40. package/dist/src/common/format.d.ts +3 -3
  41. package/dist/src/common/format.js +5 -5
  42. package/dist/src/common/format.js.map +1 -1
  43. package/dist/src/common/input.d.ts +24 -6
  44. package/dist/src/common/input.d.ts.map +1 -1
  45. package/dist/src/common/input.js +259 -23
  46. package/dist/src/common/input.js.map +1 -1
  47. package/dist/src/common/options.d.ts +2 -0
  48. package/dist/src/common/options.d.ts.map +1 -1
  49. package/dist/src/common/options.js +17 -0
  50. package/dist/src/common/options.js.map +1 -1
  51. package/dist/src/common/text.js +4 -4
  52. package/dist/src/common/text.js.map +1 -1
  53. package/dist/src/common/weights.d.ts.map +1 -1
  54. package/dist/src/common/weights.js +8 -0
  55. package/dist/src/common/weights.js.map +1 -1
  56. package/dist/src/common/xml.d.ts +7 -0
  57. package/dist/src/common/xml.d.ts.map +1 -1
  58. package/dist/src/common/xml.js +12 -0
  59. package/dist/src/common/xml.js.map +1 -1
  60. package/dist/src/formats/csv/exporter.d.ts +5 -1
  61. package/dist/src/formats/csv/exporter.d.ts.map +1 -1
  62. package/dist/src/formats/csv/exporter.js +8 -1
  63. package/dist/src/formats/csv/exporter.js.map +1 -1
  64. package/dist/src/formats/csv/importer.d.ts.map +1 -1
  65. package/dist/src/formats/csv/importer.js +1 -0
  66. package/dist/src/formats/csv/importer.js.map +1 -1
  67. package/dist/src/formats/csv/index.d.ts +6 -0
  68. package/dist/src/formats/csv/index.d.ts.map +1 -1
  69. package/dist/src/formats/csv/index.js +7 -1
  70. package/dist/src/formats/csv/index.js.map +1 -1
  71. package/dist/src/formats/csv/records.js +1 -1
  72. package/dist/src/formats/csv/records.js.map +1 -1
  73. package/dist/src/formats/dot/exporter.d.ts +1 -1
  74. package/dist/src/formats/dot/exporter.d.ts.map +1 -1
  75. package/dist/src/formats/dot/exporter.js +3 -3
  76. package/dist/src/formats/dot/exporter.js.map +1 -1
  77. package/dist/src/formats/dot/importer.d.ts +6 -0
  78. package/dist/src/formats/dot/importer.d.ts.map +1 -1
  79. package/dist/src/formats/dot/importer.js +151 -24
  80. package/dist/src/formats/dot/importer.js.map +1 -1
  81. package/dist/src/formats/gexf/exporter.d.ts.map +1 -1
  82. package/dist/src/formats/gexf/exporter.js +32 -7
  83. package/dist/src/formats/gexf/exporter.js.map +1 -1
  84. package/dist/src/formats/gexf/importer.d.ts.map +1 -1
  85. package/dist/src/formats/gexf/importer.js +2 -2
  86. package/dist/src/formats/gexf/importer.js.map +1 -1
  87. package/dist/src/formats/gexf/index.d.ts +6 -0
  88. package/dist/src/formats/gexf/index.d.ts.map +1 -1
  89. package/dist/src/formats/gexf/index.js +7 -1
  90. package/dist/src/formats/gexf/index.js.map +1 -1
  91. package/dist/src/formats/gml/importer.d.ts +2 -2
  92. package/dist/src/formats/gml/importer.d.ts.map +1 -1
  93. package/dist/src/formats/gml/importer.js +66 -25
  94. package/dist/src/formats/gml/importer.js.map +1 -1
  95. package/dist/src/formats/gml/index.d.ts +7 -1
  96. package/dist/src/formats/gml/index.d.ts.map +1 -1
  97. package/dist/src/formats/gml/index.js +8 -2
  98. package/dist/src/formats/gml/index.js.map +1 -1
  99. package/dist/src/formats/graphml/constants.d.ts +6 -0
  100. package/dist/src/formats/graphml/constants.d.ts.map +1 -1
  101. package/dist/src/formats/graphml/constants.js +7 -1
  102. package/dist/src/formats/graphml/constants.js.map +1 -1
  103. package/dist/src/formats/graphml/importer.d.ts.map +1 -1
  104. package/dist/src/formats/graphml/importer.js +2 -2
  105. package/dist/src/formats/graphml/importer.js.map +1 -1
  106. package/dist/src/formats/json/exporter.d.ts.map +1 -1
  107. package/dist/src/formats/json/exporter.js +14 -5
  108. package/dist/src/formats/json/exporter.js.map +1 -1
  109. package/dist/src/formats/json/importer.d.ts +8 -0
  110. package/dist/src/formats/json/importer.d.ts.map +1 -1
  111. package/dist/src/formats/json/importer.js +84 -37
  112. package/dist/src/formats/json/importer.js.map +1 -1
  113. package/dist/src/formats/neo4j/importer.js +1 -1
  114. package/dist/src/formats/neo4j/importer.js.map +1 -1
  115. package/dist/src/formats/neo4j/index.d.ts +6 -0
  116. package/dist/src/formats/neo4j/index.d.ts.map +1 -1
  117. package/dist/src/formats/neo4j/index.js +7 -1
  118. package/dist/src/formats/neo4j/index.js.map +1 -1
  119. package/dist/src/formats/pajek/exporter.d.ts +2 -0
  120. package/dist/src/formats/pajek/exporter.d.ts.map +1 -1
  121. package/dist/src/formats/pajek/exporter.js +13 -2
  122. package/dist/src/formats/pajek/exporter.js.map +1 -1
  123. package/dist/src/formats/pajek/importer.d.ts +8 -2
  124. package/dist/src/formats/pajek/importer.d.ts.map +1 -1
  125. package/dist/src/formats/pajek/importer.js +122 -26
  126. package/dist/src/formats/pajek/importer.js.map +1 -1
  127. package/dist/src/index.d.ts +1 -1
  128. package/dist/src/index.d.ts.map +1 -1
  129. package/dist/src/index.js +1 -1
  130. package/dist/src/index.js.map +1 -1
  131. package/dist/src/registry.d.ts +26 -0
  132. package/dist/src/registry.d.ts.map +1 -1
  133. package/dist/src/registry.js +101 -35
  134. package/dist/src/registry.js.map +1 -1
  135. package/dist/src/sniff.d.ts +1 -1
  136. package/dist/src/sniff.d.ts.map +1 -1
  137. package/dist/src/sniff.js +6 -1
  138. package/dist/src/sniff.js.map +1 -1
  139. package/dist/src/types.d.ts +22 -3
  140. package/dist/src/types.d.ts.map +1 -1
  141. package/dist/src/types.js.map +1 -1
  142. package/package.json +4 -3
  143. package/src/common/codes.ts +9 -0
  144. package/src/common/escape.ts +6 -5
  145. package/src/common/format.ts +5 -5
  146. package/src/common/input.ts +293 -22
  147. package/src/common/options.ts +24 -0
  148. package/src/common/text.ts +4 -4
  149. package/src/common/weights.ts +9 -0
  150. package/src/common/xml.ts +14 -0
  151. package/src/formats/csv/exporter.ts +12 -1
  152. package/src/formats/csv/importer.ts +1 -0
  153. package/src/formats/csv/index.ts +9 -0
  154. package/src/formats/csv/records.ts +1 -1
  155. package/src/formats/dot/exporter.ts +3 -3
  156. package/src/formats/dot/importer.ts +172 -32
  157. package/src/formats/gexf/exporter.ts +38 -7
  158. package/src/formats/gexf/importer.ts +12 -2
  159. package/src/formats/gexf/index.ts +9 -0
  160. package/src/formats/gml/importer.ts +75 -22
  161. package/src/formats/gml/index.ts +10 -1
  162. package/src/formats/graphml/constants.ts +9 -0
  163. package/src/formats/graphml/importer.ts +9 -2
  164. package/src/formats/json/exporter.ts +14 -5
  165. package/src/formats/json/importer.ts +104 -36
  166. package/src/formats/neo4j/importer.ts +1 -1
  167. package/src/formats/neo4j/index.ts +9 -0
  168. package/src/formats/pajek/exporter.ts +19 -2
  169. package/src/formats/pajek/importer.ts +145 -28
  170. package/src/index.ts +1 -0
  171. package/src/registry.ts +131 -40
  172. package/src/sniff.ts +6 -1
  173. package/src/types.ts +26 -3
  174. package/dist/chunks/escape-DyI8JofU.js.map +0 -1
  175. package/dist/chunks/importer-CQnJuWJw.js.map +0 -1
  176. package/dist/chunks/importer-CpCpfbxr.js.map +0 -1
  177. package/dist/chunks/importer-DbnGYr3_.js.map +0 -1
  178. package/dist/chunks/importer-GozH8DkN.js.map +0 -1
  179. package/dist/chunks/writer-DxSKC7TL.js.map +0 -1
  180. package/dist/tsconfig.build.tsbuildinfo +0 -1
@@ -19,6 +19,9 @@ const ID_MERGED_CODE = "W_ID_MERGED";
19
19
  const SINK_OPTION_CODE = "W_SINK_OPTION";
20
20
  const OPTION_IGNORED_CODE = "W_OPTION_IGNORED";
21
21
  const INVALID_UTF8_CODE = "E_INVALID_UTF8";
22
+ const INVALID_ENCODING_CODE = "E_INVALID_ENCODING";
23
+ const ENCODING_FALLBACK_CODE = "W_ENCODING_FALLBACK";
24
+ const UNKNOWN_ENCODING_CODE = "W_UNKNOWN_ENCODING";
22
25
  const DIRECTION_REFUSED_CODE = "W_DIRECTION_REFUSED";
23
26
  const DIRECTION_FORCED_CODE = "W_DIRECTION_FORCED";
24
27
  const MIXED_DIRECTION_CODE = "E_MIXED_DIRECTION";
@@ -1277,6 +1280,189 @@ class IdCoercer {
1277
1280
  return coerceId(value, this.mode);
1278
1281
  }
1279
1282
  }
1283
+ const HEAD_BYTES = 1024;
1284
+ const BOM_BYTES = 3;
1285
+ function canonicalEncoding(label) {
1286
+ try {
1287
+ return new TextDecoder(label.trim()).encoding;
1288
+ } catch {
1289
+ return null;
1290
+ }
1291
+ }
1292
+ function bomEncoding(head) {
1293
+ if (head.byteLength >= 3 && head[0] === 239 && head[1] === 187 && head[2] === 191) {
1294
+ return "utf-8";
1295
+ }
1296
+ if (head.byteLength >= 2 && head[0] === 255 && head[1] === 254) {
1297
+ return "utf-16le";
1298
+ }
1299
+ if (head.byteLength >= 2 && head[0] === 254 && head[1] === 255) {
1300
+ return "utf-16be";
1301
+ }
1302
+ return null;
1303
+ }
1304
+ class ByteDecoder {
1305
+ /**
1306
+ * Create the decoder of one import.
1307
+ * @param report - where warnings and the fatal decode error go
1308
+ * @param options - the encoding option and the format's declaration reader
1309
+ */
1310
+ constructor(report, options) {
1311
+ this.report = report;
1312
+ this.options = options;
1313
+ this.decoder = null;
1314
+ this.encoding = "utf-8";
1315
+ this.mayFallBack = false;
1316
+ this.asciiSoFar = true;
1317
+ this.carry = new Uint8Array(0);
1318
+ this.offset = 0;
1319
+ }
1320
+ /**
1321
+ * Whether start() ran.
1322
+ * @returns true once the encoding is chosen
1323
+ */
1324
+ get started() {
1325
+ return this.decoder !== null;
1326
+ }
1327
+ /**
1328
+ * Choose the encoding from the first bytes of the input.
1329
+ * @param head - the first bytes (up to HEAD_BYTES; fewer when the input is shorter)
1330
+ */
1331
+ start(head) {
1332
+ const explicit = this.options.encoding ?? null;
1333
+ if (explicit !== null) {
1334
+ this.use(explicit, false);
1335
+ return;
1336
+ }
1337
+ const bom = bomEncoding(head);
1338
+ if (bom !== null) {
1339
+ this.use(bom, false);
1340
+ return;
1341
+ }
1342
+ const declared = this.options.declaredEncoding?.(new TextDecoder("windows-1252").decode(head)) ?? null;
1343
+ if (declared !== null) {
1344
+ const canonical = canonicalEncoding(declared);
1345
+ if (canonical === null) {
1346
+ this.report.warning(
1347
+ "unsupported",
1348
+ UNKNOWN_ENCODING_CODE,
1349
+ `the input declares the encoding ${JSON.stringify(declared)}, which this platform cannot decode; reading it as UTF-8`,
1350
+ { element: declared }
1351
+ );
1352
+ } else if (canonical !== "utf-8" && !canonical.startsWith("utf-16")) {
1353
+ this.use(canonical, false);
1354
+ return;
1355
+ }
1356
+ }
1357
+ this.use("utf-8", true);
1358
+ }
1359
+ /**
1360
+ * Decode the next bytes.
1361
+ * @param bytes - the bytes
1362
+ * @param stream - whether more bytes follow
1363
+ * @returns the text
1364
+ */
1365
+ decode(bytes, stream) {
1366
+ const decoder = this.decoder;
1367
+ let text;
1368
+ try {
1369
+ text = decoder.decode(bytes, { stream });
1370
+ } catch (err) {
1371
+ if (!(err instanceof TypeError)) {
1372
+ throw err;
1373
+ }
1374
+ text = this.recover(bytes, stream);
1375
+ }
1376
+ if (this.asciiSoFar && this.mayFallBack) {
1377
+ if (/[\u0080-\uffff]/.test(text)) {
1378
+ this.asciiSoFar = false;
1379
+ this.carry = new Uint8Array(0);
1380
+ } else {
1381
+ const all = this.carry.byteLength === 0 ? bytes : concatBytes([this.carry, bytes]);
1382
+ this.carry = all.slice(text.length);
1383
+ }
1384
+ }
1385
+ this.offset += bytes.byteLength;
1386
+ return text;
1387
+ }
1388
+ /**
1389
+ * A decode failed: switch to windows-1252 when allowed, else fail the import.
1390
+ * @param bytes - the bytes that failed
1391
+ * @param stream - whether more bytes follow
1392
+ * @returns the bytes decoded as windows-1252
1393
+ */
1394
+ recover(bytes, stream) {
1395
+ const where = { byteOffset: this.offset };
1396
+ const all = this.carry.byteLength === 0 ? bytes : concatBytes([this.carry, bytes]);
1397
+ if (this.mayFallBack && this.asciiSoFar && !all.includes(0) && !startsWithUtf8(all)) {
1398
+ this.report.warning(
1399
+ "coercion",
1400
+ ENCODING_FALLBACK_CODE,
1401
+ `the input is not valid UTF-8 (near byte ${this.offset}) and declares no encoding; read as windows-1252 (pass the encoding option to choose another)`
1402
+ );
1403
+ this.use("windows-1252", false);
1404
+ return this.decoder.decode(all, { stream });
1405
+ }
1406
+ if (this.encoding === "utf-8") {
1407
+ const after = this.mayFallBack ? " after valid non-ASCII UTF-8 text; pass the encoding option" : "";
1408
+ return this.report.fail(
1409
+ INVALID_UTF8_CODE,
1410
+ `invalid UTF-8 near byte ${this.offset}${after}`,
1411
+ void 0,
1412
+ where
1413
+ );
1414
+ }
1415
+ return this.report.fail(
1416
+ INVALID_ENCODING_CODE,
1417
+ `the bytes near byte ${this.offset} are not valid ${this.encoding}`,
1418
+ void 0,
1419
+ where
1420
+ );
1421
+ }
1422
+ /**
1423
+ * Switch to an encoding.
1424
+ * @param label - the encoding label
1425
+ * @param mayFallBack - whether a UTF-8 failure may switch to windows-1252
1426
+ */
1427
+ use(label, mayFallBack) {
1428
+ this.decoder = new TextDecoder(label, { fatal: true, ignoreBOM: true });
1429
+ this.encoding = this.decoder.encoding;
1430
+ this.mayFallBack = mayFallBack;
1431
+ }
1432
+ }
1433
+ function startsWithUtf8(bytes) {
1434
+ const i = bytes.findIndex((b) => b >= 128);
1435
+ const lead = bytes[i];
1436
+ let length = 0;
1437
+ if (lead >= 194 && lead <= 223) {
1438
+ length = 2;
1439
+ } else if (lead >= 224 && lead <= 239) {
1440
+ length = 3;
1441
+ } else if (lead >= 240 && lead <= 244) {
1442
+ length = 4;
1443
+ }
1444
+ if (i < 0 || length === 0 || i + length > bytes.byteLength) {
1445
+ return false;
1446
+ }
1447
+ try {
1448
+ new TextDecoder("utf-8", { fatal: true }).decode(bytes.subarray(i, i + length));
1449
+ return true;
1450
+ } catch {
1451
+ return false;
1452
+ }
1453
+ }
1454
+ function concatBytes(chunks) {
1455
+ if (chunks.length === 1) {
1456
+ return chunks[0];
1457
+ }
1458
+ const out = new Uint8Array(chunks.reduce((sum, c) => sum + c.byteLength, 0));
1459
+ let offset = 0;
1460
+ for (const chunk of chunks) {
1461
+ out.set(chunk, offset);
1462
+ offset += chunk.byteLength;
1463
+ }
1464
+ return out;
1465
+ }
1280
1466
  const DECODE_SLICE = 256 * 1024;
1281
1467
  const BOM = String.fromCharCode(65279);
1282
1468
  function isImportInput(input) {
@@ -1339,22 +1525,13 @@ async function* textChunks(input, report, options = {}) {
1339
1525
  onProgress?.(done, total ?? void 0);
1340
1526
  return;
1341
1527
  }
1342
- const decoder = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true });
1343
- const decode = (bytes, stream) => {
1344
- try {
1345
- return decoder.decode(bytes, { stream });
1346
- } catch (err) {
1347
- if (err instanceof TypeError) {
1348
- report.fail(INVALID_UTF8_CODE, `invalid UTF-8 near byte ${done}`, void 0, { byteOffset: done });
1349
- }
1350
- throw err;
1351
- }
1352
- };
1528
+ const decoder = new ByteDecoder(report, options);
1353
1529
  if (input instanceof Uint8Array) {
1530
+ decoder.start(input.subarray(0, HEAD_BYTES));
1354
1531
  for (let offset = 0; offset < input.byteLength; offset += DECODE_SLICE) {
1355
1532
  throwIfAborted(signal);
1356
1533
  const slice = input.subarray(offset, Math.min(offset + DECODE_SLICE, input.byteLength));
1357
- const text = emit(decode(slice, offset + DECODE_SLICE < input.byteLength));
1534
+ const text = emit(decoder.decode(slice, offset + DECODE_SLICE < input.byteLength));
1358
1535
  done = Math.min(offset + DECODE_SLICE, input.byteLength);
1359
1536
  if (text.length > 0) {
1360
1537
  yield text;
@@ -1366,17 +1543,38 @@ async function* textChunks(input, report, options = {}) {
1366
1543
  }
1367
1544
  return;
1368
1545
  }
1546
+ const needed = options.declaredEncoding === void 0 ? BOM_BYTES : HEAD_BYTES;
1547
+ let head = [];
1548
+ let headLength = 0;
1549
+ const flushHead = (stream) => {
1550
+ const bytes = concatBytes(head);
1551
+ head = [];
1552
+ headLength = 0;
1553
+ decoder.start(bytes.subarray(0, HEAD_BYTES));
1554
+ return decoder.decode(bytes, stream);
1555
+ };
1369
1556
  const chunks = isReadableStream(input) ? streamChunks(input, signal) : input;
1370
1557
  for await (const chunk of chunks) {
1371
1558
  throwIfAborted(signal);
1372
1559
  let text;
1373
1560
  if (typeof chunk === "string") {
1374
- const pending = decode(new Uint8Array(0), false);
1561
+ let pending = "";
1562
+ if (!decoder.started && headLength > 0) {
1563
+ pending = flushHead(false);
1564
+ } else if (decoder.started) {
1565
+ pending = decoder.decode(new Uint8Array(0), false);
1566
+ }
1375
1567
  text = emit(pending + chunk);
1376
1568
  done += chunk.length;
1377
1569
  } else if (chunk instanceof Uint8Array) {
1378
- text = emit(decode(chunk, true));
1379
1570
  done += chunk.byteLength;
1571
+ if (decoder.started) {
1572
+ text = emit(decoder.decode(chunk, true));
1573
+ } else {
1574
+ head.push(chunk);
1575
+ headLength += chunk.byteLength;
1576
+ text = headLength >= needed ? emit(flushHead(true)) : "";
1577
+ }
1380
1578
  } else {
1381
1579
  throw new GraphFormatError("E_UNSUPPORTED", "an input chunk must be a string or a Uint8Array", {
1382
1580
  reason: "chunk type",
@@ -1388,7 +1586,13 @@ async function* textChunks(input, report, options = {}) {
1388
1586
  }
1389
1587
  onProgress?.(done);
1390
1588
  }
1391
- const tail = emit(decode(new Uint8Array(0), false));
1589
+ let tail = "";
1590
+ if (!decoder.started && headLength > 0) {
1591
+ tail = flushHead(false);
1592
+ } else if (decoder.started) {
1593
+ tail = decoder.decode(new Uint8Array(0), false);
1594
+ }
1595
+ tail = emit(tail);
1392
1596
  if (tail.length > 0) {
1393
1597
  yield tail;
1394
1598
  }
@@ -1605,7 +1809,8 @@ function resolveImportOptions(options, defaults) {
1605
1809
  hyperedges: enumOption("hyperedges", o.hyperedges, "skip", HYPEREDGE_POLICIES),
1606
1810
  errorLimit: errorLimitOption(o.errorLimit),
1607
1811
  signal: signalOption(o.signal),
1608
- onProgress: progressOption(o.onProgress)
1812
+ onProgress: progressOption(o.onProgress),
1813
+ encoding: encodingOption(o.encoding)
1609
1814
  });
1610
1815
  }
1611
1816
  function resolveExportOptions(options) {
@@ -1694,6 +1899,20 @@ function progressOption(value) {
1694
1899
  found: typeof value
1695
1900
  });
1696
1901
  }
1902
+ function encodingOption(value) {
1903
+ if (value === void 0 || value === null) {
1904
+ return null;
1905
+ }
1906
+ const canonical = typeof value === "string" ? canonicalEncoding(value) : null;
1907
+ if (canonical === null) {
1908
+ throw new GraphFormatError(
1909
+ "E_UNSUPPORTED",
1910
+ `option encoding: ${describe(value)} is not an encoding this platform's TextDecoder knows`,
1911
+ { option: "encoding", found: value }
1912
+ );
1913
+ }
1914
+ return canonical;
1915
+ }
1697
1916
  function describe(value) {
1698
1917
  switch (typeof value) {
1699
1918
  case "string":
@@ -1934,7 +2153,7 @@ function formatF32(value) {
1934
2153
  return String(value);
1935
2154
  }
1936
2155
  if (value === 0) {
1937
- return "0";
2156
+ return Object.is(value, -0) ? "-0" : "0";
1938
2157
  }
1939
2158
  for (let digits = 1; digits <= 9; digits++) {
1940
2159
  const text = value.toPrecision(digits);
@@ -1945,7 +2164,7 @@ function formatF32(value) {
1945
2164
  return String(value);
1946
2165
  }
1947
2166
  function formatF64(value) {
1948
- return String(value);
2167
+ return Object.is(value, -0) ? "-0" : String(value);
1949
2168
  }
1950
2169
  function formatDecimal(value, dtype = "f64") {
1951
2170
  if (!Number.isFinite(value)) {
@@ -2032,6 +2251,7 @@ function invalidWeight(value, cause) {
2032
2251
  cause: cause instanceof Error ? cause.message : null
2033
2252
  });
2034
2253
  }
2254
+ const NEGATIVE_ZERO_TEXT = "-0";
2035
2255
  const NUMERIC_DTYPES = /* @__PURE__ */ new Set(["f32", "f64", "i32", "u32", "u8"]);
2036
2256
  function weightFormatter(dtype) {
2037
2257
  switch (dtype) {
@@ -2059,6 +2279,9 @@ function explicitWeights(snapshot) {
2059
2279
  return null;
2060
2280
  }
2061
2281
  const value = shadow.value(e);
2282
+ if (Object.is(value, -0)) {
2283
+ return NEGATIVE_ZERO_TEXT;
2284
+ }
2062
2285
  return integral && Number.isInteger(value) ? formatInteger(value) : format(value);
2063
2286
  }
2064
2287
  };
@@ -2080,6 +2303,9 @@ function explicitWeights(snapshot) {
2080
2303
  value: (e) => weights[e],
2081
2304
  text: (e, integral = false) => {
2082
2305
  const value = weights[e];
2306
+ if (Object.is(value, -0)) {
2307
+ return NEGATIVE_ZERO_TEXT;
2308
+ }
2083
2309
  return integral && Number.isInteger(value) ? formatInteger(value) : formatF32(value);
2084
2310
  }
2085
2311
  };
@@ -2721,99 +2947,102 @@ function toReadableStream(chunks) {
2721
2947
  });
2722
2948
  }
2723
2949
  export {
2724
- TEMPORAL_TEXT_DROPPED_CODE as $,
2725
- MUTUAL_COLUMN as A,
2950
+ SYNTAX_CODE as $,
2951
+ MULTIPLE_GRAPHS_CODE as A,
2726
2952
  BAD_DEFAULT_CODE as B,
2727
2953
  COLUMN_RENAMED_CODE as C,
2728
2954
  DEFAULT_CHUNK_BYTES as D,
2729
2955
  EMPTY_COLUMN_DROPPED_CODE as E,
2730
- MUTUAL_EXPANDED_CODE as F,
2731
- NO_GRAPH_CODE as G,
2956
+ MUTUAL_AS_UNDIRECTED_CODE as F,
2957
+ MUTUAL_COLUMN as G,
2732
2958
  HYPEREDGE_CODE as H,
2733
2959
  ImportReportBuilder as I,
2734
- OPTION_IGNORED_CODE as J,
2735
- PARENTS_DROPPED_CODE as K,
2960
+ MUTUAL_EXPANDED_CODE as J,
2961
+ NO_GRAPH_CODE as K,
2736
2962
  LOSS as L,
2737
2963
  MISSING_ENDPOINT_CODE as M,
2738
2964
  NO_CAPABILITIES as N,
2739
2965
  OPTIONS_GAINED_CODE as O,
2740
- PAIR_COLUMN as P,
2741
- PARSE_ERROR_CODE as Q,
2742
- PRECISION_CODE as R,
2743
- RENAMED_CODE as S,
2744
- ROLE_ASSUMED_CODE as T,
2745
- ROLE_DROPPED_CODE as U,
2746
- ROLE_TAKEN_CODE as V,
2747
- SINK_OPTION_CODE as W,
2748
- STORAGE_CLASS_CODE as X,
2749
- STRAY_TEXT_CODE as Y,
2750
- SYNTAX_CODE as Z,
2751
- TEMPORAL_DROPPED_CODE as _,
2966
+ OPTION_IGNORED_CODE as P,
2967
+ PAIR_COLUMN as Q,
2968
+ PARENTS_DROPPED_CODE as R,
2969
+ PARSE_ERROR_CODE as S,
2970
+ PRECISION_CODE as T,
2971
+ RENAMED_CODE as U,
2972
+ ROLE_ASSUMED_CODE as V,
2973
+ ROLE_DROPPED_CODE as W,
2974
+ ROLE_TAKEN_CODE as X,
2975
+ SINK_OPTION_CODE as Y,
2976
+ STORAGE_CLASS_CODE as Z,
2977
+ STRAY_TEXT_CODE as _,
2752
2978
  throwIfAborted as a,
2753
- TEXT_INFERRED_CODE as a0,
2754
- UNKNOWN_ATTR_TYPE_CODE as a1,
2755
- UNKNOWN_ELEMENT_CODE as a2,
2756
- UNKNOWN_PARENT_CODE as a3,
2757
- UNKNOWN_TYPE_CODE as a4,
2758
- WEIGHT_KEY_CLASH_CODE as a5,
2759
- XML_ILLEGAL_CHAR_CODE as a6,
2760
- XML_SYNTAX_CODE as a7,
2761
- canonicalId as a8,
2762
- capabilities as a9,
2763
- reportUnusedOptions as aA,
2764
- resolveExportOptions as aB,
2765
- resolveImportOptions as aC,
2766
- sanitizeIds as aD,
2767
- toReadableStream as aE,
2768
- isNameChar as aF,
2769
- countMixedEdges as aG,
2770
- weightFromValue as aH,
2771
- uniqueColumnName as aI,
2772
- TIME_TEXT_ROLE as aJ,
2773
- TIME_TEXT_SUFFIX as aK,
2774
- declareAttribute as aL,
2775
- parseDeclaredTemporal as aM,
2776
- parseDeclaredValue as aN,
2777
- losesPrecision as aO,
2778
- parseTimeText as aP,
2779
- splitListText as aQ,
2780
- timeTextCompanion as aR,
2781
- parseDecimalText as aS,
2782
- formatTimeValue as aT,
2783
- mapDeclaredType as aU,
2784
- joinListText as aV,
2785
- formatTemporal as aW,
2786
- DictHeuristic as aX,
2787
- DICT_SAMPLE_ROWS as aY,
2788
- takenIn as aZ,
2789
- declareOn as a_,
2790
- checkCapabilities as aa,
2791
- coerceId as ab,
2792
- coerceIdText as ac,
2793
- collectBytes as ad,
2794
- declareCompanion as ae,
2795
- declareResolved as af,
2796
- decodeChunks as ag,
2797
- encodeChunks as ah,
2798
- explicitWeights as ai,
2799
- formatDecimal as aj,
2800
- formatF32 as ak,
2801
- formatF64 as al,
2802
- formatGmlReal as am,
2803
- formatInteger as an,
2804
- inputLength as ao,
2805
- isAbortError as ap,
2806
- isCanonicalIntegerText as aq,
2807
- isImportInput as ar,
2808
- isNmtoken as as,
2809
- isWeightField as at,
2810
- joinText as au,
2811
- mangleNmtoken as av,
2812
- pairFolding as aw,
2813
- parseWeightText as ax,
2814
- readText as ay,
2815
- reportSinkOptions as az,
2979
+ DICT_SAMPLE_ROWS as a$,
2980
+ TEMPORAL_DROPPED_CODE as a0,
2981
+ TEMPORAL_TEXT_DROPPED_CODE as a1,
2982
+ TEXT_INFERRED_CODE as a2,
2983
+ UNKNOWN_ATTR_TYPE_CODE as a3,
2984
+ UNKNOWN_ELEMENT_CODE as a4,
2985
+ UNKNOWN_ENCODING_CODE as a5,
2986
+ UNKNOWN_PARENT_CODE as a6,
2987
+ UNKNOWN_TYPE_CODE as a7,
2988
+ WEIGHT_KEY_CLASH_CODE as a8,
2989
+ XML_ILLEGAL_CHAR_CODE as a9,
2990
+ parseWeightText as aA,
2991
+ readText as aB,
2992
+ reportSinkOptions as aC,
2993
+ reportUnusedOptions as aD,
2994
+ resolveExportOptions as aE,
2995
+ resolveImportOptions as aF,
2996
+ sanitizeIds as aG,
2997
+ toReadableStream as aH,
2998
+ isNameChar as aI,
2999
+ countMixedEdges as aJ,
3000
+ weightFromValue as aK,
3001
+ uniqueColumnName as aL,
3002
+ TIME_TEXT_ROLE as aM,
3003
+ TIME_TEXT_SUFFIX as aN,
3004
+ declareAttribute as aO,
3005
+ parseDeclaredTemporal as aP,
3006
+ parseDeclaredValue as aQ,
3007
+ losesPrecision as aR,
3008
+ parseTimeText as aS,
3009
+ splitListText as aT,
3010
+ timeTextCompanion as aU,
3011
+ parseDecimalText as aV,
3012
+ formatTimeValue as aW,
3013
+ mapDeclaredType as aX,
3014
+ joinListText as aY,
3015
+ formatTemporal as aZ,
3016
+ DictHeuristic as a_,
3017
+ XML_SYNTAX_CODE as aa,
3018
+ canonicalId as ab,
3019
+ capabilities as ac,
3020
+ checkCapabilities as ad,
3021
+ coerceId as ae,
3022
+ coerceIdText as af,
3023
+ collectBytes as ag,
3024
+ declareCompanion as ah,
3025
+ declareResolved as ai,
3026
+ decodeChunks as aj,
3027
+ encodeChunks as ak,
3028
+ explicitWeights as al,
3029
+ formatDecimal as am,
3030
+ formatF32 as an,
3031
+ formatF64 as ao,
3032
+ formatGmlReal as ap,
3033
+ formatInteger as aq,
3034
+ inputLength as ar,
3035
+ isAbortError as as,
3036
+ isCanonicalIntegerText as at,
3037
+ isImportInput as au,
3038
+ isNmtoken as av,
3039
+ isWeightField as aw,
3040
+ joinText as ax,
3041
+ mangleNmtoken as ay,
3042
+ pairFolding as az,
2816
3043
  BAD_OPTIONS_CODE as b,
3044
+ takenIn as b0,
3045
+ declareOn as b1,
2817
3046
  COLUMN_RENAMED_LOSS_CODE as c,
2818
3047
  COUNT_HINT_CODE as d,
2819
3048
  DEFAULT_ERROR_LIMIT as e,
@@ -2825,18 +3054,18 @@ export {
2825
3054
  DUPLICATE_NODE_CODE as k,
2826
3055
  DirectionResolver as l,
2827
3056
  EMPTY_INPUT_CODE as m,
2828
- ID_MERGED_CODE as n,
2829
- ID_TEXT_COLLISION_CODE as o,
2830
- ID_TEXT_TYPE_CODE as p,
2831
- INTEGRAL_F64_CODE as q,
2832
- INVALID_UTF8_CODE as r,
2833
- IdCoercer as s,
3057
+ ENCODING_FALLBACK_CODE as n,
3058
+ ID_MERGED_CODE as o,
3059
+ ID_TEXT_COLLISION_CODE as p,
3060
+ ID_TEXT_TYPE_CODE as q,
3061
+ INTEGRAL_F64_CODE as r,
3062
+ INVALID_ENCODING_CODE as s,
2834
3063
  textChunks as t,
2835
- ImportError as u,
2836
- LineReader as v,
2837
- MISSING_ID_CODE as w,
2838
- MIXED_DIRECTION_CODE as x,
2839
- MULTIPLE_GRAPHS_CODE as y,
2840
- MUTUAL_AS_UNDIRECTED_CODE as z
3064
+ INVALID_UTF8_CODE as u,
3065
+ IdCoercer as v,
3066
+ ImportError as w,
3067
+ LineReader as x,
3068
+ MISSING_ID_CODE as y,
3069
+ MIXED_DIRECTION_CODE as z
2841
3070
  };
2842
- //# sourceMappingURL=writer-DxSKC7TL.js.map
3071
+ //# sourceMappingURL=writer-BdMak4_J.js.map