@graphty/graph-io 0.3.2 → 0.3.4

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 (91) hide show
  1. package/README.md +17 -4
  2. package/dist/chunks/{escape-CKied3Ri.js → escape-DXbOoLKl.js} +23 -5
  3. package/dist/chunks/{escape-CKied3Ri.js.map → escape-DXbOoLKl.js.map} +1 -1
  4. package/dist/chunks/{importer-DbMrAR_w.js → importer-B9qF4e32.js} +37 -2
  5. package/dist/chunks/importer-B9qF4e32.js.map +1 -0
  6. package/dist/chunks/{importer-DkzjTvHc.js → importer-BOxwmef_.js} +360 -16
  7. package/dist/chunks/importer-BOxwmef_.js.map +1 -0
  8. package/dist/chunks/{importer-D5pAsweZ.js → importer-C2caVvl6.js} +2 -2
  9. package/dist/chunks/{importer-D5pAsweZ.js.map → importer-C2caVvl6.js.map} +1 -1
  10. package/dist/chunks/{importer-C6QcIRIb.js → importer-xoHpRG5x.js} +2 -2
  11. package/dist/chunks/{importer-C6QcIRIb.js.map → importer-xoHpRG5x.js.map} +1 -1
  12. package/dist/csv.js +1 -1
  13. package/dist/dot.js +1 -1
  14. package/dist/gexf.js +1 -1
  15. package/dist/gml.js +34 -13
  16. package/dist/gml.js.map +1 -1
  17. package/dist/graph-io.js +9 -9
  18. package/dist/graph-io.js.map +1 -1
  19. package/dist/graphml.js +1 -1
  20. package/dist/json.js +1 -1
  21. package/dist/neo4j.js +60 -2
  22. package/dist/neo4j.js.map +1 -1
  23. package/dist/pajek.js +1 -1
  24. package/dist/src/common/escape.d.ts +4 -2
  25. package/dist/src/common/escape.d.ts.map +1 -1
  26. package/dist/src/common/escape.js +31 -5
  27. package/dist/src/common/escape.js.map +1 -1
  28. package/dist/src/formats/gml/importer.d.ts +2 -0
  29. package/dist/src/formats/gml/importer.d.ts.map +1 -1
  30. package/dist/src/formats/gml/importer.js +19 -5
  31. package/dist/src/formats/gml/importer.js.map +1 -1
  32. package/dist/src/formats/gml/index.d.ts +2 -0
  33. package/dist/src/formats/gml/index.d.ts.map +1 -1
  34. package/dist/src/formats/gml/index.js +3 -1
  35. package/dist/src/formats/gml/index.js.map +1 -1
  36. package/dist/src/formats/gml/syntax.d.ts +2 -0
  37. package/dist/src/formats/gml/syntax.d.ts.map +1 -1
  38. package/dist/src/formats/gml/syntax.js +8 -1
  39. package/dist/src/formats/gml/syntax.js.map +1 -1
  40. package/dist/src/formats/graphml/constants.d.ts +4 -0
  41. package/dist/src/formats/graphml/constants.d.ts.map +1 -1
  42. package/dist/src/formats/graphml/constants.js +4 -0
  43. package/dist/src/formats/graphml/constants.js.map +1 -1
  44. package/dist/src/formats/graphml/importer.d.ts.map +1 -1
  45. package/dist/src/formats/graphml/importer.js +28 -0
  46. package/dist/src/formats/graphml/importer.js.map +1 -1
  47. package/dist/src/formats/json/dialect.d.ts +21 -4
  48. package/dist/src/formats/json/dialect.d.ts.map +1 -1
  49. package/dist/src/formats/json/dialect.js +29 -4
  50. package/dist/src/formats/json/dialect.js.map +1 -1
  51. package/dist/src/formats/json/exporter.d.ts.map +1 -1
  52. package/dist/src/formats/json/exporter.js +27 -7
  53. package/dist/src/formats/json/exporter.js.map +1 -1
  54. package/dist/src/formats/json/importer.d.ts +19 -4
  55. package/dist/src/formats/json/importer.d.ts.map +1 -1
  56. package/dist/src/formats/json/importer.js +369 -8
  57. package/dist/src/formats/json/importer.js.map +1 -1
  58. package/dist/src/formats/json/index.d.ts +1 -1
  59. package/dist/src/formats/json/index.d.ts.map +1 -1
  60. package/dist/src/formats/json/index.js +1 -1
  61. package/dist/src/formats/json/index.js.map +1 -1
  62. package/dist/src/formats/neo4j/importer.d.ts +5 -0
  63. package/dist/src/formats/neo4j/importer.d.ts.map +1 -1
  64. package/dist/src/formats/neo4j/importer.js +57 -1
  65. package/dist/src/formats/neo4j/importer.js.map +1 -1
  66. package/dist/src/formats/neo4j/index.d.ts +2 -0
  67. package/dist/src/formats/neo4j/index.d.ts.map +1 -1
  68. package/dist/src/formats/neo4j/index.js +3 -1
  69. package/dist/src/formats/neo4j/index.js.map +1 -1
  70. package/dist/src/index.d.ts +1 -1
  71. package/dist/src/index.d.ts.map +1 -1
  72. package/dist/src/index.js.map +1 -1
  73. package/dist/src/sniff.d.ts +3 -3
  74. package/dist/src/sniff.d.ts.map +1 -1
  75. package/dist/src/sniff.js.map +1 -1
  76. package/package.json +2 -2
  77. package/src/common/escape.ts +5 -4
  78. package/src/formats/json/dialect.ts +40 -6
  79. package/src/formats/json/exporter.ts +28 -7
  80. package/src/formats/json/importer.ts +411 -21
  81. package/src/formats/json/index.ts +7 -1
  82. package/src/formats/neo4j/exporter.ts +43 -6
  83. package/src/formats/neo4j/importer.ts +56 -11
  84. package/src/formats/neo4j/index.ts +10 -3
  85. package/src/formats/pajek/exporter.ts +3 -1
  86. package/src/formats/pajek/importer.ts +284 -60
  87. package/src/formats/pajek/syntax.ts +98 -12
  88. package/src/index.ts +2 -0
  89. package/src/sniff.ts +3 -3
  90. package/dist/chunks/importer-DbMrAR_w.js.map +0 -1
  91. package/dist/chunks/importer-DkzjTvHc.js.map +0 -1
package/README.md CHANGED
@@ -7,7 +7,8 @@
7
7
 
8
8
  Importers and exporters for the [@graphty/graph-format](https://www.npmjs.com/package/@graphty/graph-format)
9
9
  snapshot: GEXF, GraphML, GML, DOT (Graphviz), Pajek NET, CSV / TSV, JSON (NetworkX node-link, d3,
10
- JSON Graph Format, Cytoscape, graphology, vis.js) and Neo4j (`neo4j-admin import` CSV).
10
+ JSON Graph Format, Cytoscape, graphology, vis.js; NetworkX adjacency_data and tree_data are read
11
+ only) and Neo4j (`neo4j-admin import` CSV).
11
12
 
12
13
  Every importer streams its input into a `GraphSink` (a `GraphBuilder` or your own sink) one scalar at
13
14
  a time and reports what it could not represent instead of dropping it; every exporter says what it
@@ -195,7 +196,10 @@ losses and format rules, in addition to the table:
195
196
  a count the sink cannot reserve is fatal); `*Arcs` / `*Edges` sections give per-section
196
197
  direction; time intervals map to the spells role; vertex / line parameters are plain columns read
197
198
  through the 5.1 text grammar (`2.0` stays f64, lexical forms of a string column are kept); a
198
- `.paj` project file's `*Partition` / `*Vector` sections are skipped with an issue. Nodes are
199
+ `.paj` project file's `*Partition` / `*Vector` objects become the node columns `partition` (i32)
200
+ and `vector` (f64) (a second one `partition#2`, ...; their Pajek names in
201
+ `meta.extra.pajek.objects`), and other project sections (`*Events`, ...) are skipped with a
202
+ warning; a two-mode `*Vertices N N1` reads its `*Matrix` as N1 rows of N - N1 columns. Nodes are
199
203
  always written 1..N (`W_ID_RENUMBERED`: the id text is kept as the label of a node without a
200
204
  label value, a node with one loses its id; `W_PAJEK_LABEL_GAINED` when a line's parameters force
201
205
  a label); `sanitizeIds: "mangle"` also writes every renumbered vertex's original id as a
@@ -220,10 +224,19 @@ losses and format rules, in addition to the table:
220
224
  dialect has no slot for. Edge ids exist in JGF, Cytoscape, graphology and vis only; positions in
221
225
  Cytoscape only. A repeated node id is merged with `W_DUPLICATE_NODE`, a repeated edge id skipped
222
226
  with `E_DUPLICATE_EDGE_ID`; an out-of-range d3 index link is `E_BAD_INDEX`. Non-finite numbers
223
- are written as `null` and reported.
227
+ are written as `null` and reported. NetworkX `adjacency_data` (`nodes` plus an `adjacency` list
228
+ per node; an undirected file lists each edge from both ends and it is read once) and `tree_data`
229
+ (nested `id` / `children`, read as a directed tree) are read but not written: a re-export writes
230
+ node-link. The bare `NaN`, `Infinity` and `-Infinity` that Python's json module writes are read as
231
+ numbers (`W_JSON_NONSTANDARD_NUMBER`), and an integer literal beyond 2^53 keeps its exact digits as
232
+ a string (`W_JSON_BIG_INTEGER`), so two large ids never round to one; the exporter writes an
233
+ integral number that large in exponent form (`1e+20`) so it re-imports as a number.
224
234
  - **Neo4j**: `neo4j-admin import` headers (`:ID`, `:LABEL`, `:START_ID`, `:END_ID`, `:TYPE`, typed
225
235
  properties, id spaces, arrays); one file may hold several sections; a `weight` property becomes
226
- THE weight; a quoted empty `:ID` is the id `""`. Everything is directed (an undirected snapshot,
236
+ THE weight; a quoted empty `:ID` is the id `""`. A node of an id space (`:ID(Product)`) is stored
237
+ under the string id `Product:1`, with its id text in the `originalId` column and its space in
238
+ `idSpace`, so the same id in two spaces stays two nodes; `:START_ID(Space)` / `:END_ID(Space)`
239
+ resolve inside their space, and the exporter writes the id text back. Everything is directed (an undirected snapshot,
227
240
  or the folded pairs of a mixed one under `onMixedDirection: "directed"` / `"undirected"`, is
228
241
  written with a `W_NEO4J_UNDIRECTED_AS_DIRECTED` note); `.text` companions keep the source text of
229
242
  temporal values whose canonical form differs; a dict column reads back as string and a position
@@ -853,9 +853,22 @@ function quoteGmlString(text) {
853
853
  });
854
854
  return `"${escaped}"`;
855
855
  }
856
- const GML_ENTITY = /&(#[0-9]+|#x[0-9a-fA-F]+|amp|quot|lt|gt|apos);/g;
857
- const GML_NAMED = { amp: "&", quot: '"', lt: "<", gt: ">", apos: "'" };
858
- function decodeGmlString(body) {
856
+ const GML_ENTITY = /&(#[0-9]+|#x[0-9a-fA-F]+|[A-Za-z][A-Za-z0-9]*);/g;
857
+ const GML_NAMED = (() => {
858
+ const table = /* @__PURE__ */ new Map([
859
+ ["amp", "&"],
860
+ ["quot", '"'],
861
+ ["lt", "<"],
862
+ ["gt", ">"],
863
+ ["apos", "'"]
864
+ ]);
865
+ const latin1 = "nbsp iexcl cent pound curren yen brvbar sect uml copy ordf laquo not shy reg macr deg plusmn sup2 sup3 acute micro para middot cedil sup1 ordm raquo frac14 frac12 frac34 iquest Agrave Aacute Acirc Atilde Auml Aring AElig Ccedil Egrave Eacute Ecirc Euml Igrave Iacute Icirc Iuml ETH Ntilde Ograve Oacute Ocirc Otilde Ouml times Oslash Ugrave Uacute Ucirc Uuml Yacute THORN szlig agrave aacute acirc atilde auml aring aelig ccedil egrave eacute ecirc euml igrave iacute icirc iuml eth ntilde ograve oacute ocirc otilde ouml divide oslash ugrave uacute ucirc uuml yacute thorn yuml".split(" ");
866
+ latin1.forEach((name, i) => {
867
+ table.set(name, String.fromCharCode(160 + i));
868
+ });
869
+ return table;
870
+ })();
871
+ function decodeGmlString(body, onUnknown) {
859
872
  return body.replace(GML_ENTITY, (whole, entity) => {
860
873
  if (entity.startsWith("#x")) {
861
874
  return String.fromCodePoint(Number.parseInt(entity.slice(2), 16));
@@ -863,7 +876,12 @@ function decodeGmlString(body) {
863
876
  if (entity.startsWith("#")) {
864
877
  return String.fromCodePoint(Number.parseInt(entity.slice(1), 10));
865
878
  }
866
- return GML_NAMED[entity] ?? whole;
879
+ const known = GML_NAMED.get(entity);
880
+ if (known === void 0) {
881
+ onUnknown?.(whole);
882
+ return whole;
883
+ }
884
+ return known;
867
885
  });
868
886
  }
869
887
  const DOT_NUMERAL = /^-?(\.[0-9]+|[0-9]+(\.[0-9]*)?)$/;
@@ -941,4 +959,4 @@ export {
941
959
  tokenizeXml as t,
942
960
  xmlIllegalTextNotes as x
943
961
  };
944
- //# sourceMappingURL=escape-CKied3Ri.js.map
962
+ //# sourceMappingURL=escape-DXbOoLKl.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"escape-CKied3Ri.js","sources":["../../src/common/xml.ts","../../src/common/escape.ts"],"sourcesContent":["/**\n * The streaming XML tokenizer shared by the GEXF and GraphML importers (design sections 8.2 and\n * 8.4): SAX-style start / end / text events over the text chunks of the common reader, so both\n * importers run in one pass with bounded memory and every issue carries a line number.\n *\n * Cost model: every character of the input is scanned once. A token that spans many chunks (a\n * long attribute value, comment, CDATA section or name) resumes where the previous chunk left off\n * instead of re-reading the token from its `<`, and line numbers are counted from a cached next\n * line-break position, so a document without line breaks costs the same as one with them.\n *\n * What it handles: the XML declaration and processing instructions (skipped), comments (skipped),\n * CDATA sections (text), a DOCTYPE with an internal subset (skipped; entity declarations are not\n * expanded, so an unknown entity reference is a syntax error), the five predefined entities and\n * numeric character references (decimal and hexadecimal) in text and attribute values, attribute\n * value whitespace normalisation, end-of-line normalisation (CR LF and lone CR become LF), and\n * well-formedness: matching end tags, one root element, no text outside it, no duplicate\n * attributes, no unterminated markup at the end of the input. Namespaces are not resolved; element\n * and attribute names are reported as written (with their prefix).\n *\n * Why not fast-xml-parser: its XMLParser accepts mismatched and unclosed tags without error, does\n * not decode numeric character references unless the deprecated `htmlEntities` option is set, and\n * its validator (`XMLValidator`, the `parse(xml, true)` overload) and `XMLBuilder` are deprecated in\n * 5.x, which the root lint's `no-deprecated` rule forbids using; so the malformed corpus could not\n * be rejected and attribute values written by the common `escapeXmlAttribute` (`&#10;`) could not\n * be read back.\n */\n\nimport { type Column, type GraphSnapshot } from \"@graphty/graph-format\";\n\nimport { type LossNote } from \"../types.js\";\nimport { XML_ILLEGAL_CHAR_CODE } from \"./codes.js\";\nimport { isNameChar } from \"./export.js\";\n\n/** The events of the tokenizer; every callback is synchronous. */\nexport interface XmlHandler {\n /**\n * An element starts (a self-closing element produces start then end).\n * @param name - the element name as written, prefix included\n * @param attrs - the attributes, entities decoded, in document order\n * @param line - the 1-based line of the `<`\n */\n start(name: string, attrs: ReadonlyMap<string, string>, line: number): void;\n /**\n * An element ends.\n * @param name - the element name\n * @param line - the 1-based line of the end tag (or of the self-closing start tag)\n */\n end(name: string, line: number): void;\n /**\n * Character data between two tags (entities decoded, CDATA included), one call per run;\n * whitespace-only runs are delivered too.\n * @param text - the text\n * @param line - the 1-based line where the run starts\n */\n text(text: string, line: number): void;\n}\n\n/** A well-formedness or syntax error, with the line it was found on. */\nexport class XmlSyntaxError extends Error {\n /** The 1-based line. */\n readonly line: number;\n\n /**\n * Create the error.\n * @param message - a plain-ASCII message\n * @param line - the 1-based line\n */\n constructor(message: string, line: number) {\n super(message);\n this.name = \"XmlSyntaxError\";\n this.line = line;\n }\n}\n\nconst NAMED_ENTITIES: Readonly<Record<string, string>> = {\n lt: \"<\",\n gt: \">\",\n amp: \"&\",\n quot: '\"',\n apos: \"'\",\n};\n\nconst LT = 60;\nconst GT = 62;\nconst SLASH = 47;\nconst EQUALS = 61;\nconst QUOTE = 34;\nconst APOS = 39;\nconst OPEN_BRACKET = 91;\nconst CLOSE_BRACKET = 93;\nconst BANG = 33;\nconst DASH = 45;\n\n/** The longest entity reference held back at a chunk boundary (`&#x10FFFF;` is 10 characters). */\nconst MAX_ENTITY_LENGTH = 16;\n\n/** Markup shorter than this (`<![CDATA[` is 9 characters) cannot be classified yet. */\nconst MIN_DECIDABLE_MARKUP = 9;\n\n/**\n * Whether a char code is XML whitespace (space, tab, LF, CR).\n * @param c - the char code\n * @returns true for whitespace\n */\nfunction isSpace(c: number): boolean {\n return c === 32 || c === 9 || c === 10 || c === 13;\n}\n\n/**\n * Whether a code point may start an XML Name: a NameChar that is not a digit, `-`, `.`, U+00B7,\n * a combining character (U+0300..U+036F) or U+203F / U+2040.\n * @param cp - the code point\n * @returns true for a NameStartChar\n */\nfunction isNameStart(cp: number): boolean {\n if (!isNameChar(cp)) {\n return false;\n }\n if ((cp >= 0x30 && cp <= 0x39) || cp === 0x2d || cp === 0x2e || cp === 0xb7) {\n return false;\n }\n return !(cp >= 0x300 && cp <= 0x36f) && cp !== 0x203f && cp !== 0x2040;\n}\n\n/** ASCII code -> whether it is a NameStartChar / NameChar, for the fast path of readName(). */\nconst ASCII_NAME_START = new Uint8Array(128);\nconst ASCII_NAME_CHAR = new Uint8Array(128);\nfor (let c = 0; c < 128; c++) {\n ASCII_NAME_START[c] = isNameStart(c) ? 1 : 0;\n ASCII_NAME_CHAR[c] = isNameChar(c) ? 1 : 0;\n}\n\n/**\n * Characters XML 1.0 forbids in a document (the Char production): C0 controls other than tab, LF\n * and CR, U+FFFE / U+FFFF, and lone surrogates (the `u` flag makes the surrogate class match only\n * an unpaired one). Built from char codes so no control character appears in the source.\n */\nconst ILLEGAL_CHAR = new RegExp(\n `[${String.fromCharCode(0)}-${String.fromCharCode(8)}${String.fromCharCode(11)}${String.fromCharCode(12)}` +\n `${String.fromCharCode(14)}-${String.fromCharCode(31)}\\\\uFFFE\\\\uFFFF\\\\uD800-\\\\uDFFF]`,\n \"u\",\n);\n\n/**\n * Whether a text holds a character XML 1.0 forbids (see ILLEGAL_CHAR); such a character cannot be\n * written even as a character reference, so a conforming parser rejects the whole document.\n * @param text - the text\n * @returns true when the text cannot appear in an XML 1.0 document\n */\nexport function hasIllegalXmlChar(text: string): boolean {\n return ILLEGAL_CHAR.test(text);\n}\n\n/**\n * The loss notes of the texts a snapshot holds that no XML 1.0 document can carry (see\n * hasIllegalXmlChar): one E_XML_ILLEGAL_CHAR note per column (node, edge and graph string / dict /\n * list-of-text columns) and one for the ids, each counting the affected rows; export() throws on\n * the first such text. Shared by the GEXF and GraphML exporters' check().\n * @param snapshot - the snapshot\n * @returns the notes, empty when every text is writable\n */\nexport function xmlIllegalTextNotes(snapshot: GraphSnapshot): LossNote[] {\n const notes: LossNote[] = [];\n let ids = 0;\n for (let i = 0; i < snapshot.nodeCount; i++) {\n const id = snapshot.ids.idOf(i);\n if (typeof id === \"string\" && hasIllegalXmlChar(id)) {\n ids++;\n }\n }\n if (ids > 0) {\n notes.push(\n Object.freeze({\n code: XML_ILLEGAL_CHAR_CODE,\n message: `${ids} node id(s) hold a character XML 1.0 cannot carry; export() will throw`,\n column: null,\n count: ids,\n }),\n );\n }\n for (const [domain, table] of [\n [\"node\", snapshot.nodes],\n [\"edge\", snapshot.edges],\n [\"graph\", snapshot.graph],\n ] as const) {\n for (const column of table) {\n const bad = countIllegalRows(column);\n if (bad > 0) {\n notes.push(\n Object.freeze({\n code: XML_ILLEGAL_CHAR_CODE,\n message: `${domain} column \"${column.meta.name}\": ${bad} value(s) hold a character XML 1.0 cannot carry; export() will throw`,\n column: column.meta.name,\n count: bad,\n }),\n );\n }\n }\n }\n return notes;\n}\n\n/**\n * How many set rows of a text column hold an XML-illegal character.\n * @param column - the column\n * @returns the count; 0 for a non-text column\n */\nfunction countIllegalRows(column: Column): number {\n let bad = 0;\n if (column.dtype === \"string\" || column.dtype === \"dict\") {\n for (let r = 0; r < column.length; r++) {\n if (column.isSet(r) && hasIllegalXmlChar(column.value(r) as string)) {\n bad++;\n }\n }\n } else if (column.dtype === \"list\" && (column.meta.itemDtype === \"string\" || column.meta.itemDtype === \"dict\")) {\n for (let r = 0; r < column.length; r++) {\n if (\n column.isSet(r) &&\n column.sliceOf(r).some((item) => typeof item === \"string\" && hasIllegalXmlChar(item))\n ) {\n bad++;\n }\n }\n }\n return bad;\n}\n\n/** The encoding pseudo-attribute of an XML declaration at the very start of a document. */\nconst XML_DECLARED_ENCODING = /^<\\?xml\\s[^>]*?\\bencoding\\s*=\\s*[\"']([A-Za-z][A-Za-z0-9._-]*)[\"']/;\n\n/**\n * The encoding an XML document declares in its prolog (`<?xml version=\"1.0\" encoding=\"...\"?>`),\n * for the shared byte decoder (common/input.ts).\n * @param head - the start of the document, decoded as windows-1252\n * @returns the declared label, or null when there is no declaration or it names no encoding\n */\nexport function xmlDeclaredEncoding(head: string): string | null {\n const match = XML_DECLARED_ENCODING.exec(head);\n return match === null ? null : match[1];\n}\n\n/**\n * Whether a text is an XML Name.\n * @param text - the text\n * @returns true for a well-formed name\n */\nexport function isXmlName(text: string): boolean {\n if (text.length === 0) {\n return false;\n }\n let first = true;\n for (const ch of text) {\n const cp = ch.codePointAt(0);\n if (cp === undefined || (first ? !isNameStart(cp) : !isNameChar(cp))) {\n return false;\n }\n first = false;\n }\n return true;\n}\n\n/**\n * Whether a code point is a legal XML 1.0 character.\n * @param cp - the code point\n * @returns true when a character reference may produce it\n */\nfunction isXmlChar(cp: number): boolean {\n return (\n cp === 0x9 ||\n cp === 0xa ||\n cp === 0xd ||\n (cp >= 0x20 && cp <= 0xd7ff) ||\n (cp >= 0xe000 && cp <= 0xfffd) ||\n (cp >= 0x10000 && cp <= 0x10ffff)\n );\n}\n\n/**\n * Decode the predefined entities and character references of a text.\n * @param raw - the text as written\n * @param line - the line, for errors\n * @returns the decoded text\n */\nexport function decodeEntities(raw: string, line: number): string {\n let amp = raw.indexOf(\"&\");\n if (amp < 0) {\n return raw;\n }\n let out = \"\";\n let start = 0;\n while (amp >= 0) {\n out += raw.slice(start, amp);\n const semi = raw.indexOf(\";\", amp + 1);\n if (semi < 0) {\n throw new XmlSyntaxError(\"unterminated entity reference\", line);\n }\n const name = raw.slice(amp + 1, semi);\n if (name.startsWith(\"#\")) {\n const hex = name.startsWith(\"#x\") || name.startsWith(\"#X\");\n const digits = name.slice(hex ? 2 : 1);\n const ok = hex ? /^[0-9a-fA-F]{1,6}$/.test(digits) : /^[0-9]{1,7}$/.test(digits);\n const cp = ok ? Number.parseInt(digits, hex ? 16 : 10) : -1;\n if (cp < 0 || !isXmlChar(cp)) {\n throw new XmlSyntaxError(`invalid character reference &${name};`, line);\n }\n out += String.fromCodePoint(cp);\n } else {\n const value = NAMED_ENTITIES[name];\n if (value === undefined) {\n throw new XmlSyntaxError(`unknown entity &${name};`, line);\n }\n out += value;\n }\n start = semi + 1;\n amp = raw.indexOf(\"&\", start);\n }\n return out + raw.slice(start);\n}\n\n/**\n * Whether a text is whitespace only.\n * @param text - the text\n * @returns true when every character is XML whitespace (also for an empty text)\n */\nexport function isWhitespace(text: string): boolean {\n for (let i = 0; i < text.length; i++) {\n if (!isSpace(text.charCodeAt(i))) {\n return false;\n }\n }\n return true;\n}\n\n/**\n * The local part of a possibly prefixed XML name.\n * @param name - the name as written\n * @returns the text after the last colon, or the name itself\n */\nexport function localName(name: string): string {\n const colon = name.lastIndexOf(\":\");\n return colon < 0 ? name : name.slice(colon + 1);\n}\n\n/**\n * Tokenize XML text arriving in chunks and deliver events to a handler. Throws XmlSyntaxError on\n * malformed input; any error the handler throws propagates unchanged.\n * @param chunks - the text (already UTF-8 decoded, BOM removed)\n * @param handler - the event sink\n */\nexport async function tokenizeXml(chunks: AsyncIterable<string>, handler: XmlHandler): Promise<void> {\n const tokenizer = new XmlTokenizer(handler);\n for await (const chunk of chunks) {\n tokenizer.push(chunk);\n }\n tokenizer.finish();\n}\n\n/** The result of parsing one start tag out of the buffer. */\ninterface StartTag {\n /** The element name. */\n readonly name: string;\n /** The attributes. */\n readonly attrs: Map<string, string>;\n /** Whether the tag ends with `/>`. */\n readonly selfClosing: boolean;\n /** The buffer index one past the `>`. */\n readonly end: number;\n}\n\n/** The kinds of markup whose end may lie in a later chunk. */\ntype PendingKind = \"decl\" | \"comment\" | \"cdata\" | \"pi\" | \"endtag\" | \"doctype\" | \"starttag\";\n\n/** The terminator of each fixed-terminator markup kind. */\nconst TERMINATORS: Readonly<Partial<Record<PendingKind, string>>> = {\n comment: \"-->\",\n cdata: \"]]>\",\n pi: \"?>\",\n endtag: \">\",\n};\n\n/**\n * An incomplete piece of markup at the end of the input so far: its text pieces (never joined\n * until the end is found, so a token spanning many chunks costs its length once) and the state\n * the terminator scan is in. `tail` holds the last characters of the pieces a fixed terminator\n * could straddle; `quote` is the open quote character (0 outside a value) of a start tag or a\n * DOCTYPE; `depth`, `comment` and `run` track a DOCTYPE's internal subset.\n */\ninterface Pending {\n kind: PendingKind;\n readonly pieces: string[];\n tail: string;\n quote: number;\n depth: number;\n comment: boolean;\n run: number;\n}\n\n/**\n * The tokenizer state: the unconsumed tail of the input, the current line, the open element\n * stack and the text run being accumulated. `push()` chunks, then `finish()`.\n */\nexport class XmlTokenizer {\n private readonly handler: XmlHandler;\n\n /** Unconsumed input that is not part of a pending token: at most a held-back entity or the last chunk. */\n private buffer = \"\";\n\n /** The markup whose end has not arrived yet, or null. */\n private pending: Pending | null = null;\n\n /** The line number at the start of `buffer` (or of the pending markup). */\n private line = 1;\n\n /**\n * The index of the next line break in `buffer` at or after the last counted position: -2\n * when not yet searched for the current buffer, -1 when the buffer holds no further break.\n */\n private nextBreak = -2;\n\n /** A CR held back from the end of the previous chunk (it may be the first half of CR LF). */\n private pendingCr = false;\n\n /** Whether the input has ended (an incomplete token is then an error, not a wait). */\n private final = false;\n\n /** The text run being accumulated (entities decoded), and the line it started on. */\n private text = \"\";\n\n private textLine = 1;\n\n private readonly stack: string[] = [];\n\n private rootSeen = false;\n\n private rootClosed = false;\n\n /**\n * Create a tokenizer.\n * @param handler - the event sink\n */\n constructor(handler: XmlHandler) {\n this.handler = handler;\n }\n\n /**\n * Feed one chunk and emit every complete token in it.\n * @param chunk - the text\n */\n push(chunk: string): void {\n let text = chunk;\n if (this.pendingCr) {\n text = `\\r${text}`;\n this.pendingCr = false;\n }\n if (text.endsWith(\"\\r\")) {\n this.pendingCr = true;\n text = text.slice(0, -1);\n }\n if (text.includes(\"\\r\")) {\n text = text.replace(/\\r\\n?/g, \"\\n\");\n }\n this.feed(text);\n }\n\n /** Signal the end of the input: flush the last text run and check well-formedness. */\n finish(): void {\n this.final = true;\n if (this.pendingCr) {\n this.pendingCr = false;\n this.feed(\"\\n\");\n } else {\n this.feed(\"\");\n }\n if (this.pending !== null || this.buffer.length > 0) {\n throw new XmlSyntaxError(\"unexpected end of input inside markup\", this.line);\n }\n this.flushText();\n if (this.stack.length > 0) {\n throw new XmlSyntaxError(`unclosed element <${this.stack[this.stack.length - 1]}>`, this.line);\n }\n if (!this.rootSeen) {\n throw new XmlSyntaxError(\"no root element\", this.line);\n }\n }\n\n /**\n * Append normalised text: continue a pending token's terminator scan over the new text alone,\n * and once the token is complete (or when none is pending) scan the buffer for tokens.\n * @param text - the text, line breaks normalised\n */\n private feed(text: string): void {\n const { pending } = this;\n if (pending === null) {\n this.buffer = this.buffer.length === 0 ? text : this.buffer + text;\n this.nextBreak = -2;\n this.scan();\n return;\n }\n if (pending.kind === \"decl\") {\n // fewer than MIN_DECIDABLE_MARKUP characters of markup: the kind is decided once enough arrived\n this.pending = null;\n this.buffer = pending.pieces.join(\"\") + text;\n this.nextBreak = -2;\n this.scan();\n return;\n }\n const end = this.scanPending(pending, text);\n if (end < 0) {\n if (text.length > 0) {\n pending.pieces.push(text);\n }\n if (this.final) {\n throw new XmlSyntaxError(\"unexpected end of input inside markup\", this.line);\n }\n return;\n }\n this.pending = null;\n pending.pieces.push(text.slice(0, end));\n this.buffer = pending.pieces.join(\"\") + text.slice(end);\n this.nextBreak = -2;\n this.scan();\n }\n\n /**\n * Continue the terminator scan of a pending token over new text.\n * @param pending - the pending token\n * @param text - the new text\n * @returns the index in `text` one past the token's end, or -1 when it does not end there\n */\n private scanPending(pending: Pending, text: string): number {\n switch (pending.kind) {\n case \"starttag\":\n return this.scanStartTag(pending, text, 0);\n case \"doctype\":\n return this.scanDoctype(pending, text, 0);\n case \"decl\":\n return -1;\n default: {\n const terminator = TERMINATORS[pending.kind] ?? \">\";\n const probe = pending.tail + text;\n const at = probe.indexOf(terminator);\n if (at < 0) {\n pending.tail = probe.slice(Math.max(0, probe.length - (terminator.length - 1)));\n return -1;\n }\n return at + terminator.length - pending.tail.length;\n }\n }\n }\n\n /**\n * Scan text for the `>` that ends a start tag, skipping quoted attribute values (the quote\n * state survives between calls).\n * @param pending - the pending token\n * @param text - the text\n * @param from - where to start\n * @returns the index one past the `>`, or -1\n */\n private scanStartTag(pending: Pending, text: string, from: number): number {\n let { quote } = pending;\n const n = text.length;\n let i = from;\n while (i < n) {\n if (quote !== 0) {\n // inside an attribute value: jump to its closing quote\n const close = text.indexOf(String.fromCharCode(quote), i);\n if (close < 0) {\n break;\n }\n quote = 0;\n i = close + 1;\n continue;\n }\n const c = text.charCodeAt(i);\n if (c === QUOTE || c === APOS) {\n quote = c;\n } else if (c === GT) {\n pending.quote = 0;\n return i + 1;\n }\n i++;\n }\n pending.quote = quote;\n return -1;\n }\n\n /**\n * Scan text for the `>` that ends a DOCTYPE declaration, skipping a bracketed internal subset,\n * quoted literals and comments inside the subset. A character state machine, so the state\n * (`depth`, `quote`, `comment`, and `run`, the progress through a `<!--` or the dashes before\n * a `-->`) survives between calls and nothing is re-read.\n * @param pending - the pending token\n * @param text - the text\n * @param from - where to start\n * @returns the index one past the `>`, or -1\n */\n private scanDoctype(pending: Pending, text: string, from: number): number {\n let { quote, depth, comment, run } = pending;\n for (let i = from; i < text.length; i++) {\n const c = text.charCodeAt(i);\n if (comment) {\n if (c === DASH) {\n run++;\n } else if (c === GT && run >= 2) {\n comment = false;\n run = 0;\n } else {\n run = 0;\n }\n continue;\n }\n if (quote !== 0) {\n if (c === quote) {\n quote = 0;\n }\n continue;\n }\n if (depth > 0) {\n if (run === 1 && c === BANG) {\n run = 2;\n continue;\n }\n if (run === 2 && c === DASH) {\n run = 3;\n continue;\n }\n if (run === 3 && c === DASH) {\n comment = true;\n run = 0;\n continue;\n }\n run = 0;\n if (c === LT) {\n run = 1;\n continue;\n }\n }\n if (c === QUOTE || c === APOS) {\n quote = c;\n } else if (c === OPEN_BRACKET) {\n depth++;\n } else if (c === CLOSE_BRACKET) {\n depth--;\n } else if (c === GT && depth <= 0) {\n pending.quote = 0;\n pending.depth = 0;\n pending.comment = false;\n pending.run = 0;\n return i + 1;\n }\n }\n pending.quote = quote;\n pending.depth = depth;\n pending.comment = comment;\n pending.run = run;\n return -1;\n }\n\n /**\n * Consume every complete token at the front of the buffer; an incomplete token at its end\n * becomes the pending token (its text moved out of the buffer), a possibly split entity\n * reference is held back in the buffer.\n */\n private scan(): void {\n const { buffer } = this;\n const { length } = buffer;\n let pos = 0;\n let incomplete = false;\n for (;;) {\n const lt = buffer.indexOf(\"<\", pos);\n if (lt < 0) {\n let end = length;\n if (!this.final) {\n // an entity reference may be split across chunks: hold back from its \"&\"\n const amp = buffer.lastIndexOf(\"&\");\n if (amp >= pos && amp >= length - MAX_ENTITY_LENGTH && buffer.indexOf(\";\", amp) < 0) {\n end = amp;\n }\n }\n this.takeText(pos, end);\n pos = end;\n break;\n }\n if (lt > pos) {\n this.takeText(pos, lt);\n pos = lt;\n }\n const next = this.consumeMarkup(pos);\n if (next < 0) {\n incomplete = true;\n break;\n }\n pos = next;\n }\n if (incomplete) {\n this.pending = this.startPending(buffer, pos);\n this.buffer = \"\";\n } else {\n this.buffer = pos === 0 ? buffer : buffer.slice(pos);\n }\n this.nextBreak = -2;\n }\n\n /**\n * Turn the incomplete markup at `pos` into a pending token, running the terminator scan over\n * the part already in the buffer so later chunks are scanned alone.\n * @param buffer - the buffer\n * @param pos - the index of the `<`\n * @returns the pending token\n */\n private startPending(buffer: string, pos: number): Pending {\n const piece = pos === 0 ? buffer : buffer.slice(pos);\n const pending: Pending = {\n kind: \"starttag\",\n pieces: [piece],\n tail: \"\",\n quote: 0,\n depth: 0,\n comment: false,\n run: 0,\n };\n if (piece.length < MIN_DECIDABLE_MARKUP) {\n // too short to tell a comment from a start tag: wait for more before choosing a scan\n pending.kind = \"decl\";\n return pending;\n }\n if (piece.startsWith(\"<!--\")) {\n pending.kind = \"comment\";\n } else if (piece.startsWith(\"<![CDATA[\")) {\n pending.kind = \"cdata\";\n } else if (piece.startsWith(\"<!DOCTYPE\")) {\n pending.kind = \"doctype\";\n } else if (piece.startsWith(\"<!\")) {\n pending.kind = \"decl\";\n return pending;\n } else if (piece.startsWith(\"<?\")) {\n pending.kind = \"pi\";\n } else if (piece.startsWith(\"</\")) {\n pending.kind = \"endtag\";\n }\n // the part in the buffer holds no terminator (consumeMarkup said so); record the scan state\n switch (pending.kind) {\n case \"starttag\":\n this.scanStartTag(pending, piece, 1);\n break;\n case \"doctype\":\n this.scanDoctype(pending, piece, 9);\n break;\n default: {\n const terminator = TERMINATORS[pending.kind] ?? \">\";\n pending.tail = piece.slice(Math.max(0, piece.length - (terminator.length - 1)));\n break;\n }\n }\n return pending;\n }\n\n /**\n * Consume the markup starting at `pos` (a `<`).\n * @param pos - the index of the `<`\n * @returns the index after the markup, or -1 when the buffer ends before the markup does\n */\n private consumeMarkup(pos: number): number {\n const { buffer } = this;\n if (buffer.startsWith(\"<!\", pos)) {\n if (buffer.length - pos < MIN_DECIDABLE_MARKUP && !this.final) {\n // \"<![CDATA[\" is 9 characters; wait until the kind of declaration is decidable\n return -1;\n }\n if (buffer.startsWith(\"<!--\", pos)) {\n const end = buffer.indexOf(\"-->\", pos + 4);\n if (end < 0) {\n return -1;\n }\n this.advanceLine(pos, end + 3);\n return end + 3;\n }\n if (buffer.startsWith(\"<![CDATA[\", pos)) {\n const end = buffer.indexOf(\"]]>\", pos + 9);\n if (end < 0) {\n return -1;\n }\n if (this.text.length === 0) {\n this.textLine = this.line;\n }\n const cdata = buffer.slice(pos + 9, end);\n if (hasIllegalXmlChar(cdata)) {\n throw new XmlSyntaxError(\"a character XML 1.0 forbids appears in a CDATA section\", this.line);\n }\n this.text += cdata;\n this.advanceLine(pos, end + 3);\n return end + 3;\n }\n if (!buffer.startsWith(\"<!DOCTYPE\", pos)) {\n throw new XmlSyntaxError(\"unexpected markup declaration\", this.line);\n }\n const state: Pending = {\n kind: \"doctype\",\n pieces: [],\n tail: \"\",\n quote: 0,\n depth: 0,\n comment: false,\n run: 0,\n };\n const end = this.scanDoctype(state, buffer, pos + 9);\n if (end < 0) {\n return -1;\n }\n this.advanceLine(pos, end);\n return end;\n }\n if (buffer.startsWith(\"<?\", pos)) {\n const end = buffer.indexOf(\"?>\", pos + 2);\n if (end < 0) {\n return -1;\n }\n this.advanceLine(pos, end + 2);\n return end + 2;\n }\n if (buffer.startsWith(\"</\", pos)) {\n const end = buffer.indexOf(\">\", pos + 2);\n if (end < 0) {\n return -1;\n }\n const name = buffer.slice(pos + 2, end).trim();\n if (!isXmlName(name)) {\n throw new XmlSyntaxError(`malformed end tag </${name}>`, this.line);\n }\n this.flushText();\n this.endElement(name);\n this.advanceLine(pos, end + 1);\n return end + 1;\n }\n const tag = this.parseStartTag(pos);\n if (tag === null) {\n return -1;\n }\n this.flushText();\n this.startElement(tag.name, tag.attrs);\n if (tag.selfClosing) {\n this.endElement(tag.name);\n }\n this.advanceLine(pos, tag.end);\n return tag.end;\n }\n\n /**\n * Parse a start tag at `pos`.\n * @param pos - the index of the `<`\n * @returns the tag, or null when the buffer ends inside it\n */\n private parseStartTag(pos: number): StartTag | null {\n const { buffer } = this;\n const { length } = buffer;\n let i = pos + 1;\n const nameEnd = this.readName(i);\n if (nameEnd < 0) {\n return null;\n }\n if (nameEnd === i) {\n throw new XmlSyntaxError(\"expected an element name after <\", this.line);\n }\n const name = buffer.slice(i, nameEnd);\n i = nameEnd;\n const attrs = new Map<string, string>();\n for (;;) {\n while (i < length && isSpace(buffer.charCodeAt(i))) {\n i++;\n }\n if (i >= length) {\n return null;\n }\n const c = buffer.charCodeAt(i);\n if (c === GT) {\n return { name, attrs, selfClosing: false, end: i + 1 };\n }\n if (c === SLASH) {\n if (i + 1 >= length) {\n return null;\n }\n if (buffer.charCodeAt(i + 1) !== GT) {\n throw new XmlSyntaxError(`unexpected \"/\" in <${name}>`, this.line);\n }\n return { name, attrs, selfClosing: true, end: i + 2 };\n }\n const attrEnd = this.readName(i);\n if (attrEnd < 0) {\n return null;\n }\n if (attrEnd === i) {\n throw new XmlSyntaxError(`malformed attribute in <${name}>`, this.line);\n }\n const attrName = buffer.slice(i, attrEnd);\n i = attrEnd;\n while (i < length && isSpace(buffer.charCodeAt(i))) {\n i++;\n }\n if (i >= length) {\n return null;\n }\n if (buffer.charCodeAt(i) !== EQUALS) {\n throw new XmlSyntaxError(`attribute ${attrName} of <${name}> has no value`, this.line);\n }\n i++;\n while (i < length && isSpace(buffer.charCodeAt(i))) {\n i++;\n }\n if (i >= length) {\n return null;\n }\n const quote = buffer.charCodeAt(i);\n if (quote !== QUOTE && quote !== APOS) {\n throw new XmlSyntaxError(`attribute ${attrName} of <${name}> is not quoted`, this.line);\n }\n const close = buffer.indexOf(quote === QUOTE ? '\"' : \"'\", i + 1);\n if (close < 0) {\n return null;\n }\n if (attrs.has(attrName)) {\n throw new XmlSyntaxError(`duplicate attribute ${attrName} in <${name}>`, this.line);\n }\n const raw = buffer.slice(i + 1, close);\n if (hasIllegalXmlChar(raw)) {\n throw new XmlSyntaxError(\n `a character XML 1.0 forbids appears in attribute ${attrName} of <${name}>`,\n this.line,\n );\n }\n attrs.set(attrName, decodeEntities(normalizeAttributeValue(raw), this.line));\n i = close + 1;\n }\n }\n\n /**\n * The end of the XML Name starting at `i` (an ASCII table for the common case, the code point\n * classes beyond it).\n * @param i - the start index\n * @returns the index after the name; `i` when no name starts there; -1 when the name may\n * continue past the end of the buffer\n */\n private readName(i: number): number {\n const { buffer } = this;\n const { length } = buffer;\n let j = i;\n while (j < length) {\n const c = buffer.charCodeAt(j);\n if (c < 0x80) {\n if ((j === i ? ASCII_NAME_START[c] : ASCII_NAME_CHAR[c]) === 0) {\n break;\n }\n j++;\n continue;\n }\n const cp = buffer.codePointAt(j);\n if (cp === undefined || (j === i ? !isNameStart(cp) : !isNameChar(cp))) {\n break;\n }\n j += cp > 0xffff ? 2 : 1;\n }\n return j >= length && !this.final ? -1 : j;\n }\n\n /**\n * Move text from the buffer into the current run.\n * @param start - the start index\n * @param end - the end index (exclusive)\n */\n private takeText(start: number, end: number): void {\n if (end <= start) {\n return;\n }\n if (this.text.length === 0) {\n this.textLine = this.line;\n }\n const raw = this.buffer.slice(start, end);\n if (hasIllegalXmlChar(raw)) {\n throw new XmlSyntaxError(\"a character XML 1.0 forbids appears in character data\", this.line);\n }\n this.text += decodeEntities(raw, this.line);\n this.advanceLine(start, end);\n }\n\n /**\n * Count the newlines of a consumed range. Ranges are consumed in order, so the next line break\n * is searched for once per buffer and re-searched only after it was passed; a buffer without\n * a further break is searched once and remembered as such.\n * @param start - the start index\n * @param end - the end index (exclusive)\n */\n private advanceLine(start: number, end: number): void {\n let i = this.nextBreak;\n if (i === -1) {\n return;\n }\n if (i === -2 || i < start) {\n i = this.buffer.indexOf(\"\\n\", start);\n }\n while (i >= 0 && i < end) {\n this.line++;\n i = this.buffer.indexOf(\"\\n\", i + 1);\n }\n this.nextBreak = i;\n }\n\n /** Deliver the accumulated text run, if any. */\n private flushText(): void {\n if (this.text.length === 0) {\n return;\n }\n const { text } = this;\n this.text = \"\";\n if (this.stack.length === 0) {\n if (!isWhitespace(text)) {\n throw new XmlSyntaxError(\"text outside the root element\", this.textLine);\n }\n return;\n }\n this.handler.text(text, this.textLine);\n }\n\n /**\n * Open an element.\n * @param name - the element name\n * @param attrs - its attributes\n */\n private startElement(name: string, attrs: Map<string, string>): void {\n if (this.stack.length === 0) {\n if (this.rootClosed) {\n throw new XmlSyntaxError(`a second root element <${name}> follows the document element`, this.line);\n }\n this.rootSeen = true;\n }\n this.stack.push(name);\n this.handler.start(name, attrs, this.line);\n }\n\n /**\n * Close an element, checking that it matches the innermost open one.\n * @param name - the element name\n */\n private endElement(name: string): void {\n const open = this.stack.length > 0 ? this.stack[this.stack.length - 1] : null;\n if (open === null) {\n throw new XmlSyntaxError(`unexpected end tag </${name}>`, this.line);\n }\n if (open !== name) {\n throw new XmlSyntaxError(`end tag </${name}> does not match <${open}>`, this.line);\n }\n this.stack.pop();\n if (this.stack.length === 0) {\n this.rootClosed = true;\n }\n this.handler.end(name, this.line);\n }\n}\n\n/**\n * Attribute value normalisation (XML 1.0 section 3.3.3): a literal tab or line break becomes a\n * space; a character reference to one is kept, which is why this runs before entity decoding.\n * @param raw - the value between the quotes\n * @returns the normalised value\n */\nfunction normalizeAttributeValue(raw: string): string {\n return raw.includes(\"\\n\") || raw.includes(\"\\t\") ? raw.replace(/[\\n\\t]/g, \" \") : raw;\n}\n","/**\n * Id, label and value escaping for the text formats (design section 8.5), one function per\n * syntax, with the inverse where the importer needs it: XML attribute and element text (GEXF,\n * GraphML), GML quoted strings (`\"` and `&` and non-ASCII as `&#NN;` character entities, the\n * NetworkX convention), DOT ids (bare when the grammar allows, quoted with `\\\"` otherwise), RFC\n * 4180 CSV cells and Pajek labels.\n */\n\nimport { GraphFormatError } from \"@graphty/graph-format\";\n\nimport { hasIllegalXmlChar } from \"./xml.js\";\n\nconst XML_TEXT_SPECIAL = /[&<>\\r]/g;\nconst XML_ATTR_SPECIAL = /[&<>\"\\t\\n\\r]/g;\nconst XML_REPLACEMENTS: Readonly<Record<string, string>> = {\n \"&\": \"&amp;\",\n \"<\": \"&lt;\",\n \">\": \"&gt;\",\n '\"': \"&quot;\",\n \"\\t\": \"&#9;\",\n \"\\n\": \"&#10;\",\n \"\\r\": \"&#13;\",\n};\n\n/**\n * Escape text for an XML element body: `&`, `<`, `>` and a carriage return (which XML\n * end-of-line handling would turn into a line feed on every read) as character references. A\n * character XML 1.0 forbids (a C0 control other than tab / LF / CR, U+FFFE, U+FFFF, a lone\n * surrogate) has no XML spelling at all and is E_COLUMN_TYPE; the exporters' check() counts them.\n * @param text - the text\n * @returns the escaped text\n */\nexport function escapeXmlText(text: string): string {\n if (hasIllegalXmlChar(text)) {\n throw illegalXml(text);\n }\n return text.replace(XML_TEXT_SPECIAL, (c) => XML_REPLACEMENTS[c]);\n}\n\n/**\n * Escape text for a double-quoted XML attribute value: `&`, `<`, `>`, `\"` and the whitespace\n * characters attribute normalisation would fold; a character XML 1.0 forbids is E_COLUMN_TYPE.\n * @param text - the text\n * @returns the escaped text\n */\nexport function escapeXmlAttribute(text: string): string {\n if (hasIllegalXmlChar(text)) {\n throw illegalXml(text);\n }\n return text.replace(XML_ATTR_SPECIAL, (c) => XML_REPLACEMENTS[c]);\n}\n\n/**\n * The error of a text no XML 1.0 document can carry.\n * @param text - the text\n * @returns the error\n */\nfunction illegalXml(text: string): GraphFormatError {\n return new GraphFormatError(\"E_COLUMN_TYPE\", \"the text holds a character XML 1.0 cannot carry\", {\n reason: \"xml illegal char\",\n length: text.length,\n });\n}\n\nconst GML_SPECIAL = /[\"&]|[^ -~]/gu;\n\n/**\n * Quote a GML string value: double quotes around the text with `\"`, `&` and every character\n * outside printable ASCII written as `&#NN;` (NetworkX's writer convention, which its reader and\n * Gephi's decode).\n * A lone surrogate cannot be written and is E_COLUMN_TYPE.\n * @param text - the text\n * @returns the quoted GML string\n */\nexport function quoteGmlString(text: string): string {\n const escaped = text.replace(GML_SPECIAL, (c) => {\n const code = c.codePointAt(0);\n if (code === undefined) {\n return c;\n }\n if (code >= 0xd800 && code <= 0xdfff) {\n throw new GraphFormatError(\"E_COLUMN_TYPE\", \"a lone surrogate cannot be written as a GML string\", {\n reason: \"lone surrogate\",\n });\n }\n return `&#${code};`;\n });\n return `\"${escaped}\"`;\n}\n\nconst GML_ENTITY = /&(#[0-9]+|#x[0-9a-fA-F]+|amp|quot|lt|gt|apos);/g;\nconst GML_NAMED: Readonly<Record<string, string>> = { amp: \"&\", quot: '\"', lt: \"<\", gt: \">\", apos: \"'\" };\n\n/**\n * Decode the character entities of a GML string body (the inverse of quoteGmlString on the text\n * between the quotes). An unknown entity is left as written.\n * @param body - the text between the quotes\n * @returns the decoded text\n */\nexport function decodeGmlString(body: string): string {\n return body.replace(GML_ENTITY, (whole, entity: string) => {\n if (entity.startsWith(\"#x\")) {\n return String.fromCodePoint(Number.parseInt(entity.slice(2), 16));\n }\n if (entity.startsWith(\"#\")) {\n return String.fromCodePoint(Number.parseInt(entity.slice(1), 10));\n }\n return GML_NAMED[entity] ?? whole;\n });\n}\n\nconst DOT_NUMERAL = /^-?(\\.[0-9]+|[0-9]+(\\.[0-9]*)?)$/;\nconst DOT_KEYWORDS: ReadonlySet<string> = new Set([\"node\", \"edge\", \"graph\", \"digraph\", \"subgraph\", \"strict\"]);\n\n/**\n * Whether a text is a DOT ID that needs no quotes: an alphanumeric identifier not starting with\n * a digit, or a numeral, and not a keyword (case-insensitive).\n * @param text - the text\n * @returns true when the text can be written bare\n */\nexport function isBareDotId(text: string): boolean {\n if (DOT_KEYWORDS.has(text.toLowerCase())) {\n return false;\n }\n return isDotIdentifier(text) || DOT_NUMERAL.test(text);\n}\n\n/**\n * Whether a text is a DOT identifier: a letter, underscore or any character of code 128 and\n * above, followed by letters, digits, underscores or such characters.\n * @param text - the text\n * @returns true for a bare identifier\n */\nfunction isDotIdentifier(text: string): boolean {\n if (text.length === 0) {\n return false;\n }\n for (let i = 0; i < text.length; i++) {\n const c = text.charCodeAt(i);\n const letter = (c >= 65 && c <= 90) || (c >= 97 && c <= 122) || c === 95 || c >= 128;\n const digit = c >= 48 && c <= 57;\n if (!letter && (i === 0 || !digit)) {\n return false;\n }\n }\n return true;\n}\n\n/**\n * Whether a text can be written as a DOT ID at all. Graphviz's scanner consumes a backslash pair\n * `\\\\` as one unit, `\\\"` as an escaped quote and a backslash before a line break as a line\n * continuation (both removed), left to right, so a backslash that precedes a double quote or a\n * line break, or ends the text, cannot be written: the written `\\\\\"` reads as a pair and a closing\n * quote, a backslash before a line break vanishes with the break, and a trailing backslash escapes\n * the closing quote. Every other text is writable; quoteDotId() writes it.\n * @param text - the id, name or value text\n * @returns true when quoteDotId(text) reads back as `text`\n */\nexport function isWritableDotText(text: string): boolean {\n return !text.endsWith(\"\\\\\") && !text.includes('\\\\\"') && !/\\\\[\\r\\n]/.test(text);\n}\n\n/**\n * Write a DOT ID: bare when the grammar allows, otherwise double-quoted with `\"` escaped as `\\\"`.\n * In DOT quoted strings the dyad `\\\"` is the only escape; every other character, a backslash and\n * a raw line break included, is kept as written, so nothing else is rewritten. A text ending in a\n * backslash has no DOT spelling (isWritableDotText); the caller refuses it before writing.\n * @param text - the id or label text\n * @returns the DOT ID\n */\nexport function quoteDotId(text: string): string {\n if (isBareDotId(text)) {\n return text;\n }\n return `\"${text.replace(/\"/g, '\\\\\"')}\"`;\n}\n\n/**\n * Write a set CSV cell per RFC 4180: quoted with `\"` doubled when the text contains the\n * delimiter, a quote, a CR or LF, or leading / trailing whitespace; bare otherwise. The empty\n * string is written as the quoted empty cell `\"\"`, so the importers can tell a set empty string\n * (and an empty-string node id, legal under design section 4.1) from an unset cell, which every\n * exporter writes as nothing between the delimiters.\n * @param text - the cell text of a set cell\n * @param delimiter - the field delimiter (default \",\")\n * @returns the cell as written\n */\nexport function quoteCsvCell(text: string, delimiter = \",\"): string {\n if (text.length === 0) {\n return '\"\"';\n }\n if (\n !text.includes(delimiter) &&\n !text.includes('\"') &&\n !text.includes(\"\\n\") &&\n !text.includes(\"\\r\") &&\n text === text.trim()\n ) {\n return text;\n }\n return `\"${text.replace(/\"/g, '\"\"')}\"`;\n}\n\n/**\n * Whether a text can be a Pajek label: Pajek has no escape mechanism inside its double-quoted\n * labels, so a text containing a double quote, a CR or an LF cannot be written.\n * @param text - the label text\n * @returns true when quotePajekLabel() can write it\n */\nexport function isPajekLabel(text: string): boolean {\n return !text.includes('\"') && !text.includes(\"\\n\") && !text.includes(\"\\r\");\n}\n\n/**\n * Write a Pajek label: bare when it is a single run of non-space, non-quote characters, otherwise\n * double-quoted. E_UNSUPPORTED (reason \"pajek label\") for a text isPajekLabel() rejects; the\n * exporter's check() counts those.\n * @param text - the label text\n * @returns the label as written\n */\nexport function quotePajekLabel(text: string): string {\n if (!isPajekLabel(text)) {\n throw new GraphFormatError(\"E_UNSUPPORTED\", \"a Pajek label cannot contain a double quote or a line break\", {\n reason: \"pajek label\",\n value: text,\n });\n }\n if (text.length > 0 && !/[\\s\"]/.test(text)) {\n return text;\n }\n return `\"${text}\"`;\n}\n"],"names":["end"],"mappings":"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"}
1
+ {"version":3,"file":"escape-DXbOoLKl.js","sources":["../../src/common/xml.ts","../../src/common/escape.ts"],"sourcesContent":["/**\n * The streaming XML tokenizer shared by the GEXF and GraphML importers (design sections 8.2 and\n * 8.4): SAX-style start / end / text events over the text chunks of the common reader, so both\n * importers run in one pass with bounded memory and every issue carries a line number.\n *\n * Cost model: every character of the input is scanned once. A token that spans many chunks (a\n * long attribute value, comment, CDATA section or name) resumes where the previous chunk left off\n * instead of re-reading the token from its `<`, and line numbers are counted from a cached next\n * line-break position, so a document without line breaks costs the same as one with them.\n *\n * What it handles: the XML declaration and processing instructions (skipped), comments (skipped),\n * CDATA sections (text), a DOCTYPE with an internal subset (skipped; entity declarations are not\n * expanded, so an unknown entity reference is a syntax error), the five predefined entities and\n * numeric character references (decimal and hexadecimal) in text and attribute values, attribute\n * value whitespace normalisation, end-of-line normalisation (CR LF and lone CR become LF), and\n * well-formedness: matching end tags, one root element, no text outside it, no duplicate\n * attributes, no unterminated markup at the end of the input. Namespaces are not resolved; element\n * and attribute names are reported as written (with their prefix).\n *\n * Why not fast-xml-parser: its XMLParser accepts mismatched and unclosed tags without error, does\n * not decode numeric character references unless the deprecated `htmlEntities` option is set, and\n * its validator (`XMLValidator`, the `parse(xml, true)` overload) and `XMLBuilder` are deprecated in\n * 5.x, which the root lint's `no-deprecated` rule forbids using; so the malformed corpus could not\n * be rejected and attribute values written by the common `escapeXmlAttribute` (`&#10;`) could not\n * be read back.\n */\n\nimport { type Column, type GraphSnapshot } from \"@graphty/graph-format\";\n\nimport { type LossNote } from \"../types.js\";\nimport { XML_ILLEGAL_CHAR_CODE } from \"./codes.js\";\nimport { isNameChar } from \"./export.js\";\n\n/** The events of the tokenizer; every callback is synchronous. */\nexport interface XmlHandler {\n /**\n * An element starts (a self-closing element produces start then end).\n * @param name - the element name as written, prefix included\n * @param attrs - the attributes, entities decoded, in document order\n * @param line - the 1-based line of the `<`\n */\n start(name: string, attrs: ReadonlyMap<string, string>, line: number): void;\n /**\n * An element ends.\n * @param name - the element name\n * @param line - the 1-based line of the end tag (or of the self-closing start tag)\n */\n end(name: string, line: number): void;\n /**\n * Character data between two tags (entities decoded, CDATA included), one call per run;\n * whitespace-only runs are delivered too.\n * @param text - the text\n * @param line - the 1-based line where the run starts\n */\n text(text: string, line: number): void;\n}\n\n/** A well-formedness or syntax error, with the line it was found on. */\nexport class XmlSyntaxError extends Error {\n /** The 1-based line. */\n readonly line: number;\n\n /**\n * Create the error.\n * @param message - a plain-ASCII message\n * @param line - the 1-based line\n */\n constructor(message: string, line: number) {\n super(message);\n this.name = \"XmlSyntaxError\";\n this.line = line;\n }\n}\n\nconst NAMED_ENTITIES: Readonly<Record<string, string>> = {\n lt: \"<\",\n gt: \">\",\n amp: \"&\",\n quot: '\"',\n apos: \"'\",\n};\n\nconst LT = 60;\nconst GT = 62;\nconst SLASH = 47;\nconst EQUALS = 61;\nconst QUOTE = 34;\nconst APOS = 39;\nconst OPEN_BRACKET = 91;\nconst CLOSE_BRACKET = 93;\nconst BANG = 33;\nconst DASH = 45;\n\n/** The longest entity reference held back at a chunk boundary (`&#x10FFFF;` is 10 characters). */\nconst MAX_ENTITY_LENGTH = 16;\n\n/** Markup shorter than this (`<![CDATA[` is 9 characters) cannot be classified yet. */\nconst MIN_DECIDABLE_MARKUP = 9;\n\n/**\n * Whether a char code is XML whitespace (space, tab, LF, CR).\n * @param c - the char code\n * @returns true for whitespace\n */\nfunction isSpace(c: number): boolean {\n return c === 32 || c === 9 || c === 10 || c === 13;\n}\n\n/**\n * Whether a code point may start an XML Name: a NameChar that is not a digit, `-`, `.`, U+00B7,\n * a combining character (U+0300..U+036F) or U+203F / U+2040.\n * @param cp - the code point\n * @returns true for a NameStartChar\n */\nfunction isNameStart(cp: number): boolean {\n if (!isNameChar(cp)) {\n return false;\n }\n if ((cp >= 0x30 && cp <= 0x39) || cp === 0x2d || cp === 0x2e || cp === 0xb7) {\n return false;\n }\n return !(cp >= 0x300 && cp <= 0x36f) && cp !== 0x203f && cp !== 0x2040;\n}\n\n/** ASCII code -> whether it is a NameStartChar / NameChar, for the fast path of readName(). */\nconst ASCII_NAME_START = new Uint8Array(128);\nconst ASCII_NAME_CHAR = new Uint8Array(128);\nfor (let c = 0; c < 128; c++) {\n ASCII_NAME_START[c] = isNameStart(c) ? 1 : 0;\n ASCII_NAME_CHAR[c] = isNameChar(c) ? 1 : 0;\n}\n\n/**\n * Characters XML 1.0 forbids in a document (the Char production): C0 controls other than tab, LF\n * and CR, U+FFFE / U+FFFF, and lone surrogates (the `u` flag makes the surrogate class match only\n * an unpaired one). Built from char codes so no control character appears in the source.\n */\nconst ILLEGAL_CHAR = new RegExp(\n `[${String.fromCharCode(0)}-${String.fromCharCode(8)}${String.fromCharCode(11)}${String.fromCharCode(12)}` +\n `${String.fromCharCode(14)}-${String.fromCharCode(31)}\\\\uFFFE\\\\uFFFF\\\\uD800-\\\\uDFFF]`,\n \"u\",\n);\n\n/**\n * Whether a text holds a character XML 1.0 forbids (see ILLEGAL_CHAR); such a character cannot be\n * written even as a character reference, so a conforming parser rejects the whole document.\n * @param text - the text\n * @returns true when the text cannot appear in an XML 1.0 document\n */\nexport function hasIllegalXmlChar(text: string): boolean {\n return ILLEGAL_CHAR.test(text);\n}\n\n/**\n * The loss notes of the texts a snapshot holds that no XML 1.0 document can carry (see\n * hasIllegalXmlChar): one E_XML_ILLEGAL_CHAR note per column (node, edge and graph string / dict /\n * list-of-text columns) and one for the ids, each counting the affected rows; export() throws on\n * the first such text. Shared by the GEXF and GraphML exporters' check().\n * @param snapshot - the snapshot\n * @returns the notes, empty when every text is writable\n */\nexport function xmlIllegalTextNotes(snapshot: GraphSnapshot): LossNote[] {\n const notes: LossNote[] = [];\n let ids = 0;\n for (let i = 0; i < snapshot.nodeCount; i++) {\n const id = snapshot.ids.idOf(i);\n if (typeof id === \"string\" && hasIllegalXmlChar(id)) {\n ids++;\n }\n }\n if (ids > 0) {\n notes.push(\n Object.freeze({\n code: XML_ILLEGAL_CHAR_CODE,\n message: `${ids} node id(s) hold a character XML 1.0 cannot carry; export() will throw`,\n column: null,\n count: ids,\n }),\n );\n }\n for (const [domain, table] of [\n [\"node\", snapshot.nodes],\n [\"edge\", snapshot.edges],\n [\"graph\", snapshot.graph],\n ] as const) {\n for (const column of table) {\n const bad = countIllegalRows(column);\n if (bad > 0) {\n notes.push(\n Object.freeze({\n code: XML_ILLEGAL_CHAR_CODE,\n message: `${domain} column \"${column.meta.name}\": ${bad} value(s) hold a character XML 1.0 cannot carry; export() will throw`,\n column: column.meta.name,\n count: bad,\n }),\n );\n }\n }\n }\n return notes;\n}\n\n/**\n * How many set rows of a text column hold an XML-illegal character.\n * @param column - the column\n * @returns the count; 0 for a non-text column\n */\nfunction countIllegalRows(column: Column): number {\n let bad = 0;\n if (column.dtype === \"string\" || column.dtype === \"dict\") {\n for (let r = 0; r < column.length; r++) {\n if (column.isSet(r) && hasIllegalXmlChar(column.value(r) as string)) {\n bad++;\n }\n }\n } else if (column.dtype === \"list\" && (column.meta.itemDtype === \"string\" || column.meta.itemDtype === \"dict\")) {\n for (let r = 0; r < column.length; r++) {\n if (\n column.isSet(r) &&\n column.sliceOf(r).some((item) => typeof item === \"string\" && hasIllegalXmlChar(item))\n ) {\n bad++;\n }\n }\n }\n return bad;\n}\n\n/** The encoding pseudo-attribute of an XML declaration at the very start of a document. */\nconst XML_DECLARED_ENCODING = /^<\\?xml\\s[^>]*?\\bencoding\\s*=\\s*[\"']([A-Za-z][A-Za-z0-9._-]*)[\"']/;\n\n/**\n * The encoding an XML document declares in its prolog (`<?xml version=\"1.0\" encoding=\"...\"?>`),\n * for the shared byte decoder (common/input.ts).\n * @param head - the start of the document, decoded as windows-1252\n * @returns the declared label, or null when there is no declaration or it names no encoding\n */\nexport function xmlDeclaredEncoding(head: string): string | null {\n const match = XML_DECLARED_ENCODING.exec(head);\n return match === null ? null : match[1];\n}\n\n/**\n * Whether a text is an XML Name.\n * @param text - the text\n * @returns true for a well-formed name\n */\nexport function isXmlName(text: string): boolean {\n if (text.length === 0) {\n return false;\n }\n let first = true;\n for (const ch of text) {\n const cp = ch.codePointAt(0);\n if (cp === undefined || (first ? !isNameStart(cp) : !isNameChar(cp))) {\n return false;\n }\n first = false;\n }\n return true;\n}\n\n/**\n * Whether a code point is a legal XML 1.0 character.\n * @param cp - the code point\n * @returns true when a character reference may produce it\n */\nfunction isXmlChar(cp: number): boolean {\n return (\n cp === 0x9 ||\n cp === 0xa ||\n cp === 0xd ||\n (cp >= 0x20 && cp <= 0xd7ff) ||\n (cp >= 0xe000 && cp <= 0xfffd) ||\n (cp >= 0x10000 && cp <= 0x10ffff)\n );\n}\n\n/**\n * Decode the predefined entities and character references of a text.\n * @param raw - the text as written\n * @param line - the line, for errors\n * @returns the decoded text\n */\nexport function decodeEntities(raw: string, line: number): string {\n let amp = raw.indexOf(\"&\");\n if (amp < 0) {\n return raw;\n }\n let out = \"\";\n let start = 0;\n while (amp >= 0) {\n out += raw.slice(start, amp);\n const semi = raw.indexOf(\";\", amp + 1);\n if (semi < 0) {\n throw new XmlSyntaxError(\"unterminated entity reference\", line);\n }\n const name = raw.slice(amp + 1, semi);\n if (name.startsWith(\"#\")) {\n const hex = name.startsWith(\"#x\") || name.startsWith(\"#X\");\n const digits = name.slice(hex ? 2 : 1);\n const ok = hex ? /^[0-9a-fA-F]{1,6}$/.test(digits) : /^[0-9]{1,7}$/.test(digits);\n const cp = ok ? Number.parseInt(digits, hex ? 16 : 10) : -1;\n if (cp < 0 || !isXmlChar(cp)) {\n throw new XmlSyntaxError(`invalid character reference &${name};`, line);\n }\n out += String.fromCodePoint(cp);\n } else {\n const value = NAMED_ENTITIES[name];\n if (value === undefined) {\n throw new XmlSyntaxError(`unknown entity &${name};`, line);\n }\n out += value;\n }\n start = semi + 1;\n amp = raw.indexOf(\"&\", start);\n }\n return out + raw.slice(start);\n}\n\n/**\n * Whether a text is whitespace only.\n * @param text - the text\n * @returns true when every character is XML whitespace (also for an empty text)\n */\nexport function isWhitespace(text: string): boolean {\n for (let i = 0; i < text.length; i++) {\n if (!isSpace(text.charCodeAt(i))) {\n return false;\n }\n }\n return true;\n}\n\n/**\n * The local part of a possibly prefixed XML name.\n * @param name - the name as written\n * @returns the text after the last colon, or the name itself\n */\nexport function localName(name: string): string {\n const colon = name.lastIndexOf(\":\");\n return colon < 0 ? name : name.slice(colon + 1);\n}\n\n/**\n * Tokenize XML text arriving in chunks and deliver events to a handler. Throws XmlSyntaxError on\n * malformed input; any error the handler throws propagates unchanged.\n * @param chunks - the text (already UTF-8 decoded, BOM removed)\n * @param handler - the event sink\n */\nexport async function tokenizeXml(chunks: AsyncIterable<string>, handler: XmlHandler): Promise<void> {\n const tokenizer = new XmlTokenizer(handler);\n for await (const chunk of chunks) {\n tokenizer.push(chunk);\n }\n tokenizer.finish();\n}\n\n/** The result of parsing one start tag out of the buffer. */\ninterface StartTag {\n /** The element name. */\n readonly name: string;\n /** The attributes. */\n readonly attrs: Map<string, string>;\n /** Whether the tag ends with `/>`. */\n readonly selfClosing: boolean;\n /** The buffer index one past the `>`. */\n readonly end: number;\n}\n\n/** The kinds of markup whose end may lie in a later chunk. */\ntype PendingKind = \"decl\" | \"comment\" | \"cdata\" | \"pi\" | \"endtag\" | \"doctype\" | \"starttag\";\n\n/** The terminator of each fixed-terminator markup kind. */\nconst TERMINATORS: Readonly<Partial<Record<PendingKind, string>>> = {\n comment: \"-->\",\n cdata: \"]]>\",\n pi: \"?>\",\n endtag: \">\",\n};\n\n/**\n * An incomplete piece of markup at the end of the input so far: its text pieces (never joined\n * until the end is found, so a token spanning many chunks costs its length once) and the state\n * the terminator scan is in. `tail` holds the last characters of the pieces a fixed terminator\n * could straddle; `quote` is the open quote character (0 outside a value) of a start tag or a\n * DOCTYPE; `depth`, `comment` and `run` track a DOCTYPE's internal subset.\n */\ninterface Pending {\n kind: PendingKind;\n readonly pieces: string[];\n tail: string;\n quote: number;\n depth: number;\n comment: boolean;\n run: number;\n}\n\n/**\n * The tokenizer state: the unconsumed tail of the input, the current line, the open element\n * stack and the text run being accumulated. `push()` chunks, then `finish()`.\n */\nexport class XmlTokenizer {\n private readonly handler: XmlHandler;\n\n /** Unconsumed input that is not part of a pending token: at most a held-back entity or the last chunk. */\n private buffer = \"\";\n\n /** The markup whose end has not arrived yet, or null. */\n private pending: Pending | null = null;\n\n /** The line number at the start of `buffer` (or of the pending markup). */\n private line = 1;\n\n /**\n * The index of the next line break in `buffer` at or after the last counted position: -2\n * when not yet searched for the current buffer, -1 when the buffer holds no further break.\n */\n private nextBreak = -2;\n\n /** A CR held back from the end of the previous chunk (it may be the first half of CR LF). */\n private pendingCr = false;\n\n /** Whether the input has ended (an incomplete token is then an error, not a wait). */\n private final = false;\n\n /** The text run being accumulated (entities decoded), and the line it started on. */\n private text = \"\";\n\n private textLine = 1;\n\n private readonly stack: string[] = [];\n\n private rootSeen = false;\n\n private rootClosed = false;\n\n /**\n * Create a tokenizer.\n * @param handler - the event sink\n */\n constructor(handler: XmlHandler) {\n this.handler = handler;\n }\n\n /**\n * Feed one chunk and emit every complete token in it.\n * @param chunk - the text\n */\n push(chunk: string): void {\n let text = chunk;\n if (this.pendingCr) {\n text = `\\r${text}`;\n this.pendingCr = false;\n }\n if (text.endsWith(\"\\r\")) {\n this.pendingCr = true;\n text = text.slice(0, -1);\n }\n if (text.includes(\"\\r\")) {\n text = text.replace(/\\r\\n?/g, \"\\n\");\n }\n this.feed(text);\n }\n\n /** Signal the end of the input: flush the last text run and check well-formedness. */\n finish(): void {\n this.final = true;\n if (this.pendingCr) {\n this.pendingCr = false;\n this.feed(\"\\n\");\n } else {\n this.feed(\"\");\n }\n if (this.pending !== null || this.buffer.length > 0) {\n throw new XmlSyntaxError(\"unexpected end of input inside markup\", this.line);\n }\n this.flushText();\n if (this.stack.length > 0) {\n throw new XmlSyntaxError(`unclosed element <${this.stack[this.stack.length - 1]}>`, this.line);\n }\n if (!this.rootSeen) {\n throw new XmlSyntaxError(\"no root element\", this.line);\n }\n }\n\n /**\n * Append normalised text: continue a pending token's terminator scan over the new text alone,\n * and once the token is complete (or when none is pending) scan the buffer for tokens.\n * @param text - the text, line breaks normalised\n */\n private feed(text: string): void {\n const { pending } = this;\n if (pending === null) {\n this.buffer = this.buffer.length === 0 ? text : this.buffer + text;\n this.nextBreak = -2;\n this.scan();\n return;\n }\n if (pending.kind === \"decl\") {\n // fewer than MIN_DECIDABLE_MARKUP characters of markup: the kind is decided once enough arrived\n this.pending = null;\n this.buffer = pending.pieces.join(\"\") + text;\n this.nextBreak = -2;\n this.scan();\n return;\n }\n const end = this.scanPending(pending, text);\n if (end < 0) {\n if (text.length > 0) {\n pending.pieces.push(text);\n }\n if (this.final) {\n throw new XmlSyntaxError(\"unexpected end of input inside markup\", this.line);\n }\n return;\n }\n this.pending = null;\n pending.pieces.push(text.slice(0, end));\n this.buffer = pending.pieces.join(\"\") + text.slice(end);\n this.nextBreak = -2;\n this.scan();\n }\n\n /**\n * Continue the terminator scan of a pending token over new text.\n * @param pending - the pending token\n * @param text - the new text\n * @returns the index in `text` one past the token's end, or -1 when it does not end there\n */\n private scanPending(pending: Pending, text: string): number {\n switch (pending.kind) {\n case \"starttag\":\n return this.scanStartTag(pending, text, 0);\n case \"doctype\":\n return this.scanDoctype(pending, text, 0);\n case \"decl\":\n return -1;\n default: {\n const terminator = TERMINATORS[pending.kind] ?? \">\";\n const probe = pending.tail + text;\n const at = probe.indexOf(terminator);\n if (at < 0) {\n pending.tail = probe.slice(Math.max(0, probe.length - (terminator.length - 1)));\n return -1;\n }\n return at + terminator.length - pending.tail.length;\n }\n }\n }\n\n /**\n * Scan text for the `>` that ends a start tag, skipping quoted attribute values (the quote\n * state survives between calls).\n * @param pending - the pending token\n * @param text - the text\n * @param from - where to start\n * @returns the index one past the `>`, or -1\n */\n private scanStartTag(pending: Pending, text: string, from: number): number {\n let { quote } = pending;\n const n = text.length;\n let i = from;\n while (i < n) {\n if (quote !== 0) {\n // inside an attribute value: jump to its closing quote\n const close = text.indexOf(String.fromCharCode(quote), i);\n if (close < 0) {\n break;\n }\n quote = 0;\n i = close + 1;\n continue;\n }\n const c = text.charCodeAt(i);\n if (c === QUOTE || c === APOS) {\n quote = c;\n } else if (c === GT) {\n pending.quote = 0;\n return i + 1;\n }\n i++;\n }\n pending.quote = quote;\n return -1;\n }\n\n /**\n * Scan text for the `>` that ends a DOCTYPE declaration, skipping a bracketed internal subset,\n * quoted literals and comments inside the subset. A character state machine, so the state\n * (`depth`, `quote`, `comment`, and `run`, the progress through a `<!--` or the dashes before\n * a `-->`) survives between calls and nothing is re-read.\n * @param pending - the pending token\n * @param text - the text\n * @param from - where to start\n * @returns the index one past the `>`, or -1\n */\n private scanDoctype(pending: Pending, text: string, from: number): number {\n let { quote, depth, comment, run } = pending;\n for (let i = from; i < text.length; i++) {\n const c = text.charCodeAt(i);\n if (comment) {\n if (c === DASH) {\n run++;\n } else if (c === GT && run >= 2) {\n comment = false;\n run = 0;\n } else {\n run = 0;\n }\n continue;\n }\n if (quote !== 0) {\n if (c === quote) {\n quote = 0;\n }\n continue;\n }\n if (depth > 0) {\n if (run === 1 && c === BANG) {\n run = 2;\n continue;\n }\n if (run === 2 && c === DASH) {\n run = 3;\n continue;\n }\n if (run === 3 && c === DASH) {\n comment = true;\n run = 0;\n continue;\n }\n run = 0;\n if (c === LT) {\n run = 1;\n continue;\n }\n }\n if (c === QUOTE || c === APOS) {\n quote = c;\n } else if (c === OPEN_BRACKET) {\n depth++;\n } else if (c === CLOSE_BRACKET) {\n depth--;\n } else if (c === GT && depth <= 0) {\n pending.quote = 0;\n pending.depth = 0;\n pending.comment = false;\n pending.run = 0;\n return i + 1;\n }\n }\n pending.quote = quote;\n pending.depth = depth;\n pending.comment = comment;\n pending.run = run;\n return -1;\n }\n\n /**\n * Consume every complete token at the front of the buffer; an incomplete token at its end\n * becomes the pending token (its text moved out of the buffer), a possibly split entity\n * reference is held back in the buffer.\n */\n private scan(): void {\n const { buffer } = this;\n const { length } = buffer;\n let pos = 0;\n let incomplete = false;\n for (;;) {\n const lt = buffer.indexOf(\"<\", pos);\n if (lt < 0) {\n let end = length;\n if (!this.final) {\n // an entity reference may be split across chunks: hold back from its \"&\"\n const amp = buffer.lastIndexOf(\"&\");\n if (amp >= pos && amp >= length - MAX_ENTITY_LENGTH && buffer.indexOf(\";\", amp) < 0) {\n end = amp;\n }\n }\n this.takeText(pos, end);\n pos = end;\n break;\n }\n if (lt > pos) {\n this.takeText(pos, lt);\n pos = lt;\n }\n const next = this.consumeMarkup(pos);\n if (next < 0) {\n incomplete = true;\n break;\n }\n pos = next;\n }\n if (incomplete) {\n this.pending = this.startPending(buffer, pos);\n this.buffer = \"\";\n } else {\n this.buffer = pos === 0 ? buffer : buffer.slice(pos);\n }\n this.nextBreak = -2;\n }\n\n /**\n * Turn the incomplete markup at `pos` into a pending token, running the terminator scan over\n * the part already in the buffer so later chunks are scanned alone.\n * @param buffer - the buffer\n * @param pos - the index of the `<`\n * @returns the pending token\n */\n private startPending(buffer: string, pos: number): Pending {\n const piece = pos === 0 ? buffer : buffer.slice(pos);\n const pending: Pending = {\n kind: \"starttag\",\n pieces: [piece],\n tail: \"\",\n quote: 0,\n depth: 0,\n comment: false,\n run: 0,\n };\n if (piece.length < MIN_DECIDABLE_MARKUP) {\n // too short to tell a comment from a start tag: wait for more before choosing a scan\n pending.kind = \"decl\";\n return pending;\n }\n if (piece.startsWith(\"<!--\")) {\n pending.kind = \"comment\";\n } else if (piece.startsWith(\"<![CDATA[\")) {\n pending.kind = \"cdata\";\n } else if (piece.startsWith(\"<!DOCTYPE\")) {\n pending.kind = \"doctype\";\n } else if (piece.startsWith(\"<!\")) {\n pending.kind = \"decl\";\n return pending;\n } else if (piece.startsWith(\"<?\")) {\n pending.kind = \"pi\";\n } else if (piece.startsWith(\"</\")) {\n pending.kind = \"endtag\";\n }\n // the part in the buffer holds no terminator (consumeMarkup said so); record the scan state\n switch (pending.kind) {\n case \"starttag\":\n this.scanStartTag(pending, piece, 1);\n break;\n case \"doctype\":\n this.scanDoctype(pending, piece, 9);\n break;\n default: {\n const terminator = TERMINATORS[pending.kind] ?? \">\";\n pending.tail = piece.slice(Math.max(0, piece.length - (terminator.length - 1)));\n break;\n }\n }\n return pending;\n }\n\n /**\n * Consume the markup starting at `pos` (a `<`).\n * @param pos - the index of the `<`\n * @returns the index after the markup, or -1 when the buffer ends before the markup does\n */\n private consumeMarkup(pos: number): number {\n const { buffer } = this;\n if (buffer.startsWith(\"<!\", pos)) {\n if (buffer.length - pos < MIN_DECIDABLE_MARKUP && !this.final) {\n // \"<![CDATA[\" is 9 characters; wait until the kind of declaration is decidable\n return -1;\n }\n if (buffer.startsWith(\"<!--\", pos)) {\n const end = buffer.indexOf(\"-->\", pos + 4);\n if (end < 0) {\n return -1;\n }\n this.advanceLine(pos, end + 3);\n return end + 3;\n }\n if (buffer.startsWith(\"<![CDATA[\", pos)) {\n const end = buffer.indexOf(\"]]>\", pos + 9);\n if (end < 0) {\n return -1;\n }\n if (this.text.length === 0) {\n this.textLine = this.line;\n }\n const cdata = buffer.slice(pos + 9, end);\n if (hasIllegalXmlChar(cdata)) {\n throw new XmlSyntaxError(\"a character XML 1.0 forbids appears in a CDATA section\", this.line);\n }\n this.text += cdata;\n this.advanceLine(pos, end + 3);\n return end + 3;\n }\n if (!buffer.startsWith(\"<!DOCTYPE\", pos)) {\n throw new XmlSyntaxError(\"unexpected markup declaration\", this.line);\n }\n const state: Pending = {\n kind: \"doctype\",\n pieces: [],\n tail: \"\",\n quote: 0,\n depth: 0,\n comment: false,\n run: 0,\n };\n const end = this.scanDoctype(state, buffer, pos + 9);\n if (end < 0) {\n return -1;\n }\n this.advanceLine(pos, end);\n return end;\n }\n if (buffer.startsWith(\"<?\", pos)) {\n const end = buffer.indexOf(\"?>\", pos + 2);\n if (end < 0) {\n return -1;\n }\n this.advanceLine(pos, end + 2);\n return end + 2;\n }\n if (buffer.startsWith(\"</\", pos)) {\n const end = buffer.indexOf(\">\", pos + 2);\n if (end < 0) {\n return -1;\n }\n const name = buffer.slice(pos + 2, end).trim();\n if (!isXmlName(name)) {\n throw new XmlSyntaxError(`malformed end tag </${name}>`, this.line);\n }\n this.flushText();\n this.endElement(name);\n this.advanceLine(pos, end + 1);\n return end + 1;\n }\n const tag = this.parseStartTag(pos);\n if (tag === null) {\n return -1;\n }\n this.flushText();\n this.startElement(tag.name, tag.attrs);\n if (tag.selfClosing) {\n this.endElement(tag.name);\n }\n this.advanceLine(pos, tag.end);\n return tag.end;\n }\n\n /**\n * Parse a start tag at `pos`.\n * @param pos - the index of the `<`\n * @returns the tag, or null when the buffer ends inside it\n */\n private parseStartTag(pos: number): StartTag | null {\n const { buffer } = this;\n const { length } = buffer;\n let i = pos + 1;\n const nameEnd = this.readName(i);\n if (nameEnd < 0) {\n return null;\n }\n if (nameEnd === i) {\n throw new XmlSyntaxError(\"expected an element name after <\", this.line);\n }\n const name = buffer.slice(i, nameEnd);\n i = nameEnd;\n const attrs = new Map<string, string>();\n for (;;) {\n while (i < length && isSpace(buffer.charCodeAt(i))) {\n i++;\n }\n if (i >= length) {\n return null;\n }\n const c = buffer.charCodeAt(i);\n if (c === GT) {\n return { name, attrs, selfClosing: false, end: i + 1 };\n }\n if (c === SLASH) {\n if (i + 1 >= length) {\n return null;\n }\n if (buffer.charCodeAt(i + 1) !== GT) {\n throw new XmlSyntaxError(`unexpected \"/\" in <${name}>`, this.line);\n }\n return { name, attrs, selfClosing: true, end: i + 2 };\n }\n const attrEnd = this.readName(i);\n if (attrEnd < 0) {\n return null;\n }\n if (attrEnd === i) {\n throw new XmlSyntaxError(`malformed attribute in <${name}>`, this.line);\n }\n const attrName = buffer.slice(i, attrEnd);\n i = attrEnd;\n while (i < length && isSpace(buffer.charCodeAt(i))) {\n i++;\n }\n if (i >= length) {\n return null;\n }\n if (buffer.charCodeAt(i) !== EQUALS) {\n throw new XmlSyntaxError(`attribute ${attrName} of <${name}> has no value`, this.line);\n }\n i++;\n while (i < length && isSpace(buffer.charCodeAt(i))) {\n i++;\n }\n if (i >= length) {\n return null;\n }\n const quote = buffer.charCodeAt(i);\n if (quote !== QUOTE && quote !== APOS) {\n throw new XmlSyntaxError(`attribute ${attrName} of <${name}> is not quoted`, this.line);\n }\n const close = buffer.indexOf(quote === QUOTE ? '\"' : \"'\", i + 1);\n if (close < 0) {\n return null;\n }\n if (attrs.has(attrName)) {\n throw new XmlSyntaxError(`duplicate attribute ${attrName} in <${name}>`, this.line);\n }\n const raw = buffer.slice(i + 1, close);\n if (hasIllegalXmlChar(raw)) {\n throw new XmlSyntaxError(\n `a character XML 1.0 forbids appears in attribute ${attrName} of <${name}>`,\n this.line,\n );\n }\n attrs.set(attrName, decodeEntities(normalizeAttributeValue(raw), this.line));\n i = close + 1;\n }\n }\n\n /**\n * The end of the XML Name starting at `i` (an ASCII table for the common case, the code point\n * classes beyond it).\n * @param i - the start index\n * @returns the index after the name; `i` when no name starts there; -1 when the name may\n * continue past the end of the buffer\n */\n private readName(i: number): number {\n const { buffer } = this;\n const { length } = buffer;\n let j = i;\n while (j < length) {\n const c = buffer.charCodeAt(j);\n if (c < 0x80) {\n if ((j === i ? ASCII_NAME_START[c] : ASCII_NAME_CHAR[c]) === 0) {\n break;\n }\n j++;\n continue;\n }\n const cp = buffer.codePointAt(j);\n if (cp === undefined || (j === i ? !isNameStart(cp) : !isNameChar(cp))) {\n break;\n }\n j += cp > 0xffff ? 2 : 1;\n }\n return j >= length && !this.final ? -1 : j;\n }\n\n /**\n * Move text from the buffer into the current run.\n * @param start - the start index\n * @param end - the end index (exclusive)\n */\n private takeText(start: number, end: number): void {\n if (end <= start) {\n return;\n }\n if (this.text.length === 0) {\n this.textLine = this.line;\n }\n const raw = this.buffer.slice(start, end);\n if (hasIllegalXmlChar(raw)) {\n throw new XmlSyntaxError(\"a character XML 1.0 forbids appears in character data\", this.line);\n }\n this.text += decodeEntities(raw, this.line);\n this.advanceLine(start, end);\n }\n\n /**\n * Count the newlines of a consumed range. Ranges are consumed in order, so the next line break\n * is searched for once per buffer and re-searched only after it was passed; a buffer without\n * a further break is searched once and remembered as such.\n * @param start - the start index\n * @param end - the end index (exclusive)\n */\n private advanceLine(start: number, end: number): void {\n let i = this.nextBreak;\n if (i === -1) {\n return;\n }\n if (i === -2 || i < start) {\n i = this.buffer.indexOf(\"\\n\", start);\n }\n while (i >= 0 && i < end) {\n this.line++;\n i = this.buffer.indexOf(\"\\n\", i + 1);\n }\n this.nextBreak = i;\n }\n\n /** Deliver the accumulated text run, if any. */\n private flushText(): void {\n if (this.text.length === 0) {\n return;\n }\n const { text } = this;\n this.text = \"\";\n if (this.stack.length === 0) {\n if (!isWhitespace(text)) {\n throw new XmlSyntaxError(\"text outside the root element\", this.textLine);\n }\n return;\n }\n this.handler.text(text, this.textLine);\n }\n\n /**\n * Open an element.\n * @param name - the element name\n * @param attrs - its attributes\n */\n private startElement(name: string, attrs: Map<string, string>): void {\n if (this.stack.length === 0) {\n if (this.rootClosed) {\n throw new XmlSyntaxError(`a second root element <${name}> follows the document element`, this.line);\n }\n this.rootSeen = true;\n }\n this.stack.push(name);\n this.handler.start(name, attrs, this.line);\n }\n\n /**\n * Close an element, checking that it matches the innermost open one.\n * @param name - the element name\n */\n private endElement(name: string): void {\n const open = this.stack.length > 0 ? this.stack[this.stack.length - 1] : null;\n if (open === null) {\n throw new XmlSyntaxError(`unexpected end tag </${name}>`, this.line);\n }\n if (open !== name) {\n throw new XmlSyntaxError(`end tag </${name}> does not match <${open}>`, this.line);\n }\n this.stack.pop();\n if (this.stack.length === 0) {\n this.rootClosed = true;\n }\n this.handler.end(name, this.line);\n }\n}\n\n/**\n * Attribute value normalisation (XML 1.0 section 3.3.3): a literal tab or line break becomes a\n * space; a character reference to one is kept, which is why this runs before entity decoding.\n * @param raw - the value between the quotes\n * @returns the normalised value\n */\nfunction normalizeAttributeValue(raw: string): string {\n return raw.includes(\"\\n\") || raw.includes(\"\\t\") ? raw.replace(/[\\n\\t]/g, \" \") : raw;\n}\n","/**\n * Id, label and value escaping for the text formats (design section 8.5), one function per\n * syntax, with the inverse where the importer needs it: XML attribute and element text (GEXF,\n * GraphML), GML quoted strings (`\"` and `&` and non-ASCII as `&#NN;` character entities, the\n * NetworkX convention), DOT ids (bare when the grammar allows, quoted with `\\\"` otherwise), RFC\n * 4180 CSV cells and Pajek labels.\n */\n\nimport { GraphFormatError } from \"@graphty/graph-format\";\n\nimport { hasIllegalXmlChar } from \"./xml.js\";\n\nconst XML_TEXT_SPECIAL = /[&<>\\r]/g;\nconst XML_ATTR_SPECIAL = /[&<>\"\\t\\n\\r]/g;\nconst XML_REPLACEMENTS: Readonly<Record<string, string>> = {\n \"&\": \"&amp;\",\n \"<\": \"&lt;\",\n \">\": \"&gt;\",\n '\"': \"&quot;\",\n \"\\t\": \"&#9;\",\n \"\\n\": \"&#10;\",\n \"\\r\": \"&#13;\",\n};\n\n/**\n * Escape text for an XML element body: `&`, `<`, `>` and a carriage return (which XML\n * end-of-line handling would turn into a line feed on every read) as character references. A\n * character XML 1.0 forbids (a C0 control other than tab / LF / CR, U+FFFE, U+FFFF, a lone\n * surrogate) has no XML spelling at all and is E_COLUMN_TYPE; the exporters' check() counts them.\n * @param text - the text\n * @returns the escaped text\n */\nexport function escapeXmlText(text: string): string {\n if (hasIllegalXmlChar(text)) {\n throw illegalXml(text);\n }\n return text.replace(XML_TEXT_SPECIAL, (c) => XML_REPLACEMENTS[c]);\n}\n\n/**\n * Escape text for a double-quoted XML attribute value: `&`, `<`, `>`, `\"` and the whitespace\n * characters attribute normalisation would fold; a character XML 1.0 forbids is E_COLUMN_TYPE.\n * @param text - the text\n * @returns the escaped text\n */\nexport function escapeXmlAttribute(text: string): string {\n if (hasIllegalXmlChar(text)) {\n throw illegalXml(text);\n }\n return text.replace(XML_ATTR_SPECIAL, (c) => XML_REPLACEMENTS[c]);\n}\n\n/**\n * The error of a text no XML 1.0 document can carry.\n * @param text - the text\n * @returns the error\n */\nfunction illegalXml(text: string): GraphFormatError {\n return new GraphFormatError(\"E_COLUMN_TYPE\", \"the text holds a character XML 1.0 cannot carry\", {\n reason: \"xml illegal char\",\n length: text.length,\n });\n}\n\nconst GML_SPECIAL = /[\"&]|[^ -~]/gu;\n\n/**\n * Quote a GML string value: double quotes around the text with `\"`, `&` and every character\n * outside printable ASCII written as `&#NN;` (NetworkX's writer convention, which its reader and\n * Gephi's decode).\n * A lone surrogate cannot be written and is E_COLUMN_TYPE.\n * @param text - the text\n * @returns the quoted GML string\n */\nexport function quoteGmlString(text: string): string {\n const escaped = text.replace(GML_SPECIAL, (c) => {\n const code = c.codePointAt(0);\n if (code === undefined) {\n return c;\n }\n if (code >= 0xd800 && code <= 0xdfff) {\n throw new GraphFormatError(\"E_COLUMN_TYPE\", \"a lone surrogate cannot be written as a GML string\", {\n reason: \"lone surrogate\",\n });\n }\n return `&#${code};`;\n });\n return `\"${escaped}\"`;\n}\n\nconst GML_ENTITY = /&(#[0-9]+|#x[0-9a-fA-F]+|[A-Za-z][A-Za-z0-9]*);/g;\n\n/** The XML entities and the ISO-8859-1 HTML entities (U+00A0..U+00FF), which GML uses for characters above 127. */\nconst GML_NAMED: ReadonlyMap<string, string> = (() => {\n const table = new Map<string, string>([\n [\"amp\", \"&\"],\n [\"quot\", '\"'],\n [\"lt\", \"<\"],\n [\"gt\", \">\"],\n [\"apos\", \"'\"],\n ]);\n const latin1 = (\n \"nbsp iexcl cent pound curren yen brvbar sect uml copy ordf laquo not shy reg macr deg plusmn sup2 \" +\n \"sup3 acute micro para middot cedil sup1 ordm raquo frac14 frac12 frac34 iquest Agrave Aacute Acirc \" +\n \"Atilde Auml Aring AElig Ccedil Egrave Eacute Ecirc Euml Igrave Iacute Icirc Iuml ETH Ntilde Ograve \" +\n \"Oacute Ocirc Otilde Ouml times Oslash Ugrave Uacute Ucirc Uuml Yacute THORN szlig agrave aacute \" +\n \"acirc atilde auml aring aelig ccedil egrave eacute ecirc euml igrave iacute icirc iuml eth ntilde \" +\n \"ograve oacute ocirc otilde ouml divide oslash ugrave uacute ucirc uuml yacute thorn yuml\"\n ).split(\" \");\n latin1.forEach((name, i) => {\n table.set(name, String.fromCharCode(0xa0 + i));\n });\n return table;\n})();\n\n/**\n * Decode the character entities of a GML string body (the inverse of quoteGmlString on the text\n * between the quotes): numeric references, the XML entities and the ISO-8859-1 HTML entities. An\n * unknown named entity is left as written and handed to `onUnknown`.\n * @param body - the text between the quotes\n * @param onUnknown - called with each unknown named entity (`&name;`), when given\n * @returns the decoded text\n */\nexport function decodeGmlString(body: string, onUnknown?: (entity: string) => void): string {\n return body.replace(GML_ENTITY, (whole, entity: string) => {\n if (entity.startsWith(\"#x\")) {\n return String.fromCodePoint(Number.parseInt(entity.slice(2), 16));\n }\n if (entity.startsWith(\"#\")) {\n return String.fromCodePoint(Number.parseInt(entity.slice(1), 10));\n }\n const known = GML_NAMED.get(entity);\n if (known === undefined) {\n onUnknown?.(whole);\n return whole;\n }\n return known;\n });\n}\n\nconst DOT_NUMERAL = /^-?(\\.[0-9]+|[0-9]+(\\.[0-9]*)?)$/;\nconst DOT_KEYWORDS: ReadonlySet<string> = new Set([\"node\", \"edge\", \"graph\", \"digraph\", \"subgraph\", \"strict\"]);\n\n/**\n * Whether a text is a DOT ID that needs no quotes: an alphanumeric identifier not starting with\n * a digit, or a numeral, and not a keyword (case-insensitive).\n * @param text - the text\n * @returns true when the text can be written bare\n */\nexport function isBareDotId(text: string): boolean {\n if (DOT_KEYWORDS.has(text.toLowerCase())) {\n return false;\n }\n return isDotIdentifier(text) || DOT_NUMERAL.test(text);\n}\n\n/**\n * Whether a text is a DOT identifier: a letter, underscore or any character of code 128 and\n * above, followed by letters, digits, underscores or such characters.\n * @param text - the text\n * @returns true for a bare identifier\n */\nfunction isDotIdentifier(text: string): boolean {\n if (text.length === 0) {\n return false;\n }\n for (let i = 0; i < text.length; i++) {\n const c = text.charCodeAt(i);\n const letter = (c >= 65 && c <= 90) || (c >= 97 && c <= 122) || c === 95 || c >= 128;\n const digit = c >= 48 && c <= 57;\n if (!letter && (i === 0 || !digit)) {\n return false;\n }\n }\n return true;\n}\n\n/**\n * Whether a text can be written as a DOT ID at all. Graphviz's scanner consumes a backslash pair\n * `\\\\` as one unit, `\\\"` as an escaped quote and a backslash before a line break as a line\n * continuation (both removed), left to right, so a backslash that precedes a double quote or a\n * line break, or ends the text, cannot be written: the written `\\\\\"` reads as a pair and a closing\n * quote, a backslash before a line break vanishes with the break, and a trailing backslash escapes\n * the closing quote. Every other text is writable; quoteDotId() writes it.\n * @param text - the id, name or value text\n * @returns true when quoteDotId(text) reads back as `text`\n */\nexport function isWritableDotText(text: string): boolean {\n return !text.endsWith(\"\\\\\") && !text.includes('\\\\\"') && !/\\\\[\\r\\n]/.test(text);\n}\n\n/**\n * Write a DOT ID: bare when the grammar allows, otherwise double-quoted with `\"` escaped as `\\\"`.\n * In DOT quoted strings the dyad `\\\"` is the only escape; every other character, a backslash and\n * a raw line break included, is kept as written, so nothing else is rewritten. A text ending in a\n * backslash has no DOT spelling (isWritableDotText); the caller refuses it before writing.\n * @param text - the id or label text\n * @returns the DOT ID\n */\nexport function quoteDotId(text: string): string {\n if (isBareDotId(text)) {\n return text;\n }\n return `\"${text.replace(/\"/g, '\\\\\"')}\"`;\n}\n\n/**\n * Write a set CSV cell per RFC 4180: quoted with `\"` doubled when the text contains the\n * delimiter, a quote, a CR or LF, or leading / trailing whitespace; bare otherwise. The empty\n * string is written as the quoted empty cell `\"\"`, so the importers can tell a set empty string\n * (and an empty-string node id, legal under design section 4.1) from an unset cell, which every\n * exporter writes as nothing between the delimiters.\n * @param text - the cell text of a set cell\n * @param delimiter - the field delimiter (default \",\")\n * @returns the cell as written\n */\nexport function quoteCsvCell(text: string, delimiter = \",\"): string {\n if (text.length === 0) {\n return '\"\"';\n }\n if (\n !text.includes(delimiter) &&\n !text.includes('\"') &&\n !text.includes(\"\\n\") &&\n !text.includes(\"\\r\") &&\n text === text.trim()\n ) {\n return text;\n }\n return `\"${text.replace(/\"/g, '\"\"')}\"`;\n}\n\n/**\n * Whether a text can be a Pajek label: Pajek has no escape mechanism inside its double-quoted\n * labels, so a text containing a double quote, a CR or an LF cannot be written.\n * @param text - the label text\n * @returns true when quotePajekLabel() can write it\n */\nexport function isPajekLabel(text: string): boolean {\n return !text.includes('\"') && !text.includes(\"\\n\") && !text.includes(\"\\r\");\n}\n\n/**\n * Write a Pajek label: bare when it is a single run of non-space, non-quote characters, otherwise\n * double-quoted. E_UNSUPPORTED (reason \"pajek label\") for a text isPajekLabel() rejects; the\n * exporter's check() counts those.\n * @param text - the label text\n * @returns the label as written\n */\nexport function quotePajekLabel(text: string): string {\n if (!isPajekLabel(text)) {\n throw new GraphFormatError(\"E_UNSUPPORTED\", \"a Pajek label cannot contain a double quote or a line break\", {\n reason: \"pajek label\",\n value: text,\n });\n }\n if (text.length > 0 && !/[\\s\"]/.test(text)) {\n return text;\n }\n return `\"${text}\"`;\n}\n"],"names":["end"],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  import { GraphFormatError, INVALID_INDEX, MAX_COUNT } from "@graphty/graph-format";
2
2
  import { c as childrenCsr } from "./children-CL3Cy0ez.js";
3
3
  import { z as MIXED_DIRECTION_CODE, g as DIRECTION_FORCED_CODE, h as DIRECTION_REFUSED_CODE, Y as SINK_OPTION_CODE, T as PRECISION_CODE, B as BAD_DEFAULT_CODE, a3 as UNKNOWN_ATTR_TYPE_CODE, X as ROLE_TAKEN_CODE, C as COLUMN_RENAMED_CODE, P as OPTION_IGNORED_CODE, o as ID_MERGED_CODE, _ as STRAY_TEXT_CODE, a4 as UNKNOWN_ELEMENT_CODE, H as HYPEREDGE_CODE, d as COUNT_HINT_CODE, A as MULTIPLE_GRAPHS_CODE, i as DUPLICATE_EDGE_ID_CODE, k as DUPLICATE_NODE_CODE, M as MISSING_ENDPOINT_CODE, y as MISSING_ID_CODE, j as DUPLICATE_KEY_CODE, K as NO_GRAPH_CODE, a5 as UNKNOWN_ENCODING_CODE, n as ENCODING_FALLBACK_CODE, s as INVALID_ENCODING_CODE, u as INVALID_UTF8_CODE, aa as XML_SYNTAX_CODE, q as ID_TEXT_TYPE_CODE, W as ROLE_DROPPED_CODE, R as PARENTS_DROPPED_CODE, F as MUTUAL_AS_UNDIRECTED_CODE, aE as resolveExportOptions, ax as joinText, ak as encodeChunks, ac as capabilities, ad as checkCapabilities, L as LOSS, az as pairFolding, aG as sanitizeIds, al as explicitWeights, av as isNmtoken, at as isCanonicalIntegerText, ay as mangleNmtoken, aq as formatInteger, ao as formatF64, an as formatF32, aF as resolveImportOptions, I as ImportReportBuilder, aC as reportSinkOptions, aD as reportUnusedOptions, t as textChunks, a as throwIfAborted, v as IdCoercer, l as DirectionResolver, aw as isWeightField, aO as declareAttribute, aL as uniqueColumnName, ai as declareResolved, b0 as takenIn, aA as parseWeightText, aQ as parseDeclaredValue, aR as losesPrecision } from "./writer-BdMak4_J.js";
4
- import { f as escapeXmlText, e as isWhitespace, m as isXmlName, g as escapeXmlAttribute, x as xmlIllegalTextNotes, t as tokenizeXml, d as xmlDeclaredEncoding, X as XmlSyntaxError, l as localName } from "./escape-CKied3Ri.js";
4
+ import { f as escapeXmlText, e as isWhitespace, m as isXmlName, g as escapeXmlAttribute, x as xmlIllegalTextNotes, t as tokenizeXml, d as xmlDeclaredEncoding, X as XmlSyntaxError, l as localName } from "./escape-DXbOoLKl.js";
5
5
  const GRAPHML_NAMESPACE = "http://graphml.graphdrawing.org/xmlns";
6
6
  const YFILES_NAMESPACE = "http://www.yworks.com/xml/graphml";
7
7
  const XSI_NAMESPACE = "http://www.w3.org/2001/XMLSchema-instance";
@@ -85,6 +85,10 @@ const GRAPHML_ISSUE = Object.freeze({
85
85
  HYPEREDGE_ENDPOINT: "E_GRAPHML_HYPEREDGE_ENDPOINT",
86
86
  /** `<port>` declarations (and their data) are not kept; sourceport / targetport edge attributes are. */
87
87
  PORT_DECLARATION: "W_GRAPHML_PORT_DECLARATION",
88
+ /** A GraphML `parse.*` hint on `<graph>`, `<node>` or `<edge>` the importer does not act on (parse.nodeids, parse.order, ...). */
89
+ PARSE_HINT_IGNORED: "W_GRAPHML_PARSE_HINT_IGNORED",
90
+ /** An XML attribute GraphML does not define on `<graph>`, `<node>` or `<edge>`; it is not kept. */
91
+ UNKNOWN_XML_ATTRIBUTE: "W_GRAPHML_UNKNOWN_XML_ATTRIBUTE",
88
92
  /** A `<locator>` element. */
89
93
  LOCATOR_DROPPED: "W_GRAPHML_LOCATOR_DROPPED",
90
94
  /** A `<desc>` of a node, an edge or a hyperedge. */
@@ -1336,6 +1340,9 @@ const graphmlExporter = Object.freeze({
1336
1340
  return joinText(writeGraphml(snapshot, plan));
1337
1341
  }
1338
1342
  });
1343
+ const GRAPH_ATTRIBUTES = /* @__PURE__ */ new Set(["id", "edgedefault", "parse.nodes", "parse.edges"]);
1344
+ const NODE_ATTRIBUTES = /* @__PURE__ */ new Set(["id"]);
1345
+ const EDGE_ATTRIBUTES = /* @__PURE__ */ new Set(["id", "source", "target", "directed", "sourceport", "targetport"]);
1339
1346
  const FORMAT_DEFAULTS = { ids: "canonical", defaultDirected: false, weightFrom: "weight" };
1340
1347
  const SNIFF_BYTES = 4096;
1341
1348
  const YFILES_MODES = /* @__PURE__ */ new Set(["json", "skip"]);
@@ -1895,6 +1902,31 @@ class GraphmlReader {
1895
1902
  this.descText = "";
1896
1903
  }
1897
1904
  // ------------------------------------------------------------------ graphs
1905
+ /**
1906
+ * Report, once per element kind and attribute name, an XML attribute the importer does not read:
1907
+ * a GraphML `parse.*` hint as ignored, anything else as unknown. Namespace declarations and
1908
+ * `xml:` / `xsi:` attributes are not data and pass silently.
1909
+ * @param kind - the element name
1910
+ * @param attrs - the element's attributes
1911
+ * @param known - the attributes the importer reads on that element
1912
+ * @param line - the line
1913
+ */
1914
+ reportUnreadAttributes(kind, attrs, known, line) {
1915
+ for (const name of attrs.keys()) {
1916
+ if (known.has(name) || name === "xmlns" || /^(xmlns|xml|xsi):/.test(name)) {
1917
+ continue;
1918
+ }
1919
+ const hint2 = name.startsWith("parse.");
1920
+ const code = hint2 ? GRAPHML_ISSUE.PARSE_HINT_IGNORED : GRAPHML_ISSUE.UNKNOWN_XML_ATTRIBUTE;
1921
+ this.report.warnOnce(
1922
+ "unsupported",
1923
+ code,
1924
+ hint2 ? `the <${kind}> parse hint ${name} is ignored` : `the <${kind}> attribute ${name} is not a GraphML attribute; it is not kept`,
1925
+ { line, element: name },
1926
+ `${code}:${kind}:${name}`
1927
+ );
1928
+ }
1929
+ }
1898
1930
  /**
1899
1931
  * Open a `<graph>`: the top-level one sets the sink's direction (rule 1 of design section
1900
1932
  * 8.4); a nested one records its container as the parent of its nodes.
@@ -1903,6 +1935,7 @@ class GraphmlReader {
1903
1935
  * @param parent - the containing node's index, or INVALID_INDEX
1904
1936
  */
1905
1937
  beginGraph(attrs, line, parent) {
1938
+ this.reportUnreadAttributes("graph", attrs, GRAPH_ATTRIBUTES, line);
1906
1939
  const top = this.graphs.length === 0;
1907
1940
  const edgedefault = attrs.get("edgedefault");
1908
1941
  let directed;
@@ -2466,6 +2499,7 @@ class GraphmlReader {
2466
2499
  * @param line - the line
2467
2500
  */
2468
2501
  beginNode(attrs, line) {
2502
+ this.reportUnreadAttributes("node", attrs, NODE_ATTRIBUTES, line);
2469
2503
  const graph = this.graphs[this.graphs.length - 1];
2470
2504
  const state = {
2471
2505
  id: null,
@@ -2584,6 +2618,7 @@ class GraphmlReader {
2584
2618
  * @param line - the line
2585
2619
  */
2586
2620
  beginEdge(attrs, line) {
2621
+ this.reportUnreadAttributes("edge", attrs, EDGE_ATTRIBUTES, line);
2587
2622
  const graph = this.graphs[this.graphs.length - 1];
2588
2623
  const edge = {
2589
2624
  source: null,
@@ -3053,4 +3088,4 @@ export {
3053
3088
  graphmlImporter as b,
3054
3089
  graphmlExporter as g
3055
3090
  };
3056
- //# sourceMappingURL=importer-DbMrAR_w.js.map
3091
+ //# sourceMappingURL=importer-B9qF4e32.js.map