@graphty/graph-io 0.3.15 → 0.3.17
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.
- package/dist/chunks/{escape-D1f9-cwf.js → escape-scjHxjpr.js} +2 -2
- package/dist/chunks/{escape-D1f9-cwf.js.map → escape-scjHxjpr.js.map} +1 -1
- package/dist/chunks/{importer-C7mnGdr_.js → importer-B6rKRxzv.js} +3 -3
- package/dist/chunks/importer-B6rKRxzv.js.map +1 -0
- package/dist/chunks/{importer-B8lsjFWx.js → importer-BmOl9gLW.js} +3 -3
- package/dist/chunks/{importer-B8lsjFWx.js.map → importer-BmOl9gLW.js.map} +1 -1
- package/dist/chunks/{importer-D7ZcGCeb.js → importer-Xg07gk7p.js} +3 -3
- package/dist/chunks/{importer-D7ZcGCeb.js.map → importer-Xg07gk7p.js.map} +1 -1
- package/dist/chunks/{importer-CXEiicAN.js → importer-ruMWWvVs.js} +3 -3
- package/dist/chunks/{importer-CXEiicAN.js.map → importer-ruMWWvVs.js.map} +1 -1
- package/dist/chunks/{records-IHsCfv7s.js → records-DSpbTE5s.js} +2 -2
- package/dist/chunks/{records-IHsCfv7s.js.map → records-DSpbTE5s.js.map} +1 -1
- package/dist/chunks/{writer-BtWpUaiH.js → writer-DHHfHn11.js} +206 -115
- package/dist/chunks/writer-DHHfHn11.js.map +1 -0
- package/dist/csv.js +3 -3
- package/dist/dot.js +1 -1
- package/dist/gexf.js +2 -2
- package/dist/gml.js +2 -2
- package/dist/graph-io.js +141 -103
- package/dist/graph-io.js.map +1 -1
- package/dist/graphml.js +1 -1
- package/dist/json.js +1 -1
- package/dist/neo4j.js +3 -3
- package/dist/pajek.js +1 -1
- package/dist/src/common/codes.d.ts +43 -0
- package/dist/src/common/codes.d.ts.map +1 -1
- package/dist/src/common/codes.js +43 -0
- package/dist/src/common/codes.js.map +1 -1
- package/dist/src/common/input.d.ts +9 -0
- package/dist/src/common/input.d.ts.map +1 -1
- package/dist/src/common/input.js +16 -0
- package/dist/src/common/input.js.map +1 -1
- package/dist/src/common/options.d.ts +12 -1
- package/dist/src/common/options.d.ts.map +1 -1
- package/dist/src/common/options.js +51 -1
- package/dist/src/common/options.js.map +1 -1
- package/dist/src/formats/json/importer.d.ts.map +1 -1
- package/dist/src/formats/json/importer.js +2 -2
- package/dist/src/formats/json/importer.js.map +1 -1
- package/dist/src/index.d.ts +4 -4
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +3 -3
- package/dist/src/index.js.map +1 -1
- package/dist/src/registry.d.ts +21 -3
- package/dist/src/registry.d.ts.map +1 -1
- package/dist/src/registry.js +29 -0
- package/dist/src/registry.js.map +1 -1
- package/dist/src/types.d.ts +31 -0
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/types.js.map +1 -1
- package/package.json +2 -2
- package/src/common/codes.ts +58 -0
- package/src/common/input.ts +16 -0
- package/src/common/options.ts +78 -2
- package/src/formats/json/importer.ts +2 -1
- package/src/index.ts +5 -0
- package/src/registry.ts +35 -2
- package/src/types.ts +40 -1
- package/dist/chunks/importer-C7mnGdr_.js.map +0 -1
- package/dist/chunks/writer-BtWpUaiH.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"writer-DHHfHn11.js","sources":["../../src/common/codes.ts","../../src/common/temporal.ts","../../src/common/declared-types.ts","../../src/common/lists.ts","../../src/common/attributes.ts","../../src/common/direction.ts","../../src/common/ids.ts","../../src/common/input.ts","../../src/common/options.ts","../../src/types.ts","../../src/common/report.ts","../../src/common/format.ts","../../src/common/weights.ts","../../src/common/export.ts","../../src/common/writer.ts"],"sourcesContent":["/**\n * The issue and loss codes shared by more than one format (design section 8.6: \"a stable code\n * such as E_UNKNOWN_NODE or W_WIDENED\"): one constant per condition, aliased by every format's\n * `<FMT>_ISSUE` / `<FMT>_LOSS` table, so a consumer can switch on a condition without knowing the\n * format and two importers never spell the same condition differently. A condition specific to one\n * format keeps that format's own `E_<FMT>_` / `W_<FMT>_` code next to its importer or exporter.\n *\n * Naming scheme: `E_` for an issue recorded with severity \"error\" (or a loss note whose export()\n * throws), `W_` for a warning; a table key is the code without the severity prefix and without the\n * format prefix.\n */\n\n// ============================================================ importer issues\n\n/** The element (node, attribute, key, ...) has no id where the format requires one. */\nexport const MISSING_ID_CODE = \"E_MISSING_ID\";\n\n/** An edge has no source or no target. */\nexport const MISSING_ENDPOINT_CODE = \"E_MISSING_ENDPOINT\";\n\n/** A node id declared twice; the second declaration merges into the first. */\nexport const DUPLICATE_NODE_CODE = \"W_DUPLICATE_NODE\";\n\n/** The document declares no graph at all (fatal). */\nexport const NO_GRAPH_CODE = \"E_NO_GRAPH\";\n\n/** A second graph in one document is merged into the first. */\nexport const MULTIPLE_GRAPHS_CODE = \"W_MULTIPLE_GRAPHS\";\n\n/** The input is empty (fatal). */\nexport const EMPTY_INPUT_CODE = \"E_EMPTY_INPUT\";\n\n/** The text grammar of the format is violated (fatal; the message carries the detail). */\nexport const SYNTAX_CODE = \"E_SYNTAX\";\n\n/** The XML is not well-formed (fatal; the message carries the detail and the line). */\nexport const XML_SYNTAX_CODE = \"E_XML_SYNTAX\";\n\n/** An element the format does not define at that place was skipped. */\nexport const UNKNOWN_ELEMENT_CODE = \"W_UNKNOWN_ELEMENT\";\n\n/** Text where the format allows only elements was ignored. */\nexport const STRAY_TEXT_CODE = \"W_STRAY_TEXT\";\n\n/** A `pid` / parent reference names a node the document never declares. */\nexport const UNKNOWN_PARENT_CODE = \"E_UNKNOWN_PARENT\";\n\n/** A hyperedge under the `hyperedges: \"error\"` policy (fatal). */\nexport const HYPEREDGE_CODE = \"E_HYPEREDGE\";\n\n/** A declaration's key / attribute id is declared twice. */\nexport const DUPLICATE_KEY_CODE = \"E_DUPLICATE_KEY\";\n\n/**\n * A column was renamed `<name>#<origin.id>` because the name was taken in the sink's table\n * (design section 5.6).\n */\nexport const COLUMN_RENAMED_CODE = \"W_COLUMN_RENAMED\";\n\n/** A column's role was dropped because another column of the table already holds it (design section 5.5). */\nexport const ROLE_TAKEN_CODE = \"W_ROLE_TAKEN\";\n\n/** A long value beyond 2^53 was stored as the nearest f64 (design section 5.1). */\nexport const PRECISION_CODE = \"W_PRECISION\";\n\n/** Two distinct id texts became one number under ids \"number\" (design section 4.1). */\nexport const ID_MERGED_CODE = \"W_ID_MERGED\";\n\n/** A builder-policy option the caller asked for that the sink does not honour (design section 8.4). */\nexport const SINK_OPTION_CODE = \"W_SINK_OPTION\";\n\n/** A common option the format has no use for (or cannot honour) was given a non-default value (design section 8.4). */\nexport const OPTION_IGNORED_CODE = \"W_OPTION_IGNORED\";\n\n/** An invalid UTF-8 sequence in the input (fatal). */\nexport const INVALID_UTF8_CODE = \"E_INVALID_UTF8\";\n\n/** Bytes that are not valid in the encoding a BOM, a declaration or the `encoding` option chose (fatal). */\nexport const INVALID_ENCODING_CODE = \"E_INVALID_ENCODING\";\n\n/** Bytes that are not valid UTF-8 (and declare no other encoding) were read as windows-1252. */\nexport const ENCODING_FALLBACK_CODE = \"W_ENCODING_FALLBACK\";\n\n/** The file declares an encoding the platform's TextDecoder does not know; the declaration is ignored. */\nexport const UNKNOWN_ENCODING_CODE = \"W_UNKNOWN_ENCODING\";\n\n/** The sink refused the file's direction (locked or non-empty); the file is read as the sink's. */\nexport const DIRECTION_REFUSED_CODE = \"W_DIRECTION_REFUSED\";\n\n/** Edges of the other direction were forced to the policy's direction. */\nexport const DIRECTION_FORCED_CODE = \"W_DIRECTION_FORCED\";\n\n/** A mixed-direction file under onMixedDirection \"error\" (import), or a mixed snapshot under the same export policy. */\nexport const MIXED_DIRECTION_CODE = \"E_MIXED_DIRECTION\";\n\n/** A `count` / `parse.nodes` hint the sink cannot reserve (ignored). */\nexport const COUNT_HINT_CODE = \"W_COUNT_HINT\";\n\n/** The declared type is not one the format defines; the column is kept as string. */\nexport const UNKNOWN_ATTR_TYPE_CODE = \"W_UNKNOWN_ATTR_TYPE\";\n\n/** The declared default does not parse as the declared type; the column has no default. */\nexport const BAD_DEFAULT_CODE = \"W_BAD_DEFAULT\";\n\n/** A declared option does not parse as the declared type; the options are dropped. */\nexport const BAD_OPTIONS_CODE = \"W_BAD_OPTIONS\";\n\n/** A repeated edge id in a format whose edge ids are unique; the second edge is skipped. */\nexport const DUPLICATE_EDGE_ID_CODE = \"E_DUPLICATE_EDGE_ID\";\n\n/** A value does not parse as its declared type; the cell is left unset. */\nexport const BAD_VALUE_CODE = \"E_BAD_VALUE\";\n\n/**\n * A column's dtype was widened (design section 5.1) because a later value did not fit: an i32\n * column meeting a value above 2^31, two declared types for one attribute.\n */\nexport const WIDENED_CODE = \"W_WIDENED\";\n\n/**\n * A reference that is not a containment link (an attribute's element id, a layout or bypass\n * entry, a subnetwork member, a view's network, an undeclared target) names nothing; reported\n * once per kind with the count.\n */\nexport const DANGLING_REFERENCE_CODE = \"W_DANGLING_REFERENCE\";\n\n/** The same attribute twice on one element; one value is kept (the later, unless the format's specification says the first). */\nexport const DUPLICATE_ATTRIBUTE_CODE = \"W_DUPLICATE_ATTRIBUTE\";\n\n/** A containment link would close a parent cycle; that one link is dropped. */\nexport const PARENT_CYCLE_CODE = \"E_PARENT_CYCLE\";\n\n/** A formula (Cytoscape's `=ABS($x)`) is kept as its text; it is never evaluated. */\nexport const EQUATION_AS_TEXT_CODE = \"W_EQUATION_AS_TEXT\";\n\n/**\n * The file's style rules (defaults, mappings, dependencies, visual property aspects) are not\n * applied to the snapshot; recorded once per import, the message names what was not applied.\n */\nexport const STYLES_NOT_IMPORTED_CODE = \"W_STYLES_NOT_IMPORTED\";\n\n/** A CX array member that is not a one-key object holding an array or an object; the block is skipped. */\nexport const BAD_ASPECT_BLOCK_CODE = \"E_BAD_ASPECT_BLOCK\";\n\n/** A CX aspect out of its place (after the post-metadata, a status that is not last, a block buffered for what it depends on). */\nexport const ASPECT_ORDER_CODE = \"W_ASPECT_ORDER\";\n\n/** A declared element count disagrees with what was read. */\nexport const COUNT_MISMATCH_CODE = \"W_COUNT_MISMATCH\";\n\n/** The producer marked the document as failed (CX `status.success: false`): it is incomplete (fatal). */\nexport const STATUS_FAILED_CODE = \"E_STATUS_FAILED\";\n\n/** The producer marked the document as successful but attached an error text. */\nexport const STATUS_WARNING_CODE = \"W_STATUS_WARNING\";\n\n/**\n * The input is beyond a size limit (a zip's uncompressed total or ratio, a document longer than\n * one string); the same string as graph-format's E_TOO_LARGE, recorded with category \"unsupported\".\n */\nexport const TOO_LARGE_CODE = \"E_TOO_LARGE\";\n\n/** `graphIndex` is beyond the graphs of the input, or `graphName` names none of them (fatal). */\nexport const GRAPH_NOT_FOUND_CODE = \"E_GRAPH_NOT_FOUND\";\n\n/** `graphName` names more than one graph of the input; the message lists their indexes (fatal). */\nexport const AMBIGUOUS_GRAPH_NAME_CODE = \"E_AMBIGUOUS_GRAPH_NAME\";\n\n// ============================================================ exporter loss notes\n\n/** A role column the format has no slot for is written as a plain attribute (the role is lost). */\nexport const ROLE_DROPPED_CODE = \"W_ROLE_DROPPED\";\n\n/** A parents (multi-parent) column in a format with single containment only. */\nexport const PARENTS_DROPPED_CODE = \"W_PARENTS_DROPPED\";\n\n/** A start / end / timestamp column in a format without temporal support. */\nexport const TEMPORAL_DROPPED_CODE = \"W_TEMPORAL_DROPPED\";\n\n/** A mutual pair is written as two directed edges without the mutual mark. */\nexport const MUTUAL_EXPANDED_CODE = \"W_MUTUAL_EXPANDED\";\n\n/** A mutual pair is written as one undirected edge; the pair reads back undirected, the mark is lost. */\nexport const MUTUAL_AS_UNDIRECTED_CODE = \"W_MUTUAL_AS_UNDIRECTED\";\n\n/** Node ids whose written text reads back as the other type under the importer's id rule. */\nexport const ID_TEXT_TYPE_CODE = \"W_ID_TEXT_TYPE\";\n\n/** Two node ids share one written text; export() throws E_INVALID_ID. */\nexport const ID_TEXT_COLLISION_CODE = \"E_ID_TEXT_COLLISION\";\n\n/** A `<column>.text` companion (design section 5.1) the format cannot carry. */\nexport const TEMPORAL_TEXT_DROPPED_CODE = \"W_TEMPORAL_TEXT_DROPPED\";\n\n/** A plain column named like the importer's weight key reads back as THE weight. */\nexport const WEIGHT_KEY_CLASH_CODE = \"W_WEIGHT_KEY_CLASH\";\n\n/** A role-less column whose written name the importer maps to a role. */\nexport const ROLE_ASSUMED_CODE = \"W_ROLE_ASSUMED\";\n\n/** A role column written into the format's slot reads back under the importer's fixed name. */\nexport const COLUMN_RENAMED_LOSS_CODE = \"W_COLUMN_NAME_CHANGED\";\n\n/** A declared column whose every row is unset is not written by a format without declarations. */\nexport const EMPTY_COLUMN_DROPPED_CODE = \"W_EMPTY_COLUMN_DROPPED\";\n\n/** A string / dict column whose cardinality makes the importer read it back as the other storage class. */\nexport const STORAGE_CLASS_CODE = \"W_STORAGE_CLASS_CHANGED\";\n\n/** An f64 column whose set values are all integral reads back as i32 through an untyped format. */\nexport const INTEGRAL_F64_CODE = \"W_INTEGRAL_F64_AS_I32\";\n\n/** A text cell that reads back as a number or boolean under the 5.1 grammar (its lexical form may change). */\nexport const TEXT_INFERRED_CODE = \"W_TEXT_INFERRED\";\n\n/** A string cell holding a character XML 1.0 forbids; export() throws E_COLUMN_TYPE. */\nexport const XML_ILLEGAL_CHAR_CODE = \"E_XML_ILLEGAL_CHAR\";\n\n/** A dict column without declared options gains one from its dictionary on re-import. */\nexport const OPTIONS_GAINED_CODE = \"W_OPTIONS_GAINED\";\n","/**\n * Temporal values (design section 5.1): `date` / `dateTime` attributes, GEXF time bounds and Neo4j\n * temporal types become f64 epoch milliseconds (or the raw numeric time when the file's timeformat\n * is integer / double). When a value's canonical re-formatting would differ from the source text (a\n * UTC offset, fractional seconds beyond milliseconds, a date without a time in a dateTime column)\n * the importer also keeps the lexical form in a companion `<column>.text` column with role\n * `timeText`; the exporter emits the text when present and formats the number otherwise.\n *\n * Only ISO-8601 forms are parsed (XSD date / dateTime / time and Neo4j's literals), by a fixed\n * grammar rather than Date.parse, so two hosts agree on every value.\n */\n\nimport { type ColumnDecl, type ColumnRole, GraphFormatError } from \"@graphty/graph-format\";\n\n/** The temporal kinds a declared type can map to; each fixes the parse grammar and the canonical text. */\nexport type TemporalKind = \"date\" | \"dateTime\" | \"localDateTime\" | \"time\" | \"localTime\";\n\n/**\n * The GEXF `timeformat` values (design section 5.9).\n * Consumed by the per-format importers and exporters under src/formats.\n * @public\n */\nexport type TimeFormat = \"integer\" | \"double\" | \"date\" | \"dateTime\";\n\n/** A parsed temporal value: the number stored in the column and the source text when it must be kept. */\nexport interface TemporalValue {\n /** Epoch milliseconds (date, dateTime, localDateTime), milliseconds since midnight (time, localTime), or the raw number. */\n readonly value: number;\n /** The source text when formatTemporal(value) would not reproduce it; null otherwise. */\n readonly text: string | null;\n}\n\n/** The role of a companion text column. */\nexport const TIME_TEXT_ROLE: ColumnRole = \"timeText\";\n\n/** The suffix of a companion text column's name. */\nexport const TIME_TEXT_SUFFIX = \".text\";\n\nconst DATE_TIME =\n /^(-?[0-9]{4,})-([0-9]{2})-([0-9]{2})(?:[T ]([0-9]{2}):([0-9]{2})(?::([0-9]{2})(?:\\.([0-9]{1,9}))?)?)?(Z|z|[+-][0-9]{2}(?::?[0-9]{2})?)?$/;\nconst TIME = /^([0-9]{2}):([0-9]{2})(?::([0-9]{2})(?:\\.([0-9]{1,9}))?)?(Z|z|[+-][0-9]{2}(?::?[0-9]{2})?)?$/;\nconst NUMERIC = /^[+-]?([0-9]+(\\.[0-9]*)?|\\.[0-9]+)([eE][+-]?[0-9]+)?$/;\n\nconst MS_PER_MINUTE = 60_000;\nconst MS_PER_DAY = 86_400_000;\n\n/**\n * Parse an ISO-8601 temporal text of one kind.\n * @param text - the source text (already trimmed)\n * @param kind - the temporal kind\n * @returns the value and, when the canonical form differs, the source text; E_COLUMN_TYPE when the text is not of the kind\n */\nexport function parseTemporal(text: string, kind: TemporalKind): TemporalValue {\n let value: number;\n switch (kind) {\n case \"date\":\n case \"dateTime\":\n case \"localDateTime\":\n value = parseDateTime(text, kind);\n break;\n case \"time\":\n case \"localTime\":\n value = parseTime(text, kind);\n break;\n default: {\n const name: string = kind;\n throw new GraphFormatError(\"E_COLUMN_TYPE\", `unknown temporal kind ${name}`, { kind: name });\n }\n }\n const canonical = formatTemporal(value, kind);\n return { value, text: canonical === text ? null : text };\n}\n\n/**\n * Parse a GEXF time bound (`start`, `end`, `timestamp`, a spell or an attvalue time) under the\n * graph's timeformat: integer / double values are numbers as written; date / dateTime values are\n * ISO text; when the format is unknown (absent header) numeric text is a number and anything else\n * is tried as dateTime.\n * @param text - the source text\n * @param timeFormat - the graph's timeformat, or null when the file declares none\n * @returns the value and the source text when it must be kept\n */\nexport function parseTimeText(text: string, timeFormat: TimeFormat | null): TemporalValue {\n const trimmed = text.trim();\n switch (timeFormat) {\n case \"integer\":\n case \"double\":\n return parseNumericTime(trimmed);\n case \"date\":\n return parseTemporal(trimmed, \"date\");\n case \"dateTime\":\n return parseTemporal(trimmed, \"dateTime\");\n case null:\n return NUMERIC.test(trimmed) ? parseNumericTime(trimmed) : parseTemporal(trimmed, \"dateTime\");\n default: {\n const name: string = timeFormat;\n throw new GraphFormatError(\"E_COLUMN_TYPE\", `unknown timeformat ${name}`, { timeFormat: name });\n }\n }\n}\n\n/**\n * Format a temporal value in its canonical ISO-8601 form.\n * @param value - the number as stored\n * @param kind - the temporal kind\n * @returns the canonical text: `YYYY-MM-DD`, `YYYY-MM-DDTHH:MM:SS[.mmm]Z`, `YYYY-MM-DDTHH:MM:SS[.mmm]`,\n * `HH:MM:SS[.mmm]Z` or `HH:MM:SS[.mmm]`\n */\nexport function formatTemporal(value: number, kind: TemporalKind): string {\n switch (kind) {\n case \"date\": {\n const d = new Date(value);\n return `${year(d)}-${pad2(d.getUTCMonth() + 1)}-${pad2(d.getUTCDate())}`;\n }\n case \"dateTime\":\n case \"localDateTime\": {\n const d = new Date(value);\n const date = `${year(d)}-${pad2(d.getUTCMonth() + 1)}-${pad2(d.getUTCDate())}`;\n const time = clock(d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds());\n return kind === \"dateTime\" ? `${date}T${time}Z` : `${date}T${time}`;\n }\n case \"time\":\n case \"localTime\": {\n const ms = ((value % MS_PER_DAY) + MS_PER_DAY) % MS_PER_DAY;\n const h = Math.floor(ms / 3_600_000);\n const m = Math.floor((ms % 3_600_000) / MS_PER_MINUTE);\n const s = Math.floor((ms % MS_PER_MINUTE) / 1000);\n const text = clock(h, m, s, ms % 1000);\n return kind === \"time\" ? `${text}Z` : text;\n }\n default: {\n const name: string = kind;\n throw new GraphFormatError(\"E_COLUMN_TYPE\", `unknown temporal kind ${name}`, { kind: name });\n }\n }\n}\n\n/**\n * Format a GEXF time bound under the graph's timeformat: the number's shortest text for integer /\n * double, the canonical ISO form otherwise.\n * @param value - the value as stored\n * @param timeFormat - the graph's timeformat, or null for a file that declares none (double)\n * @returns the text\n */\nexport function formatTimeValue(value: number, timeFormat: TimeFormat | null): string {\n switch (timeFormat) {\n case \"date\":\n return formatTemporal(value, \"date\");\n case \"dateTime\":\n return formatTemporal(value, \"dateTime\");\n case \"integer\":\n case \"double\":\n case null:\n return String(value);\n default: {\n const name: string = timeFormat;\n throw new GraphFormatError(\"E_COLUMN_TYPE\", `unknown timeformat ${name}`, { timeFormat: name });\n }\n }\n}\n\n/**\n * The declaration of the companion text column of a temporal column (design section 5.1).\n * @param column - the temporal column's name\n * @returns a string column named `<column>.text` with role timeText and `extra.for` naming the column\n */\nexport function timeTextCompanion(column: string): ColumnDecl {\n return {\n name: column + TIME_TEXT_SUFFIX,\n dtype: \"string\",\n role: TIME_TEXT_ROLE,\n nullable: true,\n extra: { for: column },\n };\n}\n\n/**\n * Parse a numeric time bound.\n * @param text - the trimmed source text\n * @returns the number; the text is kept when String(value) differs from it\n */\nfunction parseNumericTime(text: string): TemporalValue {\n if (!NUMERIC.test(text)) {\n throw new GraphFormatError(\"E_COLUMN_TYPE\", `\"${text}\" is not a numeric time`, { value: text });\n }\n const value = Number(text);\n return { value, text: String(value) === text ? null : text };\n}\n\n/**\n * Parse a date or date-time text into epoch milliseconds.\n * @param text - the source text\n * @param kind - date (a time part is accepted and kept in the companion), dateTime or localDateTime\n * @returns epoch milliseconds\n */\nfunction parseDateTime(text: string, kind: \"date\" | \"dateTime\" | \"localDateTime\"): number {\n const m = DATE_TIME.exec(text);\n if (m === null) {\n throw new GraphFormatError(\"E_COLUMN_TYPE\", `\"${text}\" is not an ISO-8601 ${kind}`, { value: text, kind });\n }\n const y = Number(m[1]);\n const month = Number(m[2]);\n const day = Number(m[3]);\n const hour = m[4] === undefined ? 0 : Number(m[4]);\n const minute = m[5] === undefined ? 0 : Number(m[5]);\n const second = m[6] === undefined ? 0 : Number(m[6]);\n const ms = m[7] === undefined ? 0 : fractionMs(m[7]);\n if (month < 1 || month > 12 || day < 1 || day > 31 || hour > 24 || minute > 59 || second > 60) {\n throw new GraphFormatError(\"E_COLUMN_TYPE\", `\"${text}\" is out of range for a ${kind}`, { value: text, kind });\n }\n // Date.UTC maps years 0..99 to 1900..1999; the setters do not\n const d = new Date(0);\n d.setUTCFullYear(y, month - 1, day);\n d.setUTCHours(hour, minute, second, ms);\n if (d.getUTCDate() !== day && hour !== 24) {\n throw new GraphFormatError(\"E_COLUMN_TYPE\", `\"${text}\" is not a calendar date`, { value: text, kind });\n }\n const offset = m[8] === undefined ? 0 : offsetMinutes(m[8]);\n return d.getTime() - offset * MS_PER_MINUTE;\n}\n\n/**\n * Parse a time-of-day text into milliseconds since midnight (UTC for `time` with a zone).\n * @param text - the source text\n * @param kind - time or localTime\n * @returns milliseconds since midnight in 0..86400000\n */\nfunction parseTime(text: string, kind: \"time\" | \"localTime\"): number {\n const m = TIME.exec(text);\n if (m === null) {\n throw new GraphFormatError(\"E_COLUMN_TYPE\", `\"${text}\" is not an ISO-8601 ${kind}`, { value: text, kind });\n }\n const hour = Number(m[1]);\n const minute = Number(m[2]);\n const second = m[3] === undefined ? 0 : Number(m[3]);\n const ms = m[4] === undefined ? 0 : fractionMs(m[4]);\n if (hour > 24 || minute > 59 || second > 60) {\n throw new GraphFormatError(\"E_COLUMN_TYPE\", `\"${text}\" is out of range for a ${kind}`, { value: text, kind });\n }\n const local = ((hour * 60 + minute) * 60 + second) * 1000 + ms;\n const offset = m[5] === undefined ? 0 : offsetMinutes(m[5]);\n const utc = local - offset * MS_PER_MINUTE;\n return ((utc % MS_PER_DAY) + MS_PER_DAY) % MS_PER_DAY;\n}\n\n/**\n * Milliseconds of a fractional-second text (1 to 9 digits), truncated to whole milliseconds.\n * @param digits - the digits after the decimal point\n * @returns 0..999\n */\nfunction fractionMs(digits: string): number {\n return Math.floor(Number(`0.${digits}`) * 1000);\n}\n\n/**\n * The minutes of a zone designator.\n * @param zone - \"Z\", \"+HH:MM\", \"+HHMM\" or \"+HH\"\n * @returns signed minutes east of UTC\n */\nfunction offsetMinutes(zone: string): number {\n if (zone === \"Z\" || zone === \"z\") {\n return 0;\n }\n const sign = zone.startsWith(\"-\") ? -1 : 1;\n const digits = zone.slice(1).replace(\":\", \"\");\n const hours = Number(digits.slice(0, 2));\n const minutes = digits.length > 2 ? Number(digits.slice(2, 4)) : 0;\n return sign * (hours * 60 + minutes);\n}\n\n/**\n * Two-digit zero-padded text.\n * @param n - 0..99\n * @returns the text\n */\nfunction pad2(n: number): string {\n return n < 10 ? `0${n}` : String(n);\n}\n\n/**\n * The year of a UTC date as at least four digits (negative years keep their sign).\n * @param d - the date\n * @returns the text\n */\nfunction year(d: Date): string {\n const y = d.getUTCFullYear();\n const abs = String(Math.abs(y)).padStart(4, \"0\");\n return y < 0 ? `-${abs}` : abs;\n}\n\n/**\n * `HH:MM:SS` with `.mmm` appended when the milliseconds are not zero.\n * @param h - hours\n * @param m - minutes\n * @param s - seconds\n * @param ms - milliseconds\n * @returns the text\n */\nfunction clock(h: number, m: number, s: number, ms: number): string {\n const base = `${pad2(h)}:${pad2(m)}:${pad2(s)}`;\n return ms === 0 ? base : `${base}.${String(ms).padStart(3, \"0\")}`;\n}\n","/**\n * The declared-type table of design section 5.1: what the type text of a GEXF `<attribute>`, a\n * GraphML `<key>`, a GML value class or a Neo4j CSV header maps to, and how a value's text is\n * parsed once the column dtype is known.\n *\n * Declared types map exactly: `double` and `long` -> f64, `float` -> f32, `int` / `integer` /\n * `short` / `byte` -> i32, `boolean` -> bool, `string` / `anyURI` / `char` -> string, `bigdecimal`\n * / `biginteger` -> string, `date` / `dateTime` and the Neo4j temporal types -> f64 (epoch or\n * time-of-day milliseconds, design section 5.1), `list*` and `[]` -> list of the item type, GML\n * `record` and Neo4j `point` -> json. A declared `long` is stored as f64 with a precision flag\n * (values beyond 2^53 are a `precision` issue) unless the importer option `long: \"string\"` keeps the\n * whole column as text. Neo4j `duration` has no epoch and is kept as text. The declared type text is\n * recorded in `origin.type` in every case so the exporter can restore the declaration.\n */\n\nimport { type Dtype, GraphFormatError, type ScalarDtype } from \"@graphty/graph-format\";\n\nimport { parseTemporal, type TemporalKind } from \"./temporal.js\";\n\n/** The formats whose declarations this table covers. */\nexport type DeclaringFormat = \"gexf\" | \"graphml\" | \"gml\" | \"neo4j\";\n\n/** How the text of one scalar value (or one list item) is parsed. */\ntype ValueKind =\n \"boolean\" | \"integer\" | \"long\" | \"float\" | \"double\" | \"string\" | \"temporal\" | \"duration\" | \"point\" | \"json\";\n\n/** The resolved storage of a declared type. */\nexport interface DeclaredTypeSpec {\n /** The declared type text as given by the file (origin.type). */\n readonly declared: string;\n /** The column dtype. */\n readonly dtype: Dtype;\n /** The item dtype of a list column, null otherwise. */\n readonly itemDtype: ScalarDtype | null;\n /** How each scalar value or list item text is parsed. */\n readonly kind: ValueKind;\n /** Whether the column is a list. */\n readonly list: boolean;\n /** The temporal kind of a temporal value, null otherwise. */\n readonly temporal: TemporalKind | null;\n /** Whether values may exceed 2^53 (a long stored as f64), so the importer checks Number.isSafeInteger. */\n readonly precision: boolean;\n}\n\n/** A scalar entry of the table before the list flag and the long mode are applied. */\ninterface ScalarEntry {\n readonly dtype: ScalarDtype;\n readonly kind: ValueKind;\n readonly temporal?: TemporalKind;\n readonly precision?: boolean;\n}\n\nconst BOOLEAN: ScalarEntry = { dtype: \"bool\", kind: \"boolean\" };\nconst INTEGER: ScalarEntry = { dtype: \"i32\", kind: \"integer\" };\nconst LONG: ScalarEntry = { dtype: \"f64\", kind: \"long\", precision: true };\nconst FLOAT: ScalarEntry = { dtype: \"f32\", kind: \"float\" };\nconst DOUBLE: ScalarEntry = { dtype: \"f64\", kind: \"double\" };\nconst STRING: ScalarEntry = { dtype: \"string\", kind: \"string\" };\nconst DATE: ScalarEntry = { dtype: \"f64\", kind: \"temporal\", temporal: \"date\" };\nconst DATE_TIME: ScalarEntry = { dtype: \"f64\", kind: \"temporal\", temporal: \"dateTime\" };\nconst LOCAL_DATE_TIME: ScalarEntry = { dtype: \"f64\", kind: \"temporal\", temporal: \"localDateTime\" };\nconst TIME: ScalarEntry = { dtype: \"f64\", kind: \"temporal\", temporal: \"time\" };\nconst LOCAL_TIME: ScalarEntry = { dtype: \"f64\", kind: \"temporal\", temporal: \"localTime\" };\nconst DURATION: ScalarEntry = { dtype: \"string\", kind: \"duration\" };\nconst POINT: ScalarEntry = { dtype: \"json\", kind: \"point\" };\nconst RECORD: ScalarEntry = { dtype: \"json\", kind: \"json\" };\n\n/** GEXF 1.2 / 1.3 scalar types (the `list*` variants are derived). */\nconst GEXF_SCALARS: Readonly<Record<string, ScalarEntry>> = {\n integer: INTEGER,\n long: LONG,\n double: DOUBLE,\n float: FLOAT,\n boolean: BOOLEAN,\n string: STRING,\n anyuri: STRING,\n char: STRING,\n byte: INTEGER,\n short: INTEGER,\n bigdecimal: STRING,\n biginteger: STRING,\n date: DATE,\n datetime: DATE_TIME,\n};\n\n/** GraphML `attr.type` values. */\nconst GRAPHML_SCALARS: Readonly<Record<string, ScalarEntry>> = {\n boolean: BOOLEAN,\n int: INTEGER,\n long: LONG,\n float: FLOAT,\n double: DOUBLE,\n string: STRING,\n};\n\n/** GML value classes (per value in the file; the GML importer names them per column). */\nconst GML_SCALARS: Readonly<Record<string, ScalarEntry>> = {\n int: INTEGER,\n real: DOUBLE,\n string: STRING,\n record: RECORD,\n};\n\n/** Neo4j CSV header types and Cypher property type names. */\nconst NEO4J_SCALARS: Readonly<Record<string, ScalarEntry>> = {\n int: INTEGER,\n integer: LONG,\n long: LONG,\n float: FLOAT,\n double: DOUBLE,\n boolean: BOOLEAN,\n byte: INTEGER,\n short: INTEGER,\n char: STRING,\n string: STRING,\n point: POINT,\n date: DATE,\n localtime: LOCAL_TIME,\n time: TIME,\n localdatetime: LOCAL_DATE_TIME,\n datetime: DATE_TIME,\n duration: DURATION,\n};\n\nconst TABLES: Readonly<Record<DeclaringFormat, Readonly<Record<string, ScalarEntry>>>> = {\n gexf: GEXF_SCALARS,\n graphml: GRAPHML_SCALARS,\n gml: GML_SCALARS,\n neo4j: NEO4J_SCALARS,\n};\n\nconst INTEGER_TEXT = /^[+-]?[0-9]+$/;\nconst DECIMAL_TEXT = /^[+-]?([0-9]+(\\.[0-9]*)?|\\.[0-9]+)([eE][+-]?[0-9]+)?$/;\nconst I32_MIN = -2147483648;\nconst I32_MAX = 2147483647;\n\n/**\n * Resolve a declared type text of one format to its storage.\n * @param format - the declaring format\n * @param type - the type text as written (matched case-insensitively; GEXF `list*` and Neo4j `[]` denote lists)\n * @param long - how declared long / integer-64 columns are stored (the importer option)\n * @returns the spec, or null when the format does not define the type (the importer reports it and keeps the text)\n */\nexport function mapDeclaredType(\n format: DeclaringFormat,\n type: string,\n long: \"f64\" | \"string\",\n): DeclaredTypeSpec | null {\n const table = TABLES[format];\n let key = type.trim().toLowerCase();\n let list = false;\n if (format === \"gexf\" && key.startsWith(\"list\") && key.length > 4) {\n list = true;\n key = key.slice(4);\n } else if (format === \"neo4j\" && key.endsWith(\"[]\")) {\n list = true;\n key = key.slice(0, -2);\n } else if (format === \"gml\" && key === \"list\") {\n return {\n declared: type,\n dtype: \"list\",\n itemDtype: \"json\",\n kind: \"json\",\n list: true,\n temporal: null,\n precision: false,\n };\n }\n let entry = table[key];\n if (entry === undefined) {\n return null;\n }\n if (entry.kind === \"long\" && long === \"string\") {\n entry = STRING;\n }\n return {\n declared: type,\n dtype: list ? \"list\" : entry.dtype,\n itemDtype: list ? entry.dtype : null,\n kind: entry.kind,\n list,\n temporal: entry.temporal ?? null,\n precision: entry.precision ?? false,\n };\n}\n\n/**\n * The spec of an untyped attribute: a string column with the given (or absent) type text.\n * @param declared - the type text to record in origin.type, or null\n * @returns a string spec\n */\nexport function stringSpec(declared: string | null): DeclaredTypeSpec {\n return {\n declared: declared ?? \"\",\n dtype: \"string\",\n itemDtype: null,\n kind: \"string\",\n list: false,\n temporal: null,\n precision: false,\n };\n}\n\n/**\n * Parse the text of one scalar value (or list item) by its kind. Numeric and boolean kinds trim\n * surrounding whitespace (pretty-printed XML puts newlines around `<data>` text); string kinds keep\n * the text exactly.\n * @param text - the value text\n * @param kind - the value kind\n * @param temporal - the temporal kind when `kind` is \"temporal\"\n * @returns a boolean, a number, a string or (point / json) a JSON value; E_COLUMN_TYPE when the text is not of the kind\n */\nexport function parseScalarText(text: string, kind: ValueKind, temporal: TemporalKind | null = null): unknown {\n switch (kind) {\n case \"boolean\": {\n const value = parseBooleanText(text);\n if (value === null) {\n throw typeError(text, kind);\n }\n return value;\n }\n case \"integer\": {\n const trimmed = text.trim();\n if (!INTEGER_TEXT.test(trimmed)) {\n throw typeError(text, kind);\n }\n const value = Number(trimmed);\n if (value < I32_MIN || value > I32_MAX) {\n throw new GraphFormatError(\"E_COLUMN_TYPE\", `\"${trimmed}\" is outside the 32-bit integer range`, {\n value: trimmed,\n kind,\n });\n }\n return value;\n }\n case \"long\": {\n const trimmed = text.trim();\n if (!INTEGER_TEXT.test(trimmed)) {\n throw typeError(text, kind);\n }\n return Number(trimmed);\n }\n case \"float\":\n case \"double\":\n return parseDecimalText(text, kind);\n case \"string\":\n case \"duration\":\n return text;\n case \"temporal\": {\n if (temporal === null) {\n throw new GraphFormatError(\"E_COLUMN_TYPE\", \"a temporal value needs its temporal kind\", { kind });\n }\n return parseTemporal(text.trim(), temporal).value;\n }\n case \"point\":\n return parsePointText(text);\n case \"json\":\n return parseJsonText(text);\n default: {\n const name: string = kind;\n throw new GraphFormatError(\"E_COLUMN_TYPE\", `unknown value kind ${name}`, { kind: name });\n }\n }\n}\n\n/**\n * Parse a boolean text the way the formats write it: `true` / `false` in any case, or `1` / `0`.\n * @param text - the value text\n * @returns the boolean, or null when the text is neither\n */\nexport function parseBooleanText(text: string): boolean | null {\n switch (text.trim().toLowerCase()) {\n case \"true\":\n case \"1\":\n return true;\n case \"false\":\n case \"0\":\n return false;\n default:\n return null;\n }\n}\n\n/**\n * Parse a float / double text: a decimal or exponent literal, or the XSD / JSON spellings of the\n * non-finite values (`INF`, `-INF`, `Infinity`, `-Infinity`, `NaN`).\n * @param text - the value text\n * @param kind - float or double, for the error\n * @returns the number\n */\nexport function parseDecimalText(text: string, kind: ValueKind = \"double\"): number {\n const trimmed = text.trim();\n if (DECIMAL_TEXT.test(trimmed)) {\n return Number(trimmed);\n }\n switch (trimmed) {\n case \"INF\":\n case \"+INF\":\n case \"Infinity\":\n case \"+Infinity\":\n return Infinity;\n case \"-INF\":\n case \"-Infinity\":\n return -Infinity;\n case \"NaN\":\n return NaN;\n default:\n throw typeError(text, kind);\n }\n}\n\n/**\n * Parse a Neo4j point literal `{x:1.0, y:2.0, crs:'cartesian'}` (also `latitude` / `longitude` /\n * `height` / `z` / `srid`) into a JSON object; a JSON object text is accepted as well.\n * @param text - the value text\n * @returns an object with numeric coordinates and string crs\n */\nexport function parsePointText(text: string): Readonly<Record<string, number | string>> {\n const trimmed = text.trim();\n if (!trimmed.startsWith(\"{\") || !trimmed.endsWith(\"}\")) {\n throw typeError(text, \"point\");\n }\n const out: Record<string, number | string> = {};\n const inner = trimmed.slice(1, -1).trim();\n if (inner.length === 0) {\n return out;\n }\n for (const part of inner.split(\",\")) {\n const colon = part.indexOf(\":\");\n if (colon < 0) {\n throw typeError(text, \"point\");\n }\n const key = part\n .slice(0, colon)\n .trim()\n .replace(/^[\"']|[\"']$/g, \"\");\n const raw = part.slice(colon + 1).trim();\n if (key.length === 0) {\n throw typeError(text, \"point\");\n }\n if (DECIMAL_TEXT.test(raw)) {\n out[key] = Number(raw);\n } else if ((raw.startsWith(\"'\") && raw.endsWith(\"'\")) || (raw.startsWith('\"') && raw.endsWith('\"'))) {\n out[key] = raw.slice(1, -1);\n } else {\n throw typeError(text, \"point\");\n }\n }\n return out;\n}\n\n/**\n * Parse JSON text into a value.\n * @param text - the JSON text\n * @returns the parsed value\n */\nfunction parseJsonText(text: string): unknown {\n try {\n return JSON.parse(text) as unknown;\n } catch {\n throw typeError(text, \"json\");\n }\n}\n\n/**\n * The E_COLUMN_TYPE error of a text that is not of a kind.\n * @param text - the text\n * @param kind - the kind\n * @returns the error\n */\nfunction typeError(text: string, kind: ValueKind): GraphFormatError {\n const shown = text.length > 40 ? `${text.slice(0, 40)}...` : text;\n return new GraphFormatError(\"E_COLUMN_TYPE\", `\"${shown}\" is not a ${kind}`, { value: text, kind });\n}\n","/**\n * List value syntaxes of the text formats (design section 5.1, research note 07 section 2.1):\n * GEXF 1.3 bracket lists `[1, 2, 3]` / `[foo, 'bar baz']`, GEXF 1.2 `liststring` values separated\n * by `|`, `,` or `;` (\"an unsafe type\"), Gephi and Neo4j `;`-separated arrays. The importer splits\n * the text into item texts with splitListText() and parses each item by the declared item type.\n */\n\nimport { GraphFormatError } from \"@graphty/graph-format\";\n\n/** The list syntaxes an importer or exporter names. */\nexport type ListSyntax = \"gexf\" | \"brackets\" | \"pipe\" | \"comma\" | \"semicolon\";\n\n/**\n * Split a list value into its item texts.\n *\n * - \"gexf\": a bracketed text `[a, b]` is parsed with single or double quotes around items that\n * contain commas; otherwise the 1.2 rule applies: the text is split on `|` when it contains one,\n * else on `,` when it contains one, else on `;` when it contains one, else it is one item.\n * - \"brackets\": bracketed only; an unbracketed text is one item.\n * - \"pipe\" / \"comma\" / \"semicolon\": split on that separator.\n *\n * Items are trimmed; an empty text (or `[]`) is an empty list; an empty item between separators\n * is kept as an empty string.\n * @param text - the value text\n * @param syntax - the syntax\n * @returns the item texts\n */\nexport function splitListText(text: string, syntax: ListSyntax): string[] {\n const trimmed = text.trim();\n if (trimmed.length === 0) {\n return [];\n }\n switch (syntax) {\n case \"gexf\": {\n if (isBracketed(trimmed)) {\n return splitBracketed(trimmed);\n }\n const separator = firstSeparator(trimmed, [\"|\", \",\", \";\"]);\n return separator === null ? [trimmed] : splitOn(trimmed, separator);\n }\n case \"brackets\":\n return isBracketed(trimmed) ? splitBracketed(trimmed) : [trimmed];\n case \"pipe\":\n return splitOn(trimmed, \"|\");\n case \"comma\":\n return splitOn(trimmed, \",\");\n case \"semicolon\":\n return splitOn(trimmed, \";\");\n default: {\n const name: string = syntax;\n throw new GraphFormatError(\"E_UNSUPPORTED\", `unknown list syntax ${name}`, {\n option: \"listSyntax\",\n found: name,\n });\n }\n }\n}\n\n/**\n * Join item texts into a list value of one syntax, the inverse of splitListText() for the exporters.\n * Bracket syntaxes quote an item that contains a comma, a bracket or a quote (with double quotes,\n * a double quote inside doubled); separator syntaxes cannot escape and leave items as they are.\n * @param items - the item texts\n * @param syntax - the syntax; \"gexf\" writes the 1.3 bracket form\n * @returns the list text\n */\nexport function joinListText(items: readonly string[], syntax: ListSyntax): string {\n switch (syntax) {\n case \"gexf\":\n case \"brackets\":\n return `[${items.map(quoteBracketItem).join(\", \")}]`;\n case \"pipe\":\n return items.join(\"|\");\n case \"comma\":\n return items.join(\",\");\n case \"semicolon\":\n return items.join(\";\");\n default: {\n const name: string = syntax;\n throw new GraphFormatError(\"E_UNSUPPORTED\", `unknown list syntax ${name}`, {\n option: \"listSyntax\",\n found: name,\n });\n }\n }\n}\n\n/**\n * Whether a trimmed text is `[...]`.\n * @param text - the trimmed text\n * @returns true when bracketed\n */\nfunction isBracketed(text: string): boolean {\n return text.length >= 2 && text.startsWith(\"[\") && text.endsWith(\"]\");\n}\n\n/**\n * The first of several separators that occurs in a text.\n * @param text - the text\n * @param candidates - separators in priority order\n * @returns the first candidate found, or null\n */\nfunction firstSeparator(text: string, candidates: readonly string[]): string | null {\n for (const candidate of candidates) {\n if (text.includes(candidate)) {\n return candidate;\n }\n }\n return null;\n}\n\n/**\n * Split on a separator and trim every item.\n * @param text - the text\n * @param separator - the separator\n * @returns the trimmed items\n */\nfunction splitOn(text: string, separator: string): string[] {\n return text.split(separator).map((item) => item.trim());\n}\n\n/**\n * Parse the inside of a bracketed list: comma-separated items, each optionally wrapped in single\n * or double quotes (a doubled quote inside a quoted item is one quote).\n * @param text - the bracketed text\n * @returns the items\n */\nfunction splitBracketed(text: string): string[] {\n const inner = text.slice(1, -1);\n const items: string[] = [];\n const n = inner.length;\n if (inner.trim().length === 0) {\n return items;\n }\n let i = 0;\n for (;;) {\n while (i < n && isSpace(inner.charCodeAt(i))) {\n i++;\n }\n let item = \"\";\n if (i < n && (inner[i] === '\"' || inner[i] === \"'\")) {\n const quote = inner[i];\n i++;\n while (i < n) {\n if (inner[i] === quote) {\n if (inner[i + 1] === quote) {\n item += quote;\n i += 2;\n continue;\n }\n i++;\n break;\n }\n item += inner[i];\n i++;\n }\n }\n // unquoted text, or text after a closing quote that is not a separator, runs to the next comma\n let end = inner.indexOf(\",\", i);\n if (end < 0) {\n end = n;\n }\n item += inner.slice(i, end).trim();\n items.push(item);\n i = end;\n if (i >= n) {\n return items;\n }\n i++;\n if (inner.slice(i).trim().length === 0) {\n items.push(\"\");\n return items;\n }\n }\n}\n\n/**\n * Whether a char code is ASCII whitespace.\n * @param c - the char code\n * @returns true for space, tab, CR, LF\n */\nfunction isSpace(c: number): boolean {\n return c === 32 || c === 9 || c === 13 || c === 10;\n}\n\n/**\n * Quote one item for a bracket list when it needs it.\n * @param item - the item text\n * @returns the item, quoted when it contains a comma, a bracket, a quote or surrounding whitespace\n */\nfunction quoteBracketItem(item: string): string {\n if (item.length === 0 || /[,[\\]\"']/.test(item) || item !== item.trim()) {\n return `\"${item.replace(/\"/g, '\"\"')}\"`;\n }\n return item;\n}\n","/**\n * Attribute declaration shared by the typed importers (design sections 5.1, 5.5 and 5.6): turn a\n * GEXF `<attribute>`, a GraphML `<key>` or a Neo4j header column into a ColumnDecl with the right\n * dtype, default, options and origin metadata; parse values (scalars and lists) by the declaration;\n * derive the deterministic `<name>#<origin.id>` name when a declared name collides; and the dict\n * heuristic of design section 5.4.\n *\n * Naming rule (design section 5.6): a column's name is the GEXF `title` / GraphML `attr.name`,\n * falling back to the attribute `id` when the title is absent; `origin.id` always keeps the source\n * id and `origin.title` the title when it differs from the resolved name.\n */\n\nimport {\n type ColumnDecl,\n type ColumnHandle,\n type ColumnRole,\n GraphFormatError,\n type GraphSink,\n INVALID_INDEX,\n} from \"@graphty/graph-format\";\n\nimport { type IssueCategory } from \"../types.js\";\nimport {\n BAD_DEFAULT_CODE,\n BAD_OPTIONS_CODE,\n COLUMN_RENAMED_CODE,\n PRECISION_CODE,\n ROLE_TAKEN_CODE,\n UNKNOWN_ATTR_TYPE_CODE,\n} from \"./codes.js\";\nimport {\n type DeclaredTypeSpec,\n type DeclaringFormat,\n mapDeclaredType,\n parseScalarText,\n stringSpec,\n} from \"./declared-types.js\";\nimport { type ListSyntax, splitListText } from \"./lists.js\";\nimport { type ImportReportBuilder, type IssueLocation } from \"./report.js\";\nimport { parseTemporal, type TemporalValue, timeTextCompanion } from \"./temporal.js\";\n\n/**\n * What an importer knows about a declared attribute.\n * Consumed by the per-format importers and exporters under src/formats.\n * @public\n */\nexport interface AttributeDeclarationInput {\n /** The declaring format. */\n readonly format: DeclaringFormat;\n /** The attribute id (GEXF `id`, GraphML key `id`, Neo4j header name); null when the format has none. */\n readonly id: string | null;\n /** The GEXF `title` / GraphML `attr.name`; null when absent (yFiles keys omit it). */\n readonly title: string | null;\n /** The declared type text; null for an untyped declaration (stored as string). */\n readonly type: string | null;\n /** The declaring namespace (\"viz\", \"yfiles\", \"neo4j\"), or null. */\n readonly namespace?: string | null | undefined;\n /** The `<default>` text, or null. */\n readonly defaultText?: string | null | undefined;\n /** The GEXF `<options>` text, or null. */\n readonly optionsText?: string | null | undefined;\n /** The list syntax of defaults, options and values; \"gexf\" by default. */\n readonly listSyntax?: ListSyntax | undefined;\n /** A role to give the column, or null. */\n readonly role?: ColumnRole | null | undefined;\n /** Whether the attribute is dynamic (GEXF mode=\"dynamic\"). */\n readonly dynamic?: boolean | undefined;\n /** The importer's `long` option. */\n readonly long: \"f64\" | \"string\";\n /** Whether a column name is already taken in the target table; drives the `#id` rename. */\n readonly taken?: ((name: string) => boolean) | undefined;\n}\n\n/**\n * A non-fatal problem with a declaration, for the importer to record as a warning.\n * Consumed by the per-format importers and exporters under src/formats.\n * @public\n */\nexport interface DeclarationIssue {\n /** The issue category. */\n readonly category: IssueCategory;\n /** The stable code. */\n readonly code: string;\n /** A plain-ASCII message. */\n readonly message: string;\n}\n\n/**\n * A declared attribute: the ColumnDecl to push, the spec to parse values with, and what to report.\n * Consumed by the per-format importers and exporters under src/formats.\n * @public\n */\nexport interface DeclaredAttribute {\n /** The declaration for declareNodeColumn / declareEdgeColumn. */\n readonly decl: ColumnDecl;\n /** How values are parsed. */\n readonly spec: DeclaredTypeSpec;\n /** The list syntax values are split with. */\n readonly listSyntax: ListSyntax;\n /** The companion text column of a temporal attribute (design section 5.1), or null. */\n readonly companion: ColumnDecl | null;\n /** Whether the name received the `#id` suffix. */\n readonly renamed: boolean;\n /** Problems the importer records as warnings (unknown type, unparsable default or options). */\n readonly issues: readonly DeclarationIssue[];\n}\n\n/** Issue code: the declared type is not one the format defines; the column is kept as string. */\nexport const UNKNOWN_TYPE_CODE = UNKNOWN_ATTR_TYPE_CODE;\n/** Issue code: the column was renamed `<name>#<id>` because the name was taken (design section 5.6). */\nexport const RENAMED_CODE = COLUMN_RENAMED_CODE;\n\nexport { BAD_DEFAULT_CODE, BAD_OPTIONS_CODE, PRECISION_CODE, ROLE_TAKEN_CODE };\n\n/** Rows sampled before the dict heuristic decides (design section 5.4). */\nexport const DICT_SAMPLE_ROWS = 1024;\n\n/**\n * Build the column declaration of a declared attribute.\n * @param input - what the file declares\n * @returns the declaration, the value spec and any warnings to record\n */\nexport function declareAttribute(input: AttributeDeclarationInput): DeclaredAttribute {\n const issues: DeclarationIssue[] = [];\n const listSyntax = input.listSyntax ?? \"gexf\";\n let spec: DeclaredTypeSpec;\n if (input.type === null) {\n spec = stringSpec(null);\n } else {\n const mapped = mapDeclaredType(input.format, input.type, input.long);\n if (mapped === null) {\n spec = stringSpec(input.type);\n issues.push({\n category: \"unsupported\",\n code: UNKNOWN_TYPE_CODE,\n message: `${input.format} type \"${input.type}\" is not supported; values kept as text`,\n });\n } else {\n spec = mapped;\n }\n }\n const { name, renamed } = resolveName(input);\n if (renamed) {\n issues.push({\n category: \"coercion\",\n code: RENAMED_CODE,\n message: `attribute \"${input.title ?? input.id ?? \"\"}\" renamed to \"${name}\": the name was taken`,\n });\n }\n const decl: ColumnDecl = {\n name,\n dtype: spec.dtype,\n nullable: true,\n origin: {\n format: input.format,\n id: input.id,\n title: input.title !== null && input.title !== name ? input.title : null,\n type: input.type,\n namespace: input.namespace ?? null,\n },\n };\n if (spec.list) {\n decl.itemDtype = spec.itemDtype ?? \"string\";\n }\n if (input.role !== undefined && input.role !== null) {\n decl.role = input.role;\n }\n if (input.dynamic === true) {\n decl.dynamic = true;\n }\n const optionsText = input.optionsText ?? null;\n if (optionsText !== null) {\n try {\n const options = splitListText(optionsText, listSyntax).map((item) => parseItem(item, spec));\n decl.options = options;\n if (spec.dtype === \"string\" && !spec.list && options.every((o) => typeof o === \"string\")) {\n decl.dtype = \"dict\";\n spec = { ...spec, dtype: \"dict\" };\n }\n } catch (err) {\n issues.push({\n category: \"validation-error\",\n code: BAD_OPTIONS_CODE,\n message: `options \"${optionsText}\" of attribute \"${name}\" do not parse as ${spec.declared}: ${messageOf(err)}`,\n });\n }\n }\n const defaultText = input.defaultText ?? null;\n if (defaultText !== null) {\n try {\n decl.default = parseDeclaredValue(defaultText, spec, listSyntax);\n } catch (err) {\n issues.push({\n category: \"validation-error\",\n code: BAD_DEFAULT_CODE,\n message: `default \"${defaultText}\" of attribute \"${name}\" does not parse as ${spec.declared}: ${messageOf(err)}`,\n });\n }\n }\n const companion = spec.temporal !== null && !spec.list ? timeTextCompanion(name) : null;\n return { decl, spec, listSyntax, companion, renamed, issues };\n}\n\n/**\n * Parse a value text by a declaration: a scalar, or a list split by the syntax with each item\n * parsed by the item kind.\n * @param text - the value text\n * @param spec - the declared type\n * @param listSyntax - the list syntax\n * @returns the value to push (a boolean, a number, a string, a JSON value or an array)\n */\nexport function parseDeclaredValue(text: string, spec: DeclaredTypeSpec, listSyntax: ListSyntax): unknown {\n if (spec.list) {\n return splitListText(text, listSyntax).map((item) => parseItem(item, spec));\n }\n return parseItem(text, spec);\n}\n\n/**\n * Parse a temporal value text by a declaration, keeping the source text when its canonical form\n * differs (for the companion column).\n * @param text - the value text\n * @param spec - a scalar temporal spec\n * @returns the value and the text to keep, or null text\n */\nexport function parseDeclaredTemporal(text: string, spec: DeclaredTypeSpec): TemporalValue {\n if (spec.temporal === null || spec.list) {\n throw new GraphFormatError(\"E_COLUMN_TYPE\", `\"${spec.declared}\" is not a scalar temporal type`, {\n declared: spec.declared,\n });\n }\n return parseTemporal(text.trim(), spec.temporal);\n}\n\nconst INTEGER_TEXT = /^[+-]?[0-9]+$/;\n\n/**\n * Whether a long value's text lost precision when parsed to f64 (design section 5.1: a value with\n * |v| > 2^53 is stored as the nearest f64 and recorded as a `precision` issue). Decided from the\n * text, since the parsed number alone cannot tell 2^53 from 2^53 + 1.\n * @param spec - the declared type\n * @param text - the value text (trimmed or not)\n * @returns true when the importer should record a `precision` issue\n */\nexport function losesPrecision(spec: DeclaredTypeSpec, text: string): boolean {\n if (!spec.precision) {\n return false;\n }\n const trimmed = text.trim();\n if (!INTEGER_TEXT.test(trimmed)) {\n return false;\n }\n const n = Number(trimmed);\n return !Number.isFinite(n) || BigInt(trimmed) !== BigInt(n);\n}\n\n/**\n * Declare a column on the sink for one domain.\n * @param sink - the sink\n * @param domain - node or edge\n * @param decl - the declaration\n * @returns the column handle\n */\nexport function declareOn(sink: GraphSink, domain: \"node\" | \"edge\", decl: ColumnDecl): ColumnHandle {\n return domain === \"node\" ? sink.declareNodeColumn(decl) : sink.declareEdgeColumn(decl);\n}\n\n/**\n * The outcome of declareResolved(): the handle and the declaration as it was applied.\n * Consumed by the per-format importers under src/formats.\n * @public\n */\nexport interface ResolvedDeclaration {\n /** The column handle. */\n readonly handle: ColumnHandle;\n /** The declaration as applied (its name and role may differ from the request). */\n readonly decl: ColumnDecl;\n /** Whether the column was renamed `<name>#<id>` (W_COLUMN_RENAMED recorded). */\n readonly renamed: boolean;\n /** Whether the role was dropped because the table already holds it (W_ROLE_TAKEN recorded). */\n readonly roleDropped: boolean;\n}\n\n/**\n * The io rule of design section 5.6 in one place, so every importer agrees: declare a column on\n * the sink and, when the sink already holds the name with another shape (an earlier import, a\n * caller's column), rename it `<name>#<origin.id>` (a counter when the source has no id) and\n * record W_COLUMN_RENAMED (coercion); when the table already holds the role (design section 5.5:\n * at most one column per role), declare without the role and record W_ROLE_TAKEN (coercion). The\n * same shape under the same name returns the existing handle, as the sink does.\n * @param sink - the sink\n * @param domain - node or edge\n * @param decl - the wanted declaration\n * @param report - the report the coercion issues are recorded in\n * @param where - the line and element, when known\n * @returns the handle and the declaration as applied\n */\nexport function declareResolved(\n sink: GraphSink,\n domain: \"node\" | \"edge\",\n decl: ColumnDecl,\n report: ImportReportBuilder,\n where?: IssueLocation,\n): ResolvedDeclaration {\n let current = decl;\n let renamed = false;\n let roleDropped = false;\n for (;;) {\n try {\n return { handle: declareOn(sink, domain, current), decl: current, renamed, roleDropped };\n } catch (err) {\n if (!(err instanceof GraphFormatError)) {\n throw err;\n }\n if (err.code === \"E_COLUMN_EXISTS\" && !renamed) {\n const taken = takenIn(sink, domain);\n const id = current.origin?.id ?? null;\n const name = uniqueColumnName(current.name, id, taken);\n report.warning(\n \"coercion\",\n COLUMN_RENAMED_CODE,\n `${domain} column \"${current.name}\" renamed to \"${name}\": the sink already holds that name with another shape`,\n { ...where, element: where?.element ?? current.name },\n );\n current = { ...current, name };\n renamed = true;\n continue;\n }\n if (err.code === \"E_DUPLICATE_ROLE\" && current.role !== undefined && !roleDropped) {\n const holder = typeof err.details.holder === \"string\" ? err.details.holder : \"another column\";\n report.warning(\n \"coercion\",\n ROLE_TAKEN_CODE,\n `${domain} column \"${current.name}\" loses the ${current.role} role: \"${holder}\" already holds it`,\n { ...where, element: where?.element ?? current.name },\n );\n const { role: _role, ...withoutRole } = current;\n current = withoutRole;\n roleDropped = true;\n continue;\n }\n throw err;\n }\n }\n}\n\n/**\n * Declare the companion text column of a temporal column (design section 5.1). A table holds at\n * most one column per role, so when another companion already carries `timeText` this one is\n * declared without the role (reported once per table); exporters find every companion through\n * `extra.for`.\n * @param sink - the sink\n * @param domain - node or edge\n * @param companion - the declaration from declareAttribute()\n * @param report - the report the role loss is recorded in; when omitted the loss is silent\n * @returns the column handle\n */\nexport function declareCompanion(\n sink: GraphSink,\n domain: \"node\" | \"edge\",\n companion: ColumnDecl,\n report?: ImportReportBuilder,\n): ColumnHandle {\n try {\n return declareOn(sink, domain, companion);\n } catch (err) {\n if (err instanceof GraphFormatError && err.code === \"E_DUPLICATE_ROLE\") {\n report?.warnOnce(\n \"coercion\",\n ROLE_TAKEN_CODE,\n `${domain} column \"${companion.name}\" is declared without the timeText role: another companion holds it (exporters use extra.for)`,\n { element: companion.name },\n );\n const { role: _role, ...withoutRole } = companion;\n return declareOn(sink, domain, withoutRole);\n }\n throw err;\n }\n}\n\n/**\n * Whether a column name is taken in a sink's table, the usual `taken` callback.\n * @param sink - the sink\n * @param domain - node or edge\n * @returns a predicate over column names\n */\nexport function takenIn(sink: GraphSink, domain: \"node\" | \"edge\"): (name: string) => boolean {\n return (name: string): boolean =>\n (domain === \"node\" ? sink.nodeColumn(name) : sink.edgeColumn(name)) !== INVALID_INDEX;\n}\n\n/**\n * The deterministic name of a declared attribute whose preferred name is taken (design section\n * 5.6): `<name>#<origin.id>`, and `<name>#<origin.id>#2`, `#3`... should that be taken as well.\n * @param name - the preferred name\n * @param id - the source id (the attribute id or key id); null falls back to a counter\n * @param taken - whether a name is already used in the table\n * @returns a free name\n */\nexport function uniqueColumnName(name: string, id: string | null, taken: (name: string) => boolean): string {\n if (!taken(name)) {\n return name;\n }\n const base = id === null ? name : `${name}#${id}`;\n if (id !== null && !taken(base)) {\n return base;\n }\n for (let n = 2; ; n++) {\n const candidate = `${base}#${n}`;\n if (!taken(candidate)) {\n return candidate;\n }\n }\n}\n\n/**\n * The dict heuristic of design section 5.4 for an untyped string column: observe values until the\n * sample is full; the column is a dict when the distinct count stays below half the rows, a string\n * otherwise. The importer buffers the sampled values and declares the column on the decision.\n */\nexport class DictHeuristic {\n private readonly distinct = new Set<string>();\n\n private rowsSeen = 0;\n\n private readonly sampleRows: number;\n\n /**\n * Create a heuristic.\n * @param sampleRows - rows observed before deciding; DICT_SAMPLE_ROWS by default\n */\n constructor(sampleRows: number = DICT_SAMPLE_ROWS) {\n this.sampleRows = sampleRows;\n }\n\n /**\n * Rows observed so far.\n * @returns the count\n */\n get rows(): number {\n return this.rowsSeen;\n }\n\n /**\n * Distinct values observed so far.\n * @returns the count\n */\n get distinctCount(): number {\n return this.distinct.size;\n }\n\n /**\n * Whether the sample is full.\n * @returns true once sampleRows values were observed\n */\n get decided(): boolean {\n return this.rowsSeen >= this.sampleRows;\n }\n\n /**\n * Observe one value.\n * @param value - the value text\n * @returns true when this observation completed the sample\n */\n observe(value: string): boolean {\n this.rowsSeen++;\n if (this.distinct.size < this.rowsSeen) {\n this.distinct.add(value);\n }\n return this.rowsSeen === this.sampleRows;\n }\n\n /**\n * The dtype the sample suggests: dict when the distinct count is below rows / 2 (and at least\n * one row was seen), string otherwise. Valid before the sample is full (end of input).\n * @returns \"dict\" or \"string\"\n */\n decide(): \"dict\" | \"string\" {\n return this.rowsSeen > 0 && this.distinct.size * 2 < this.rowsSeen ? \"dict\" : \"string\";\n }\n}\n\n/**\n * The resolved name of a declaration and whether it was renamed.\n * @param input - the declaration input\n * @returns the name and the rename flag; E_COLUMN_TYPE when neither a title nor an id exists\n */\nfunction resolveName(input: AttributeDeclarationInput): { name: string; renamed: boolean } {\n const preferred = input.title !== null && input.title.length > 0 ? input.title : input.id;\n if (preferred === null || preferred.length === 0) {\n throw new GraphFormatError(\"E_COLUMN_TYPE\", \"an attribute declaration needs a title or an id\", {\n field: \"name\",\n format: input.format,\n });\n }\n if (input.taken === undefined) {\n return { name: preferred, renamed: false };\n }\n const name = uniqueColumnName(preferred, input.id, input.taken);\n return { name, renamed: name !== preferred };\n}\n\n/**\n * Parse one scalar value or list item by a spec.\n * @param text - the item text\n * @param spec - the declared type\n * @returns the parsed value\n */\nfunction parseItem(text: string, spec: DeclaredTypeSpec): unknown {\n return parseScalarText(text, spec.kind, spec.temporal);\n}\n\n/**\n * The message of a caught value.\n * @param err - the thrown value\n * @returns the message\n */\nfunction messageOf(err: unknown): string {\n return err instanceof Error ? err.message : String(err);\n}\n","/**\n * Direction resolution through the sink (design sections 3.6 and 8.4, decision D-DIR): the\n * importer reads the file's header direction, calls `sink.setDirected()` once before the first\n * edge, then pushes every edge as it is read. Mixed files are handled per `onMixedDirection`:\n *\n * - \"expand\" (default): an undirected edge into a directed sink becomes two logical edges linked\n * by the `graphty.pair` column with `graphty.directed` = false on both halves; a directed edge\n * into an undirected sink triggers ONE `setDirected(true, { expand: true })`, after which the\n * builder has expanded everything pushed so far and the importer continues in directed mode.\n * - \"directed\" / \"undirected\": every edge is treated that way (the distinction is dropped and\n * reported once, with the count).\n * - \"error\": the first edge whose direction differs from the sink's aborts the import.\n *\n * A locked or non-empty sink wins over the file (design section 8.4 precedence): a refused\n * `setDirected` is recorded as a coercion issue and the importer continues with `sink.directed`,\n * expanding every edge that differs. A GEXF `mutual` edge expands like an undirected one with the\n * additional `graphty.mutual` role column set on its primary half.\n *\n * The reserved columns are declared with exactly the builder's own declarations so that a sink the\n * builder already expanded hands back the existing handles.\n */\n\nimport {\n type Column,\n type ColumnDecl,\n type ColumnHandle,\n GraphFormatError,\n type GraphSink,\n type GraphSnapshot,\n INVALID_INDEX,\n type NodeId,\n} from \"@graphty/graph-format\";\n\nimport { DIRECTION_FORCED_CODE, DIRECTION_REFUSED_CODE, MIXED_DIRECTION_CODE } from \"./codes.js\";\nimport { type ImportReportBuilder } from \"./report.js\";\n\n/**\n * The direction of one source edge.\n * Consumed by the per-format importers and exporters under src/formats.\n * @public\n */\nexport type EdgeKind = \"directed\" | \"undirected\" | \"mutual\";\n\n/**\n * Where an edge or header was read, for issues.\n * Consumed by the per-format importers and exporters under src/formats.\n * @public\n */\nexport interface EdgeLocation {\n /** The 1-based line, when known. */\n readonly line?: number | null | undefined;\n /** The edge id or another element name, when known. */\n readonly element?: string | null | undefined;\n}\n\n/** The name of the bool edge column marking source-directed edges (design section 3.6). */\nexport const DIRECTED_COLUMN = \"graphty.directed\";\n\n/** The name of the u32 edge column pairing the halves of an expanded edge (design section 3.6). */\nexport const PAIR_COLUMN = \"graphty.pair\";\n\n/** The name of the bool edge column marking GEXF mutual edges (design section 3.6). */\nexport const MUTUAL_COLUMN = \"graphty.mutual\";\n\nexport { DIRECTION_FORCED_CODE, DIRECTION_REFUSED_CODE, MIXED_DIRECTION_CODE };\n\nconst DIRECTED_DECL: ColumnDecl = { name: DIRECTED_COLUMN, dtype: \"bool\", role: \"directed\" };\nconst PAIR_DECL: ColumnDecl = { name: PAIR_COLUMN, dtype: \"u32\", role: \"pair\", refersTo: \"edge\" };\nconst MUTUAL_DECL: ColumnDecl = { name: MUTUAL_COLUMN, dtype: \"bool\", role: \"mutual\" };\n\n/**\n * Pushes edges into a sink while resolving direction per design section 8.4. One instance per\n * import call; `setHeader()` before the first `addEdge()`.\n */\nexport class DirectionResolver {\n private readonly sink: GraphSink;\n\n private readonly report: ImportReportBuilder;\n\n private readonly policy: \"expand\" | \"directed\" | \"undirected\" | \"error\";\n\n private directedHandle: ColumnHandle = INVALID_INDEX as ColumnHandle;\n\n private pairHandle: ColumnHandle = INVALID_INDEX as ColumnHandle;\n\n private mutualHandle: ColumnHandle = INVALID_INDEX as ColumnHandle;\n\n /** The first edge index this resolver pushed, for the backfill of graphty.directed; -1 before the first. */\n private firstEdge = -1;\n\n /** The next edge index this resolver expects to receive (contiguity between compactions, I16). */\n private nextEdge = -1;\n\n private forcedCount = 0;\n\n private headerSet = false;\n\n private mirrorOfLast: number = INVALID_INDEX;\n\n /**\n * Create a resolver.\n * @param sink - the sink edges are pushed into\n * @param report - the report issues are recorded in\n * @param policy - the resolved onMixedDirection option\n */\n constructor(sink: GraphSink, report: ImportReportBuilder, policy: \"expand\" | \"directed\" | \"undirected\" | \"error\") {\n this.sink = sink;\n this.report = report;\n this.policy = policy;\n }\n\n /**\n * The sink's current direction.\n * @returns true when directed\n */\n get directed(): boolean {\n return this.sink.directed;\n }\n\n /**\n * Whether the reserved direction columns exist (the sink holds expanded edges).\n * @returns true once graphty.pair was declared or adopted\n */\n get expanded(): boolean {\n return this.pairHandle !== INVALID_INDEX;\n }\n\n /**\n * Rule 1 of design section 8.4: set the sink's direction from the file's header (or the\n * `defaultDirected` option for a file that declares none) before the first edge. Under the\n * \"directed\" / \"undirected\" policies the policy's direction is used instead and the difference\n * is reported. A refusal (E_DIRECTED: locked, or a non-empty directed sink for an undirected\n * header) is recorded as a coercion issue and the sink's direction stands; a non-empty unlocked\n * undirected sink with a directed header is expanded in place.\n * @param headerDirected - the direction the file declares (or the default)\n * @param where - the line of the header, when known\n */\n setHeader(headerDirected: boolean, where?: EdgeLocation): void {\n this.headerSet = true;\n let wanted = headerDirected;\n if (this.policy === \"directed\" || this.policy === \"undirected\") {\n wanted = this.policy === \"directed\";\n if (wanted !== headerDirected) {\n this.report.warning(\n \"coercion\",\n DIRECTION_FORCED_CODE,\n `the file declares ${direction(headerDirected)} edges; read as ${direction(wanted)} per onMixedDirection`,\n { line: where?.line ?? null },\n );\n }\n }\n const { sink } = this;\n if (sink.directed === wanted) {\n this.adoptExisting();\n return;\n }\n try {\n if (wanted && sink.edgeCount > 0 && !sink.directedLocked) {\n const before = sink.edgeCount;\n sink.setDirected(true, { expand: true });\n this.adoptExpansionColumns();\n this.report.counts.expandedMixed += before;\n } else {\n sink.setDirected(wanted);\n }\n } catch (err) {\n if (!(err instanceof GraphFormatError) || err.code !== \"E_DIRECTED\") {\n throw err;\n }\n this.report.warning(\n \"coercion\",\n DIRECTION_REFUSED_CODE,\n `the file is ${direction(wanted)} but the sink is ${direction(sink.directed)} (${reasonOf(err)}); read as ${direction(sink.directed)}`,\n { line: where?.line ?? null },\n );\n }\n this.adoptExisting();\n }\n\n /**\n * Pick up reserved columns a caller's sink already holds (an earlier expansion), so every edge\n * pushed from now on gets its graphty.directed value.\n */\n private adoptExisting(): void {\n if (this.pairHandle === INVALID_INDEX && this.sink.edgeColumn(PAIR_COLUMN) !== INVALID_INDEX) {\n this.adoptExpansionColumns();\n }\n }\n\n /**\n * The mirror half of the edge most recently pushed by addEdge(), when it was expanded into a\n * pair; INVALID_INDEX otherwise. An importer that learns an edge's weight after pushing it\n * (a GEXF attvalue) sets it on both halves.\n * @returns the mirror's logical index, or INVALID_INDEX\n */\n get lastMirror(): number {\n return this.mirrorOfLast;\n }\n\n /**\n * Rule 2 of design section 8.4: push one source edge. An edge whose direction equals the\n * sink's is one addEdge; one that differs is expanded, forced or refused per the policy.\n * @param source - the source id\n * @param target - the target id\n * @param kind - the edge's direction in the file\n * @param weight - the weight, or undefined when the file gives none\n * @param where - the line and element, for issues\n * @returns the logical index of the (primary) edge\n */\n addEdge(source: NodeId, target: NodeId, kind: EdgeKind, weight?: number, where?: EdgeLocation): number {\n if (!this.headerSet) {\n throw new GraphFormatError(\"E_DIRECTED\", \"DirectionResolver.setHeader() must run before the first edge\", {\n reason: \"header not set\",\n });\n }\n const { sink } = this;\n this.mirrorOfLast = INVALID_INDEX;\n const edgeDirected = kind !== \"undirected\";\n if (edgeDirected === sink.directed && kind !== \"mutual\") {\n const e = sink.addEdge(source, target, weight);\n this.track(e);\n if (this.directedHandle !== INVALID_INDEX) {\n sink.setEdgeValue(this.directedHandle, e, edgeDirected);\n }\n return e;\n }\n switch (this.policy) {\n case \"directed\":\n case \"undirected\": {\n // the sink's direction is the policy's (or a locked sink's); the edge is pushed as the sink's kind\n this.forcedCount++;\n this.report.warnOnce(\n \"coercion\",\n DIRECTION_FORCED_CODE,\n `${kind} edges read as ${direction(sink.directed)} per onMixedDirection`,\n where,\n );\n const e = sink.addEdge(source, target, weight);\n this.track(e);\n if (this.directedHandle !== INVALID_INDEX) {\n sink.setEdgeValue(this.directedHandle, e, sink.directed);\n }\n return e;\n }\n case \"error\":\n this.report.error(\n \"validation-error\",\n MIXED_DIRECTION_CODE,\n `${kind} edge in a ${direction(sink.directed)} graph (onMixedDirection: \"error\")`,\n where,\n );\n throw this.report.abort(\"mixed direction refused\", { code: MIXED_DIRECTION_CODE });\n case \"expand\":\n return this.expand(source, target, kind, weight, where);\n default: {\n const name: string = this.policy;\n throw new GraphFormatError(\"E_UNSUPPORTED\", `unknown onMixedDirection ${name}`, {\n option: \"onMixedDirection\",\n found: name,\n });\n }\n }\n }\n\n /**\n * How many edges were pushed with a direction other than their own under the forcing policies.\n * @returns the count\n */\n get forced(): number {\n return this.forcedCount;\n }\n\n /**\n * Expand one edge that differs from the sink's direction.\n * @param source - the source id\n * @param target - the target id\n * @param kind - the edge's direction in the file\n * @param weight - the weight, or undefined\n * @param where - the line and element, for issues\n * @returns the primary edge index\n */\n private expand(\n source: NodeId,\n target: NodeId,\n kind: EdgeKind,\n weight: number | undefined,\n where: EdgeLocation | undefined,\n ): number {\n const { sink } = this;\n if (!sink.directed) {\n // a directed (or mutual) edge into an undirected sink: expand the sink once\n try {\n const before = sink.edgeCount;\n sink.setDirected(true, { expand: true });\n this.adoptExpansionColumns();\n this.report.counts.expandedMixed += before;\n } catch (err) {\n if (!(err instanceof GraphFormatError) || err.code !== \"E_DIRECTED\") {\n throw err;\n }\n this.report.error(\n \"coercion\",\n DIRECTION_REFUSED_CODE,\n `${direction(true)} edge in a locked ${direction(false)} sink cannot be expanded`,\n where,\n );\n throw this.report.abort(\"the sink refused the expansion to directed\", {\n code: DIRECTION_REFUSED_CODE,\n reason: err.details.reason,\n });\n }\n if (kind === \"directed\") {\n const e = sink.addEdge(source, target, weight);\n this.track(e);\n sink.setEdgeValue(this.directedHandle, e, true);\n return e;\n }\n }\n this.ensureExpansionColumns();\n const first = sink.addEdge(source, target, weight);\n this.track(first);\n const mutual = kind === \"mutual\";\n sink.setEdgeValue(this.directedHandle, first, mutual);\n this.report.counts.expandedMixed++;\n if (mutual) {\n this.ensureMutualColumn();\n sink.setEdgeValue(this.mutualHandle, first, true);\n }\n const u = sink.indexOf(source);\n const v = sink.indexOf(target);\n if (u === v) {\n // an undirected self-loop is one arc (I7); the builder does not mirror it either\n return first;\n }\n const mirror = sink.addEdge(target, source, weight);\n this.track(mirror);\n this.mirrorOfLast = mirror;\n sink.setEdgeValue(this.directedHandle, mirror, mutual);\n sink.setEdgeValue(this.pairHandle, first, mirror);\n sink.setEdgeValue(this.pairHandle, mirror, first);\n return first;\n }\n\n /**\n * Note an edge index this resolver pushed, for the backfill of graphty.directed.\n * @param e - the edge index\n */\n private track(e: number): void {\n if (this.firstEdge < 0) {\n this.firstEdge = e;\n }\n this.nextEdge = e + 1;\n }\n\n /**\n * Pick up the reserved columns the builder wrote during its own expansion.\n */\n private adoptExpansionColumns(): void {\n this.directedHandle = this.sink.declareEdgeColumn(DIRECTED_DECL);\n this.pairHandle = this.sink.declareEdgeColumn(PAIR_DECL);\n }\n\n /**\n * Declare the reserved columns on first use in a directed sink and backfill graphty.directed\n * = true for every edge this resolver pushed so far (they were directed in the source).\n */\n private ensureExpansionColumns(): void {\n if (this.pairHandle !== INVALID_INDEX) {\n return;\n }\n this.directedHandle = this.sink.declareEdgeColumn(DIRECTED_DECL);\n this.pairHandle = this.sink.declareEdgeColumn(PAIR_DECL);\n if (this.firstEdge >= 0) {\n for (let e = this.firstEdge; e < this.nextEdge; e++) {\n this.sink.setEdgeValue(this.directedHandle, e, true);\n }\n }\n }\n\n /** Declare graphty.mutual on first use. */\n private ensureMutualColumn(): void {\n if (this.mutualHandle === INVALID_INDEX) {\n this.mutualHandle = this.sink.declareEdgeColumn(MUTUAL_DECL);\n }\n }\n}\n\n/**\n * The reason of a refused setDirected(), for messages.\n * @param err - the E_DIRECTED error\n * @returns details.reason when it is a string, \"refused\" otherwise\n */\nfunction reasonOf(err: GraphFormatError): string {\n const { reason } = err.details;\n return typeof reason === \"string\" ? reason : \"refused\";\n}\n\n/**\n * The word for a direction, for messages.\n * @param directed - the direction\n * @returns \"directed\" or \"undirected\"\n */\nfunction direction(directed: boolean): string {\n return directed ? \"directed\" : \"undirected\";\n}\n\n// ============================================================ the exporter side\n\n/**\n * The expanded-pair view of a snapshot's logical edges for exporters (design sections 3.6 and\n * 8.5): which edges are the mirror half of an expanded pair (and are folded back into their\n * primary), which were undirected in the source, and which carry the GEXF mutual mark. One\n * implementation for every exporter; the only per-format choice is whether a mutual pair folds\n * back into one edge (`foldMutual`, for formats with a mutual or undirected slot) or is written as\n * two directed edges (the default).\n * Consumed by the per-format exporters under src/formats.\n * @public\n */\nexport interface PairFolding {\n /** Whether the snapshot carries expanded pairs at all (the pair role column exists). */\n readonly expanded: boolean;\n /** The number of mutual primaries (edges with the mutual mark whose mirror exists). */\n readonly mutualCount: number;\n /**\n * Whether an edge is the mirror half of a pair the exporter folds (its primary is written).\n * @param e - the logical edge index\n * @returns true when the edge must be skipped\n */\n folded(e: number): boolean;\n /**\n * The other half of an expanded pair.\n * @param e - the logical edge index\n * @returns the mate's index, or INVALID_INDEX when the edge is not paired\n */\n mateOf(e: number): number;\n /**\n * Whether an edge was directed in the source (true for every edge of a snapshot without the\n * directed role column, and for an undirected snapshot's edges as far as the column says).\n * @param e - the logical edge index\n * @returns the source direction\n */\n sourceDirected(e: number): boolean;\n /**\n * Whether an edge is a mutual primary or mirror (the GEXF `mutual` type).\n * @param e - the logical edge index\n * @returns true for a mutual edge\n */\n isMutual(e: number): boolean;\n}\n\n/** The per-format choice of pairFolding(). */\nexport interface PairFoldingOptions {\n /**\n * Fold a mutual pair back into its primary (a format with a mutual or undirected slot);\n * false (the default) writes both halves as directed edges, and the caller reports the mark.\n */\n readonly foldMutual?: boolean | undefined;\n}\n\n/**\n * Build the pair-folding view of a snapshot (one pass over the role columns).\n * @param snapshot - the snapshot\n * @param options - the per-format choice\n * @returns the view\n */\nexport function pairFolding(snapshot: GraphSnapshot, options: PairFoldingOptions = {}): PairFolding {\n const foldMutual = options.foldMutual ?? false;\n const directedColumn = roleColumn(snapshot.edges.byRole(\"directed\"), \"bool\");\n const pairColumn = roleColumn(snapshot.edges.byRole(\"pair\"), \"u32\");\n const mutualColumn = roleColumn(snapshot.edges.byRole(\"mutual\"), \"bool\");\n const { edgeCount } = snapshot;\n const mateOf = (e: number): number => {\n if (pairColumn === null || !pairColumn.isSet(e)) {\n return INVALID_INDEX;\n }\n const mate = pairColumn.value(e);\n return typeof mate === \"number\" && mate !== INVALID_INDEX ? mate : INVALID_INDEX;\n };\n const sourceDirected = (e: number): boolean =>\n directedColumn === null || !directedColumn.isSet(e) || directedColumn.value(e) === true;\n const isMutual = (e: number): boolean => {\n if (mutualColumn === null) {\n return false;\n }\n if (mutualColumn.isSet(e) && mutualColumn.value(e) === true) {\n return true;\n }\n const mate = mateOf(e);\n return mate !== INVALID_INDEX && mutualColumn.isSet(mate) && mutualColumn.value(mate) === true;\n };\n const folded = (e: number): boolean => {\n const mate = mateOf(e);\n if (mate === INVALID_INDEX || mate >= e) {\n return false;\n }\n // an undirected pair always folds; a mutual pair (directed on both halves) folds on request\n return !sourceDirected(e) || (foldMutual && isMutual(e));\n };\n let mutualCount = 0;\n if (mutualColumn !== null) {\n for (let e = 0; e < edgeCount; e++) {\n if (mutualColumn.isSet(e) && mutualColumn.value(e) === true && mateOf(e) > e) {\n mutualCount++;\n }\n }\n }\n return { expanded: pairColumn !== null, mutualCount, folded, mateOf, sourceDirected, isMutual };\n}\n\n/**\n * A role column when it has the dtype the role requires, else null.\n * @param column - the column, or null\n * @param dtype - the required dtype\n * @returns the column or null\n */\nfunction roleColumn(column: Column | null, dtype: \"bool\" | \"u32\"): Column | null {\n return column !== null && column.dtype === dtype ? column : null;\n}\n","/**\n * Id coercion (design section 4.1): the importer-side rule that turns a text cell or a JSON value\n * into a NodeId before it reaches the sink. The core never coerces.\n *\n * - \"keep\": typed values pass through; anything that is not a string or a number is E_INVALID_ID.\n * - \"canonical\": text becomes a number iff it is canonical integer text (`/^-?(0|[1-9][0-9]*)$/`\n * and a safe integer, excluding \"-0\" which would collide with \"0\"); every other text stays a\n * string. Injective on text, so `String(id)` on export reproduces the cell exactly: \"01\", \"1.0\"\n * and \"+1\" stay strings, \"1\" becomes 1. Typed values pass through as under \"keep\".\n * - \"string\": `String(v)` for strings, numbers, booleans, bigints and null; anything else is\n * E_INVALID_ID.\n * - \"number\": `Number(text)` for text (empty or whitespace-only text, NaN and non-finite results\n * are E_INVALID_ID); numbers pass through; anything else is E_INVALID_ID. This rule can merge\n * distinct cells (\"01\" and \"1\"); IdCoercer counts such merges so the importer can report them as\n * coercion issues.\n */\n\nimport { GraphFormatError, type IdCoercion, type NodeId } from \"@graphty/graph-format\";\n\nimport { ID_MERGED_CODE } from \"./codes.js\";\n\nconst CANONICAL_INTEGER = /^-?(0|[1-9][0-9]*)$/;\n\nexport { ID_MERGED_CODE };\n\n/**\n * The \"canonical\" rule on one text cell.\n * @param text - the cell text, exactly as read\n * @returns the number for canonical safe-integer text (never for \"-0\"), the text itself otherwise\n */\nexport function canonicalId(text: string): NodeId {\n if (text !== \"-0\" && CANONICAL_INTEGER.test(text)) {\n const n = Number(text);\n if (Number.isSafeInteger(n)) {\n return n;\n }\n }\n return text;\n}\n\n/**\n * Whether a text cell is canonical integer text under the \"canonical\" rule (a number after import).\n * @param text - the cell text\n * @returns true when canonicalId(text) returns a number\n */\nexport function isCanonicalIntegerText(text: string): boolean {\n return typeof canonicalId(text) === \"number\";\n}\n\n/**\n * Coerce a text cell under a rule.\n * @param text - the cell text, exactly as read\n * @param mode - the coercion rule\n * @returns the id; E_INVALID_ID when the rule rejects the text\n */\nexport function coerceIdText(text: string, mode: IdCoercion): NodeId {\n switch (mode) {\n case \"keep\":\n case \"string\":\n return text;\n case \"canonical\":\n return canonicalId(text);\n case \"number\": {\n if (text.trim().length === 0) {\n throw invalidId(text, \"empty text is not a number\");\n }\n const n = Number(text);\n if (!Number.isFinite(n)) {\n throw invalidId(text, \"not a finite number\");\n }\n return n;\n }\n default: {\n const name: string = mode;\n throw new GraphFormatError(\"E_UNSUPPORTED\", `unknown id coercion ${name}`, { option: \"ids\", found: name });\n }\n }\n}\n\n/**\n * Coerce a typed value (a JSON scalar, a record field) under a rule.\n * @param value - the value\n * @param mode - the coercion rule\n * @returns the id; E_INVALID_ID when the rule rejects the value\n */\nexport function coerceId(value: unknown, mode: IdCoercion): NodeId {\n if (typeof value === \"string\") {\n return coerceIdText(value, mode);\n }\n if (typeof value === \"number\") {\n if (!Number.isFinite(value)) {\n throw invalidId(value, \"not a finite number\");\n }\n return mode === \"string\" ? String(value) : value;\n }\n if (mode === \"string\" && (typeof value === \"boolean\" || typeof value === \"bigint\" || value === null)) {\n return String(value);\n }\n throw invalidId(value, `a ${value === null ? \"null\" : typeof value} is not an id under ids: \"${mode}\"`);\n}\n\n/**\n * The E_INVALID_ID error of a rejected value.\n * @param value - the rejected value\n * @param reason - why\n * @returns the error\n */\nfunction invalidId(value: unknown, reason: string): GraphFormatError {\n const shown = typeof value === \"string\" || typeof value === \"number\" ? value : typeof value;\n return new GraphFormatError(\"E_INVALID_ID\", `invalid node id ${JSON.stringify(shown)}: ${reason}`, {\n reason,\n value: typeof value === \"bigint\" ? value.toString() : value,\n });\n}\n\n/**\n * A stateful coercer for one import call: applies the rule and, under \"number\", detects merges\n * (two distinct texts mapping to one number) so the importer can report them as coercion issues\n * (design section 4.1).\n */\nexport class IdCoercer {\n /** The rule. */\n readonly mode: IdCoercion;\n\n /** Texts merged into an id another text already produced. */\n mergeCount = 0;\n\n /** The text that first produced each numeric id, kept only under \"number\". */\n private readonly firstText: Map<number, string> | null;\n\n /** The merge detected by the most recent text() call, or null. */\n lastMerge: { readonly id: number; readonly text: string; readonly previousText: string } | null = null;\n\n /**\n * Create a coercer.\n * @param mode - the rule\n */\n constructor(mode: IdCoercion) {\n this.mode = mode;\n this.firstText = mode === \"number\" ? new Map() : null;\n }\n\n /**\n * Coerce a text cell, recording a merge under \"number\" when a different text already produced\n * the same number.\n * @param text - the cell text\n * @returns the id\n */\n text(text: string): NodeId {\n const id = coerceIdText(text, this.mode);\n this.lastMerge = null;\n if (this.firstText !== null && typeof id === \"number\") {\n const previous = this.firstText.get(id);\n if (previous === undefined) {\n this.firstText.set(id, text);\n } else if (previous !== text) {\n this.mergeCount++;\n this.lastMerge = { id, text, previousText: previous };\n }\n }\n return id;\n }\n\n /**\n * Coerce a typed value.\n * @param value - the value\n * @returns the id\n */\n value(value: unknown): NodeId {\n if (typeof value === \"string\") {\n return this.text(value);\n }\n this.lastMerge = null;\n return coerceId(value, this.mode);\n }\n}\n","/**\n * Input handling shared by every importer (design section 8.4): the ImportInput union (whole\n * text, whole bytes, a byte stream, an async iterable of text or byte chunks) read as a sequence of\n * text chunks, as lines, or as one string, with BOM handling, cancellation through an AbortSignal\n * and byte progress.\n *\n * Bytes are decoded ONCE, here, for every importer. The encoding is, in order of precedence: the\n * caller's `encoding` option; a byte order mark (UTF-8, UTF-16LE, UTF-16BE); the encoding the file\n * declares (the importer's `declaredEncoding` reader: the XML prolog for GEXF and GraphML, the\n * `charset` attribute for DOT); else UTF-8. Decoding is strict (`fatal: true`): an invalid sequence\n * is never a silent U+FFFD that could alias two ids. Only in the last case, when bytes that are not\n * valid UTF-8 appear while everything before them was ASCII, is the rest of the input read as\n * windows-1252 (the superset of ISO 8859-1 that Excel, Pajek and older tools write), with the\n * warning W_ENCODING_FALLBACK; invalid UTF-8 after valid non-ASCII UTF-8 is E_INVALID_UTF8. A\n * leading U+FEFF is stripped from text and from decoded bytes alike.\n */\n\nimport { GraphFormatError } from \"@graphty/graph-format\";\n\nimport { type ImportInput } from \"../types.js\";\nimport { ENCODING_FALLBACK_CODE, INVALID_ENCODING_CODE, INVALID_UTF8_CODE, UNKNOWN_ENCODING_CODE } from \"./codes.js\";\nimport { type ImportReportBuilder } from \"./report.js\";\n\nexport { INVALID_UTF8_CODE };\n\n/**\n * Cancellation and progress hooks of the reader; the resolved importer options satisfy this shape.\n * Consumed by the per-format importers and exporters under src/formats.\n * @public\n */\nexport interface ReadOptions {\n /** The cancellation signal, or null / undefined for none. */\n readonly signal?: AbortSignal | null | undefined;\n /** The progress callback, or null / undefined for none. */\n readonly onProgress?: ((bytesDone: number, bytesTotal?: number) => void) | null | undefined;\n /** The caller's `encoding` option (a label TextDecoder knows), or null / undefined for detection. */\n readonly encoding?: string | null | undefined;\n /**\n * The format's reader of a declared encoding: given the head of the input decoded as\n * windows-1252 (ASCII-compatible), the encoding label it declares, or null.\n */\n readonly declaredEncoding?: ((head: string) => string | null) | undefined;\n}\n\n/** How many leading bytes the declaration check sees (an XML prolog, a DOT `charset` near the top). */\nconst HEAD_BYTES = 1024;\n\n/** How many leading bytes the BOM check needs. */\nconst BOM_BYTES = 3;\n\n/**\n * The canonical name of an encoding label, or null when the platform's TextDecoder does not know it.\n * @param label - a WHATWG encoding label (\"latin1\", \"UTF-16LE\", \"cp1252\", ...)\n * @returns the canonical name (\"windows-1252\", \"utf-16le\", ...) or null\n */\nexport function canonicalEncoding(label: string): string | null {\n try {\n return new TextDecoder(label.trim()).encoding;\n } catch {\n return null;\n }\n}\n\n/**\n * The encoding a byte order mark announces.\n * @param head - the first bytes\n * @returns \"utf-8\", \"utf-16le\", \"utf-16be\" or null\n */\nfunction bomEncoding(head: Uint8Array): string | null {\n if (head.byteLength >= 3 && head[0] === 0xef && head[1] === 0xbb && head[2] === 0xbf) {\n return \"utf-8\";\n }\n if (head.byteLength >= 2 && head[0] === 0xff && head[1] === 0xfe) {\n return \"utf-16le\";\n }\n if (head.byteLength >= 2 && head[0] === 0xfe && head[1] === 0xff) {\n return \"utf-16be\";\n }\n return null;\n}\n\n/**\n * The one byte decoder of an import: picks the encoding from the head (option, BOM, declaration,\n * UTF-8) and decodes strictly, switching to windows-1252 with a warning when undeclared input\n * turns out not to be UTF-8 while everything decoded so far was ASCII.\n */\nclass ByteDecoder {\n private decoder: TextDecoder | null = null;\n\n private encoding = \"utf-8\";\n\n /** Whether a failed UTF-8 decode may switch to windows-1252 (nothing chose UTF-8 explicitly). */\n private mayFallBack = false;\n\n /** Whether every character decoded so far was ASCII (so switching encodings changes no earlier text). */\n private asciiSoFar = true;\n\n /** While asciiSoFar: the bytes the UTF-8 decoder holds back (a sequence split across chunks). */\n private carry: Uint8Array = new Uint8Array(0);\n\n /** Bytes decoded so far, for error positions. */\n private offset = 0;\n\n /**\n * Create the decoder of one import.\n * @param report - where warnings and the fatal decode error go\n * @param options - the encoding option and the format's declaration reader\n */\n constructor(\n private readonly report: ImportReportBuilder,\n private readonly options: ReadOptions,\n ) {}\n\n /**\n * Whether start() ran.\n * @returns true once the encoding is chosen\n */\n get started(): boolean {\n return this.decoder !== null;\n }\n\n /**\n * Choose the encoding from the first bytes of the input.\n * @param head - the first bytes (up to HEAD_BYTES; fewer when the input is shorter)\n */\n start(head: Uint8Array): void {\n const explicit = this.options.encoding ?? null;\n if (explicit !== null) {\n this.use(explicit, false);\n return;\n }\n const bom = bomEncoding(head);\n if (bom !== null) {\n this.use(bom, false);\n return;\n }\n const declared = this.options.declaredEncoding?.(new TextDecoder(\"windows-1252\").decode(head)) ?? null;\n if (declared !== null) {\n const canonical = canonicalEncoding(declared);\n if (canonical === null) {\n this.report.warning(\n \"unsupported\",\n UNKNOWN_ENCODING_CODE,\n `the input declares the encoding ${JSON.stringify(declared)}, which this platform cannot decode; reading it as UTF-8`,\n { element: declared },\n );\n } else if (canonical !== \"utf-8\" && !canonical.startsWith(\"utf-16\")) {\n // a declared UTF-16 without a BOM is not UTF-16 (its declaration read as ASCII), and\n // a declared UTF-8 gets the same undeclared treatment: tools often write the default\n // prolog over Latin-1 bytes\n this.use(canonical, false);\n return;\n }\n }\n this.use(\"utf-8\", true);\n }\n\n /**\n * Decode the next bytes.\n * @param bytes - the bytes\n * @param stream - whether more bytes follow\n * @returns the text\n */\n decode(bytes: Uint8Array, stream: boolean): string {\n const decoder = this.decoder as TextDecoder;\n let text: string;\n try {\n text = decoder.decode(bytes, { stream });\n } catch (err) {\n if (!(err instanceof TypeError)) {\n throw err;\n }\n text = this.recover(bytes, stream);\n }\n if (this.asciiSoFar && this.mayFallBack) {\n if (/[\\u0080-\\uffff]/.test(text)) {\n this.asciiSoFar = false;\n this.carry = new Uint8Array(0);\n } else {\n // every character so far is one ASCII byte, so what was not emitted is held back\n const all = this.carry.byteLength === 0 ? bytes : concatBytes([this.carry, bytes]);\n this.carry = all.slice(text.length);\n }\n }\n this.offset += bytes.byteLength;\n return text;\n }\n\n /**\n * A decode failed: switch to windows-1252 when allowed, else fail the import.\n * @param bytes - the bytes that failed\n * @param stream - whether more bytes follow\n * @returns the bytes decoded as windows-1252\n */\n private recover(bytes: Uint8Array, stream: boolean): string {\n const where = { byteOffset: this.offset };\n const all = this.carry.byteLength === 0 ? bytes : concatBytes([this.carry, bytes]);\n // a NUL byte never occurs in windows-1252 text: it marks binary data (or BOM-less UTF-16)\n if (this.mayFallBack && this.asciiSoFar && !all.includes(0) && !startsWithUtf8(all)) {\n this.report.warning(\n \"coercion\",\n ENCODING_FALLBACK_CODE,\n `the input is not valid UTF-8 (near byte ${this.offset}) and declares no encoding; read as windows-1252 (pass the encoding option to choose another)`,\n );\n this.use(\"windows-1252\", false);\n return (this.decoder as TextDecoder).decode(all, { stream });\n }\n if (this.encoding === \"utf-8\") {\n const after = this.mayFallBack ? \" after valid non-ASCII UTF-8 text; pass the encoding option\" : \"\";\n return this.report.fail(\n INVALID_UTF8_CODE,\n `invalid UTF-8 near byte ${this.offset}${after}`,\n undefined,\n where,\n );\n }\n return this.report.fail(\n INVALID_ENCODING_CODE,\n `the bytes near byte ${this.offset} are not valid ${this.encoding}`,\n undefined,\n where,\n );\n }\n\n /**\n * Switch to an encoding.\n * @param label - the encoding label\n * @param mayFallBack - whether a UTF-8 failure may switch to windows-1252\n */\n private use(label: string, mayFallBack: boolean): void {\n this.decoder = new TextDecoder(label, { fatal: true, ignoreBOM: true });\n this.encoding = this.decoder.encoding;\n this.mayFallBack = mayFallBack;\n }\n}\n\n/**\n * Whether the first non-ASCII byte of a chunk starts a valid UTF-8 sequence: then the chunk holds\n * valid non-ASCII UTF-8 before whatever made it fail, and the input is not windows-1252.\n * @param bytes - a chunk that failed to decode as UTF-8\n * @returns true when its first non-ASCII sequence is valid UTF-8\n */\nfunction startsWithUtf8(bytes: Uint8Array): boolean {\n const i = bytes.findIndex((b) => b >= 0x80);\n const lead = bytes[i];\n let length = 0;\n if (lead >= 0xc2 && lead <= 0xdf) {\n length = 2;\n } else if (lead >= 0xe0 && lead <= 0xef) {\n length = 3;\n } else if (lead >= 0xf0 && lead <= 0xf4) {\n length = 4;\n }\n if (i < 0 || length === 0 || i + length > bytes.byteLength) {\n return false;\n }\n try {\n new TextDecoder(\"utf-8\", { fatal: true }).decode(bytes.subarray(i, i + length));\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * A zip entry name as text (APPNOTE 4.4.17): UTF-8 when the bytes are valid UTF-8, whether or not\n * the entry sets the language-encoding flag (bit 11), else windows-1252 (WHATWG has no CP437, and\n * session entry names are ASCII in practice). Never throws: a name is a matching key, never a path,\n * so an undecodable one still has to name its entry.\n * @param bytes - the name bytes from the central directory or a local header\n * @returns the name\n */\nexport function decodeEntryName(bytes: Uint8Array): string {\n try {\n return new TextDecoder(\"utf-8\", { fatal: true, ignoreBOM: true }).decode(bytes);\n } catch {\n return new TextDecoder(\"windows-1252\").decode(bytes);\n }\n}\n\n/**\n * Join byte chunks.\n * @param chunks - the chunks\n * @returns one array holding them in order\n */\nfunction concatBytes(chunks: readonly Uint8Array[]): Uint8Array {\n if (chunks.length === 1) {\n return chunks[0];\n }\n const out = new Uint8Array(chunks.reduce((sum, c) => sum + c.byteLength, 0));\n let offset = 0;\n for (const chunk of chunks) {\n out.set(chunk, offset);\n offset += chunk.byteLength;\n }\n return out;\n}\n\n/**\n * Bytes decoded per call when the input is one in-memory Uint8Array: every consumer of textChunks()\n * then sees bounded chunks whatever the input shape (a line reader or a record reader that holds\n * one parse result per chunk never holds more than this much text at once), and progress stays\n * granular.\n */\nconst DECODE_SLICE = 256 * 1024;\n\nconst BOM = String.fromCharCode(0xfeff);\n\n/**\n * Whether a value is an ImportInput this module can read.\n * @param input - any value\n * @returns true for a string, a Uint8Array, a ReadableStream or an async iterable\n */\nexport function isImportInput(input: unknown): input is ImportInput {\n if (typeof input === \"string\" || input instanceof Uint8Array) {\n return true;\n }\n if (typeof input !== \"object\" || input === null) {\n return false;\n }\n return typeof (input as { getReader?: unknown }).getReader === \"function\" || Symbol.asyncIterator in input;\n}\n\n/**\n * The total size of an in-memory input (bytes for a Uint8Array, UTF-16 code units for a string),\n * for the `bytesTotal` argument of onProgress; null for a stream or an iterable.\n * @param input - the input\n * @returns the size, or null when unknown up front\n */\nexport function inputLength(input: ImportInput): number | null {\n if (typeof input === \"string\") {\n return input.length;\n }\n if (input instanceof Uint8Array) {\n return input.byteLength;\n }\n return null;\n}\n\n/**\n * Throw the signal's reason when it is aborted, exactly as the platform's\n * `AbortSignal.throwIfAborted()` does: the reason as it is (the DOMException named \"AbortError\"\n * of a reason-less abort, or whatever the caller passed to `abort(reason)`, an Error or not), so a\n * caller can compare the rejection with `signal.reason`. Only a runtime that stores no reason at\n * all gets a synthesised AbortError.\n * @param signal - the signal, or null\n */\nexport function throwIfAborted(signal: AbortSignal | null | undefined): void {\n if (signal === null || signal === undefined || !signal.aborted) {\n return;\n }\n const { reason }: { reason: unknown } = signal;\n if (reason === undefined) {\n throw abortError();\n }\n // the platform contract: the reason itself, whatever its type\n throw reason as Error;\n}\n\n/**\n * An abort error for a signal that carries no reason.\n * @returns a DOMException named \"AbortError\" where DOMException exists, else an Error with that name\n */\nfunction abortError(): Error {\n const message = \"The import was aborted\";\n if (typeof DOMException === \"function\") {\n return new DOMException(message, \"AbortError\");\n }\n const err = new Error(message);\n err.name = \"AbortError\";\n return err;\n}\n\n/**\n * Read an ImportInput as a sequence of decoded text chunks. Chunk boundaries carry no meaning:\n * a caller that needs lines uses LineReader, one that needs the whole document uses readText().\n * The signal is checked before every chunk; a stream is cancelled when the consumer stops early\n * or the signal fires. Progress is reported after every chunk.\n * @param input - the input\n * @param report - the report the decode error is recorded in (E_INVALID_UTF8, then ImportError)\n * @param options - cancellation and progress\n * @yields decoded text; the first chunk has any leading BOM removed\n * @returns nothing\n */\nexport async function* textChunks(\n input: ImportInput,\n report: ImportReportBuilder,\n options: ReadOptions = {},\n): AsyncGenerator<string, void, undefined> {\n const signal = options.signal ?? null;\n const onProgress = options.onProgress ?? null;\n const total = inputLength(input);\n let done = 0;\n let first = true;\n const emit = (text: string): string => {\n if (first && text.length > 0) {\n first = false;\n return text.startsWith(BOM) ? text.slice(1) : text;\n }\n return text;\n };\n throwIfAborted(signal);\n if (typeof input === \"string\") {\n const text = emit(input);\n done = input.length;\n if (text.length > 0) {\n yield text;\n }\n onProgress?.(done, total ?? undefined);\n return;\n }\n const decoder = new ByteDecoder(report, options);\n if (input instanceof Uint8Array) {\n decoder.start(input.subarray(0, HEAD_BYTES));\n for (let offset = 0; offset < input.byteLength; offset += DECODE_SLICE) {\n throwIfAborted(signal);\n const slice = input.subarray(offset, Math.min(offset + DECODE_SLICE, input.byteLength));\n const text = emit(decoder.decode(slice, offset + DECODE_SLICE < input.byteLength));\n done = Math.min(offset + DECODE_SLICE, input.byteLength);\n if (text.length > 0) {\n yield text;\n }\n onProgress?.(done, total ?? undefined);\n }\n if (input.byteLength === 0) {\n onProgress?.(0, 0);\n }\n return;\n }\n // the first bytes of a stream are held back until the BOM check (and the declaration check,\n // when the format has one) can see enough of them, or the input ended, or text arrived, so a\n // BOM or a declaration split across small chunks is still seen\n const needed = options.declaredEncoding === undefined ? BOM_BYTES : HEAD_BYTES;\n let head: Uint8Array[] = [];\n let headLength = 0;\n const flushHead = (stream: boolean): string => {\n const bytes = concatBytes(head);\n head = [];\n headLength = 0;\n decoder.start(bytes.subarray(0, HEAD_BYTES));\n return decoder.decode(bytes, stream);\n };\n const chunks = isReadableStream(input) ? streamChunks(input, signal) : input;\n for await (const chunk of chunks) {\n throwIfAborted(signal);\n let text: string;\n if (typeof chunk === \"string\") {\n // finish any byte sequence still pending in the decoder before switching to text\n let pending = \"\";\n if (!decoder.started && headLength > 0) {\n pending = flushHead(false);\n } else if (decoder.started) {\n pending = decoder.decode(new Uint8Array(0), false);\n }\n text = emit(pending + chunk);\n done += chunk.length;\n } else if (chunk instanceof Uint8Array) {\n done += chunk.byteLength;\n if (decoder.started) {\n text = emit(decoder.decode(chunk, true));\n } else {\n head.push(chunk);\n headLength += chunk.byteLength;\n text = headLength >= needed ? emit(flushHead(true)) : \"\";\n }\n } else {\n throw new GraphFormatError(\"E_UNSUPPORTED\", \"an input chunk must be a string or a Uint8Array\", {\n reason: \"chunk type\",\n found: typeof chunk,\n });\n }\n if (text.length > 0) {\n yield text;\n }\n onProgress?.(done);\n }\n let tail = \"\";\n if (!decoder.started && headLength > 0) {\n tail = flushHead(false);\n } else if (decoder.started) {\n tail = decoder.decode(new Uint8Array(0), false);\n }\n tail = emit(tail);\n if (tail.length > 0) {\n yield tail;\n }\n onProgress?.(done, done);\n}\n\n/**\n * Whether an input is a ReadableStream (by duck type, so a stream from another realm qualifies).\n * @param input - a non-string, non-Uint8Array input\n * @returns true for a ReadableStream\n */\nfunction isReadableStream(\n input: ReadableStream<Uint8Array> | AsyncIterable<string | Uint8Array>,\n): input is ReadableStream<Uint8Array> {\n return typeof (input as { getReader?: unknown }).getReader === \"function\";\n}\n\n/**\n * Iterate a ReadableStream through a reader, cancelling the stream when iteration stops early.\n * @param stream - the stream\n * @param signal - the cancellation signal, or null\n * @yields the stream's chunks\n * @returns nothing\n */\nasync function* streamChunks(\n stream: ReadableStream<Uint8Array>,\n signal: AbortSignal | null,\n): AsyncGenerator<Uint8Array, void, undefined> {\n const reader = stream.getReader();\n let finished = false;\n try {\n for (;;) {\n throwIfAborted(signal);\n const { done, value } = await reader.read();\n if (done) {\n finished = true;\n return;\n }\n yield value;\n }\n } finally {\n if (!finished) {\n await reader.cancel(signal?.reason).catch(() => undefined);\n }\n reader.releaseLock();\n }\n}\n\n/**\n * Read the whole input as one string (the GML / DOT / JSON path, design section 8.4).\n * @param input - the input\n * @param report - the report the decode error is recorded in\n * @param options - cancellation and progress\n * @returns the decoded text without a leading BOM\n */\nexport async function readText(\n input: ImportInput,\n report: ImportReportBuilder,\n options: ReadOptions = {},\n): Promise<string> {\n if (typeof input === \"string\") {\n throwIfAborted(options.signal);\n options.onProgress?.(input.length, input.length);\n return input.startsWith(BOM) ? input.slice(1) : input;\n }\n const parts: string[] = [];\n for await (const chunk of textChunks(input, report, options)) {\n parts.push(chunk);\n }\n return parts.length === 1 ? parts[0] : parts.join(\"\");\n}\n\n/**\n * Lines of an ImportInput without allocating anything per line but the string itself: iterate with\n * `for await (const text of reader)` and read `reader.line` (1-based) for the line just yielded.\n * `\\n`, `\\r\\n` and lone `\\r` all end a line; the terminator is not part of the text; a final\n * line without a terminator is yielded when non-empty, and every line in between is yielded even\n * when empty (the importer decides what a blank line means).\n */\nexport class LineReader implements AsyncIterable<string> {\n private readonly input: ImportInput;\n\n private readonly report: ImportReportBuilder;\n\n private readonly options: ReadOptions;\n\n private lineNumber = 0;\n\n /**\n * Create a reader over an input; nothing is read until iteration starts.\n * @param input - the input\n * @param report - the report decode errors are recorded in\n * @param options - cancellation and progress\n */\n constructor(input: ImportInput, report: ImportReportBuilder, options: ReadOptions = {}) {\n this.input = input;\n this.report = report;\n this.options = options;\n }\n\n /**\n * The 1-based number of the line most recently yielded.\n * @returns the line number; 0 before the first line\n */\n get line(): number {\n return this.lineNumber;\n }\n\n /**\n * Iterate the lines.\n * @yields one line at a time, terminator removed\n * @returns nothing\n */\n async *[Symbol.asyncIterator](): AsyncGenerator<string, void, undefined> {\n // The pieces of the line in progress (none of them holds a line break, except that the last\n // may end with a `\\r` whose meaning the next chunk decides); joined once when the line ends,\n // so a line spanning many chunks costs its length, not its length times the chunk count.\n const pending: string[] = [];\n let trailingCr = false;\n for await (const chunk of textChunks(this.input, this.report, this.options)) {\n let start = 0;\n const end = chunk.length;\n if (trailingCr) {\n // the previous chunk ended with `\\r`: that ended a line, and a leading `\\n` here is\n // the second half of the same terminator\n trailingCr = false;\n this.lineNumber++;\n const joined = pending.join(\"\");\n pending.length = 0;\n yield joined.slice(0, -1);\n if (chunk.charCodeAt(0) === 10) {\n start = 1;\n }\n }\n // the next `\\n` and `\\r` at or after `start`; each is searched for once per chunk and\n // again only after it was consumed, so a chunk is scanned once whatever its line count\n let nl = chunk.indexOf(\"\\n\", start);\n let cr = chunk.indexOf(\"\\r\", start);\n while (nl >= 0 || cr >= 0) {\n let cut: number;\n let next: number;\n if (cr >= 0 && (nl < 0 || cr < nl)) {\n if (cr === end - 1) {\n // a trailing \\r may be the first half of \\r\\n split across chunks\n break;\n }\n cut = cr;\n next = chunk.charCodeAt(cr + 1) === 10 ? cr + 2 : cr + 1;\n } else {\n cut = nl;\n next = nl + 1;\n }\n this.lineNumber++;\n const piece = chunk.slice(start, cut);\n if (pending.length === 0) {\n yield piece;\n } else {\n pending.push(piece);\n const joined = pending.join(\"\");\n pending.length = 0;\n yield joined;\n }\n start = next;\n if (nl >= 0 && nl < next) {\n nl = chunk.indexOf(\"\\n\", next);\n }\n if (cr >= 0 && cr < next) {\n cr = chunk.indexOf(\"\\r\", next);\n }\n }\n if (start < end) {\n pending.push(start === 0 ? chunk : chunk.slice(start));\n trailingCr = chunk.charCodeAt(end - 1) === 13;\n }\n }\n if (pending.length > 0) {\n this.lineNumber++;\n const joined = pending.join(\"\");\n yield joined.endsWith(\"\\r\") ? joined.slice(0, -1) : joined;\n }\n }\n}\n","/**\n * Option normalisation for importers and exporters (design sections 8.4 and 8.5): every common\n * option resolved to its documented default, enum values checked (E_UNSUPPORTED, the core's\n * convention for an option outside its set), and the per-format defaults (`ids`, `defaultDirected`,\n * `weightFrom`, `addMissingNodes`) supplied by the importer that calls resolveImportOptions().\n */\n\nimport { type DuplicatePolicy, GraphFormatError, type GraphSink, type IdCoercion } from \"@graphty/graph-format\";\n\nimport { type CommonExportOptions, type CommonImportOptions, type GraphChoiceOptions } from \"../types.js\";\nimport {\n AMBIGUOUS_GRAPH_NAME_CODE,\n GRAPH_NOT_FOUND_CODE,\n NO_GRAPH_CODE,\n OPTION_IGNORED_CODE,\n SINK_OPTION_CODE,\n} from \"./codes.js\";\nimport { canonicalEncoding } from \"./input.js\";\nimport { type ImportReportBuilder } from \"./report.js\";\n\n/** The defaults an importer supplies for the options whose default is per format (design section 8.4). */\nexport interface ImportFormatDefaults {\n /** \"canonical\" for text-cell formats, \"keep\" for JSON. */\n readonly ids: IdCoercion;\n /** The direction assumed when the file declares none. */\n readonly defaultDirected: boolean;\n /** The attribute that becomes the weight (\"weight\", GML \"value\"), or null for an unweighted format. */\n readonly weightFrom: string | null;\n /** Whether edges may reference undeclared nodes; true unless the format says otherwise (GEXF: false). */\n readonly addMissingNodes?: boolean | undefined;\n}\n\n/**\n * CommonImportOptions with every field present (design section 8.4 defaults applied).\n * Consumed by the per-format importers and exporters under src/formats.\n * @public\n */\nexport interface ResolvedImportOptions {\n /** The id coercion rule. */\n readonly ids: IdCoercion;\n /** Which field becomes the node id. */\n readonly nodeIdFrom: \"id\" | \"label\" | \"index\";\n /** Whether an edge may reference an undeclared node. */\n readonly addMissingNodes: boolean;\n /** The builder's duplicate-edge policy seed. */\n readonly duplicateEdges: DuplicatePolicy;\n /** The builder's self-loop policy seed. */\n readonly selfLoops: \"keep\" | \"drop\" | \"error\";\n /** The mixed-direction policy. */\n readonly onMixedDirection: \"expand\" | \"directed\" | \"undirected\" | \"error\";\n /** The direction assumed when the file declares none. */\n readonly defaultDirected: boolean;\n /** The weight attribute, or null for unweighted. */\n readonly weightFrom: string | null;\n /** The weight staging precision. */\n readonly weightDtype: \"f32\" | \"f64\";\n /** How declared long columns are stored. */\n readonly long: \"f64\" | \"string\";\n /** Whether mangled ids are restored. */\n readonly restoreMangledIds: boolean;\n /** The hyperedge policy. */\n readonly hyperedges: \"error\" | \"skip\" | \"star\" | \"clique\";\n /** Errors tolerated before aborting. */\n readonly errorLimit: number;\n /** The cancellation signal, or null. */\n readonly signal: AbortSignal | null;\n /** The progress callback, or null. */\n readonly onProgress: ((bytesDone: number, bytesTotal?: number) => void) | null;\n /** The caller's byte encoding (canonical name), or null to detect it. */\n readonly encoding: string | null;\n}\n\n/** CommonExportOptions with every field present (design section 8.5 defaults applied). */\nexport interface ResolvedExportOptions {\n /** \"error\" never renames a node; \"mangle\" rewrites and keeps the original. */\n readonly sanitizeIds: \"error\" | \"mangle\";\n /** What a format without mixed-direction support does with a mixed snapshot. */\n readonly onMixedDirection: \"error\" | \"directed\" | \"undirected\";\n}\n\nconst ID_COERCIONS: ReadonlySet<string> = new Set([\"keep\", \"canonical\", \"string\", \"number\"]);\nconst NODE_ID_SOURCES: ReadonlySet<string> = new Set([\"id\", \"label\", \"index\"]);\nconst DUPLICATE_POLICIES: ReadonlySet<string> = new Set([\"keep\", \"error\", \"first\", \"last\", \"sum\", \"min\", \"max\"]);\nconst SELF_LOOP_POLICIES: ReadonlySet<string> = new Set([\"keep\", \"drop\", \"error\"]);\nconst IMPORT_MIXED_POLICIES: ReadonlySet<string> = new Set([\"expand\", \"directed\", \"undirected\", \"error\"]);\nconst EXPORT_MIXED_POLICIES: ReadonlySet<string> = new Set([\"error\", \"directed\", \"undirected\"]);\nconst WEIGHT_DTYPES: ReadonlySet<string> = new Set([\"f32\", \"f64\"]);\nconst LONG_MODES: ReadonlySet<string> = new Set([\"f64\", \"string\"]);\nconst HYPEREDGE_POLICIES: ReadonlySet<string> = new Set([\"error\", \"skip\", \"star\", \"clique\"]);\nconst SANITIZE_MODES: ReadonlySet<string> = new Set([\"error\", \"mangle\"]);\n\n/** The default error limit of design section 8.4. */\nexport const DEFAULT_ERROR_LIMIT = 100;\n\nexport { SINK_OPTION_CODE };\n\n/** The builder-policy options a sink exposes read-only as `sink.options` (design section 8.4). */\nconst SINK_OPTION_NAMES = [\"addMissingNodes\", \"duplicateEdges\", \"selfLoops\", \"weightDtype\"] as const;\n\n/**\n * Report every builder-policy option the caller explicitly requested that the sink does not use\n * (design section 8.4 precedence), one `W_SINK_OPTION` warning per option with the option name as\n * the element. Options left undefined are never reported: they are defaults, not requests. On the\n * registry's builder, which is seeded from the same options, nothing is ever reported.\n * @param sink - the sink the importer pushes into\n * @param options - the caller's raw options, possibly undefined\n * @param report - the report to record into\n * @param enforcesMissingNodes - true when the importer applies `addMissingNodes: false` itself (it\n * refuses unknown endpoints before the sink sees them), so that request is honoured on any sink and\n * only `addMissingNodes: true` against a refusing sink is reported\n * @returns the number of warnings recorded\n */\nexport function reportSinkOptions(\n sink: GraphSink,\n options: CommonImportOptions | undefined,\n report: ImportReportBuilder,\n enforcesMissingNodes = false,\n): number {\n if (options === undefined) {\n return 0;\n }\n let recorded = 0;\n for (const name of SINK_OPTION_NAMES) {\n const wanted: unknown = options[name];\n const actual: unknown = sink.options[name];\n if (wanted === undefined || wanted === actual) {\n continue;\n }\n if (name === \"addMissingNodes\" && enforcesMissingNodes && wanted === false) {\n continue;\n }\n report.warning(\n \"coercion\",\n SINK_OPTION_CODE,\n `option ${name}: ${JSON.stringify(wanted)} requested but the sink uses ${JSON.stringify(actual)}; the sink's setting applies`,\n { element: name },\n );\n recorded++;\n }\n return recorded;\n}\n\n/** The common options a format may leave unused; `signal`, `onProgress` and `errorLimit` apply everywhere. */\nconst IGNORABLE_OPTION_NAMES = [\n \"ids\",\n \"nodeIdFrom\",\n \"addMissingNodes\",\n \"duplicateEdges\",\n \"selfLoops\",\n \"onMixedDirection\",\n \"defaultDirected\",\n \"weightFrom\",\n \"weightDtype\",\n \"long\",\n \"restoreMangledIds\",\n \"hyperedges\",\n] as const;\n\n/**\n * Report every common option the caller set to a non-default value that the format has no use\n * for (design section 8.4: \"the importer reports every option it could not honour\"): one\n * `W_OPTION_IGNORED` warning (category `unsupported`) per option, the option name as the element.\n * The builder-policy options are reportSinkOptions()'s and are skipped here.\n * @param options - the caller's raw options, possibly undefined\n * @param report - the report to record into\n * @param used - the common option names the importer reads\n * @returns the number of warnings recorded\n */\nexport function reportUnusedOptions(\n options: CommonImportOptions | undefined,\n report: ImportReportBuilder,\n used: ReadonlySet<keyof CommonImportOptions>,\n): number {\n if (options === undefined) {\n return 0;\n }\n let recorded = 0;\n for (const name of IGNORABLE_OPTION_NAMES) {\n if (used.has(name) || (SINK_OPTION_NAMES as readonly string[]).includes(name)) {\n continue;\n }\n const value: unknown = options[name];\n if (value === undefined) {\n continue;\n }\n report.warning(\n \"unsupported\",\n OPTION_IGNORED_CODE,\n `option ${name}: ${JSON.stringify(value)} has no effect on the ${report.format} importer`,\n { element: name },\n );\n recorded++;\n }\n return recorded;\n}\n\n/**\n * The graph an importer reads from an input that holds several: the one `graphIndex` or\n * `graphName` names, else the first. A choice that names no graph is E_GRAPH_NOT_FOUND, a name two\n * graphs share is E_AMBIGUOUS_GRAPH_NAME, and an input with no graph at all is E_NO_GRAPH, each\n * fatal (the report fails with ImportError).\n * @param names - each graph's name (null for an unnamed graph), in document order\n * @param options - the caller's graphIndex / graphName\n * @param report - the report a failure is recorded in\n * @returns the index of the graph to read; E_UNSUPPORTED for an option of the wrong type, or both\n */\nexport function chooseGraph(\n names: readonly (string | null)[],\n options: GraphChoiceOptions | undefined,\n report: ImportReportBuilder,\n): number {\n const { graphIndex, graphName } = options ?? {};\n if (\n graphIndex !== undefined &&\n (typeof graphIndex !== \"number\" || !Number.isInteger(graphIndex) || graphIndex < 0)\n ) {\n throw new GraphFormatError(\n \"E_UNSUPPORTED\",\n `option graphIndex: ${describe(graphIndex)} is not a non-negative integer`,\n {\n option: \"graphIndex\",\n found: graphIndex,\n },\n );\n }\n if (graphName !== undefined && typeof graphName !== \"string\") {\n throw new GraphFormatError(\"E_UNSUPPORTED\", `option graphName: ${describe(graphName)} is not a string`, {\n option: \"graphName\",\n found: graphName,\n });\n }\n if (graphIndex !== undefined && graphName !== undefined) {\n throw new GraphFormatError(\"E_UNSUPPORTED\", \"options graphIndex and graphName both choose a graph; pass one\", {\n option: \"graphName\",\n found: graphName,\n });\n }\n if (names.length === 0) {\n return report.fail(NO_GRAPH_CODE, \"the input holds no graph\");\n }\n if (graphName !== undefined) {\n const matches = names.flatMap((name, i) => (name === graphName ? [i] : []));\n if (matches.length > 1) {\n return report.fail(\n AMBIGUOUS_GRAPH_NAME_CODE,\n `graphName ${JSON.stringify(graphName)} names the graphs at indexes ${matches.join(\", \")}; pass graphIndex`,\n { element: graphName },\n );\n }\n if (matches.length === 0) {\n return report.fail(\n GRAPH_NOT_FOUND_CODE,\n `graphName ${JSON.stringify(graphName)} names none of the ${names.length} graph(s)`,\n { element: graphName },\n { names: [...names] },\n );\n }\n return matches[0];\n }\n const index = graphIndex ?? 0;\n if (index >= names.length) {\n return report.fail(GRAPH_NOT_FOUND_CODE, `graphIndex ${index} is beyond the ${names.length} graph(s)`);\n }\n return index;\n}\n\n/**\n * Apply the design section 8.4 defaults to an importer's common options and check every enum\n * value. Format-specific options in the same object are ignored here.\n * @param options - the caller's options, possibly undefined\n * @param defaults - the importer's per-format defaults\n * @returns the resolved options; E_UNSUPPORTED for a value outside its set\n */\nexport function resolveImportOptions(\n options: CommonImportOptions | undefined,\n defaults: ImportFormatDefaults,\n): ResolvedImportOptions {\n const o: CommonImportOptions = options ?? {};\n return Object.freeze({\n ids: enumOption(\"ids\", o.ids, defaults.ids, ID_COERCIONS),\n nodeIdFrom: enumOption(\"nodeIdFrom\", o.nodeIdFrom, \"id\", NODE_ID_SOURCES),\n addMissingNodes: booleanOption(\"addMissingNodes\", o.addMissingNodes, defaults.addMissingNodes ?? true),\n duplicateEdges: enumOption(\"duplicateEdges\", o.duplicateEdges, \"keep\", DUPLICATE_POLICIES),\n selfLoops: enumOption(\"selfLoops\", o.selfLoops, \"keep\", SELF_LOOP_POLICIES),\n onMixedDirection: enumOption(\"onMixedDirection\", o.onMixedDirection, \"expand\", IMPORT_MIXED_POLICIES),\n defaultDirected: booleanOption(\"defaultDirected\", o.defaultDirected, defaults.defaultDirected),\n weightFrom: weightFromOption(o.weightFrom, defaults.weightFrom),\n weightDtype: enumOption(\"weightDtype\", o.weightDtype, \"f64\", WEIGHT_DTYPES),\n long: enumOption(\"long\", o.long, \"f64\", LONG_MODES),\n restoreMangledIds: booleanOption(\"restoreMangledIds\", o.restoreMangledIds, true),\n hyperedges: enumOption(\"hyperedges\", o.hyperedges, \"skip\", HYPEREDGE_POLICIES),\n errorLimit: errorLimitOption(o.errorLimit),\n signal: signalOption(o.signal),\n onProgress: progressOption(o.onProgress),\n encoding: encodingOption(o.encoding),\n });\n}\n\n/**\n * Apply the design section 8.5 defaults to an exporter's common options and check the enum values.\n * @param options - the caller's options, possibly undefined\n * @returns the resolved options; E_UNSUPPORTED for a value outside its set\n */\nexport function resolveExportOptions(options: CommonExportOptions | undefined): ResolvedExportOptions {\n const o: CommonExportOptions = options ?? {};\n return Object.freeze({\n sanitizeIds: enumOption(\"sanitizeIds\", o.sanitizeIds, \"error\", SANITIZE_MODES),\n onMixedDirection: enumOption(\"onMixedDirection\", o.onMixedDirection, \"error\", EXPORT_MIXED_POLICIES),\n });\n}\n\n/**\n * Resolve one enum-valued option.\n * @param name - the option name, for the error\n * @param value - the caller's value\n * @param fallback - the default\n * @param allowed - the accepted values\n * @returns the value or the default; E_UNSUPPORTED when outside the set\n */\nfunction enumOption<T extends string>(name: string, value: unknown, fallback: T, allowed: ReadonlySet<string>): T {\n if (value === undefined) {\n return fallback;\n }\n if (typeof value !== \"string\" || !allowed.has(value)) {\n throw new GraphFormatError(\n \"E_UNSUPPORTED\",\n `option ${name}: ${describe(value)} is not one of ${list(allowed)}`,\n {\n option: name,\n found: value,\n supported: [...allowed],\n },\n );\n }\n return value as T;\n}\n\n/**\n * Resolve one boolean option.\n * @param name - the option name, for the error\n * @param value - the caller's value\n * @param fallback - the default\n * @returns the value or the default; E_UNSUPPORTED when not a boolean\n */\nfunction booleanOption(name: string, value: unknown, fallback: boolean): boolean {\n if (value === undefined) {\n return fallback;\n }\n if (typeof value !== \"boolean\") {\n throw new GraphFormatError(\"E_UNSUPPORTED\", `option ${name}: ${describe(value)} is not a boolean`, {\n option: name,\n found: value,\n });\n }\n return value;\n}\n\n/**\n * Resolve the weightFrom option: a non-empty attribute name, null for unweighted, or the format default.\n * @param value - the caller's value\n * @param fallback - the format default\n * @returns the resolved value; E_UNSUPPORTED for anything else\n */\nfunction weightFromOption(value: unknown, fallback: string | null): string | null {\n if (value === undefined) {\n return fallback;\n }\n if (value === null || (typeof value === \"string\" && value.length > 0)) {\n return value;\n }\n throw new GraphFormatError(\n \"E_UNSUPPORTED\",\n `option weightFrom: ${describe(value)} is not an attribute name or null`,\n { option: \"weightFrom\", found: value },\n );\n}\n\n/**\n * Resolve the error limit: a non-negative integer or Infinity.\n * @param value - the caller's value\n * @returns the limit or the default\n */\nfunction errorLimitOption(value: unknown): number {\n if (value === undefined) {\n return DEFAULT_ERROR_LIMIT;\n }\n if (typeof value === \"number\" && value >= 0 && (Number.isInteger(value) || value === Infinity)) {\n return value;\n }\n throw new GraphFormatError(\n \"E_UNSUPPORTED\",\n `option errorLimit: ${describe(value)} is not a non-negative integer or Infinity`,\n { option: \"errorLimit\", found: value },\n );\n}\n\n/**\n * Resolve the signal option by duck type, so a signal from another realm is accepted.\n * @param value - the caller's value\n * @returns the signal or null\n */\nfunction signalOption(value: unknown): AbortSignal | null {\n if (value === undefined || value === null) {\n return null;\n }\n if (typeof value === \"object\" && typeof (value as { aborted?: unknown }).aborted === \"boolean\") {\n return value as AbortSignal;\n }\n throw new GraphFormatError(\"E_UNSUPPORTED\", `option signal: ${describe(value)} is not an AbortSignal`, {\n option: \"signal\",\n found: typeof value,\n });\n}\n\n/**\n * Resolve the progress callback option.\n * @param value - the caller's value\n * @returns the callback or null\n */\nfunction progressOption(value: unknown): ((bytesDone: number, bytesTotal?: number) => void) | null {\n if (value === undefined || value === null) {\n return null;\n }\n if (typeof value === \"function\") {\n return value as (bytesDone: number, bytesTotal?: number) => void;\n }\n throw new GraphFormatError(\"E_UNSUPPORTED\", `option onProgress: ${describe(value)} is not a function`, {\n option: \"onProgress\",\n found: typeof value,\n });\n}\n\n/**\n * Resolve the encoding option: a label the platform's TextDecoder knows.\n * @param value - the caller's value\n * @returns the canonical encoding name, or null for detection\n */\nfunction encodingOption(value: unknown): string | null {\n if (value === undefined || value === null) {\n return null;\n }\n const canonical = typeof value === \"string\" ? canonicalEncoding(value) : null;\n if (canonical === null) {\n throw new GraphFormatError(\n \"E_UNSUPPORTED\",\n `option encoding: ${describe(value)} is not an encoding this platform's TextDecoder knows`,\n { option: \"encoding\", found: value },\n );\n }\n return canonical;\n}\n\n/**\n * A short description of an option value for an error message.\n * @param value - the value\n * @returns the JSON text of a primitive, or the type name otherwise\n */\nfunction describe(value: unknown): string {\n switch (typeof value) {\n case \"string\":\n return JSON.stringify(value);\n case \"number\":\n case \"boolean\":\n return String(value);\n default:\n return value === null ? \"null\" : typeof value;\n }\n}\n\n/**\n * The accepted values of an enum option, for an error message.\n * @param allowed - the set\n * @returns the quoted values joined by commas\n */\nfunction list(allowed: ReadonlySet<string>): string {\n return [...allowed].map((v) => JSON.stringify(v)).join(\", \");\n}\n","/**\n * The io contract types of @graphty/graph-io (design section 12.4, normative): what every importer\n * and exporter implements and what every caller of one programs against. They are declared here\n * rather than in the core because ImportInput and CommonImportOptions reference ReadableStream and\n * AbortSignal, which need the DOM lib (or @types/node >= 18); the core's public types reference only\n * ES2020 globals (decision D-IO-TYPES). Every declaration is transcribed verbatim from the design;\n * the behaviour behind each option is specified in sections 8.4 (import), 8.5 (export) and 8.6\n * (report and error aggregation).\n */\n\nimport {\n type Dtype,\n type DuplicatePolicy,\n GraphFormatError,\n type GraphSink,\n type GraphSnapshot,\n type IdCoercion,\n} from \"@graphty/graph-format\";\n\n/**\n * What an importer reads (design section 8.4): whole text, whole bytes, a byte stream (a browser\n * `File.stream()`, a fetch body) or an async iterable of text or byte chunks. Bytes are decoded\n * strictly in the encoding the `encoding` option, a byte order mark or the file's own declaration\n * names, else as UTF-8 (undeclared bytes that are not UTF-8 are read as windows-1252 with a\n * warning), so an invalid sequence is a parse-error and never a silent U+FFFD that could alias two ids.\n */\nexport type ImportInput = string | Uint8Array | ReadableStream<Uint8Array> | AsyncIterable<string | Uint8Array>;\n\n/**\n * The options every importer accepts next to its format-specific ones (design section 8.4). The\n * builder-policy fields (`addMissingNodes`, `duplicateEdges`, `selfLoops`, `weightDtype`) seed the\n * registry's builder; on a caller's sink they are read back from `sink.options` and every option the\n * sink cannot honour is reported.\n */\nexport interface CommonImportOptions {\n /**\n * Id coercion rule applied before an id reaches the sink (design section 4.1): \"canonical\" by default for\n * text-cell formats, \"keep\" for JSON.\n */\n ids?: IdCoercion | undefined;\n /** Which field becomes the node id; \"id\" by default; \"label\" / \"index\" resolve the GML / Pajek / d3 ambiguity. */\n nodeIdFrom?: \"id\" | \"label\" | \"index\" | undefined;\n /** Whether an edge may reference an undeclared node (default true; the GEXF importer defaults false for edges). */\n addMissingNodes?: boolean | undefined;\n /** The builder's duplicate-edge policy seed; default \"keep\". */\n duplicateEdges?: DuplicatePolicy | undefined;\n /** The builder's self-loop policy seed; default \"keep\". */\n selfLoops?: \"keep\" | \"drop\" | \"error\" | undefined;\n /** What to do with a file whose edges disagree on direction (design section 3.6); default \"expand\". */\n onMixedDirection?: \"expand\" | \"directed\" | \"undirected\" | \"error\" | undefined;\n /** The direction assumed for a file that declares none (GEXF: undirected per spec). */\n defaultDirected?: boolean | undefined;\n /** The attribute that becomes THE weight (per-format default: \"weight\", GML \"value\"); null = unweighted. */\n weightFrom?: string | null | undefined;\n /** Weight staging precision; \"f64\" for every importer by default so 0.1 and 16777217 survive. */\n weightDtype?: \"f32\" | \"f64\" | undefined;\n /** How a declared `long` column is stored: \"f64\" (default) or \"string\" (design section 5.1). */\n long?: \"f64\" | \"string\" | undefined;\n /** Restore ids mangled by sanitizeIds \"mangle\" from the graphty:originalId attribute (default true). */\n restoreMangledIds?: boolean | undefined;\n /** GraphML / JGF hyperedges: refuse, skip with a report entry (default), or expand to a star / clique. */\n hyperedges?: \"error\" | \"skip\" | \"star\" | \"clique\" | undefined;\n /** Errors tolerated before the importer aborts with E_IMPORT (default 100). */\n errorLimit?: number | undefined;\n /** Cancellation; the importer stops between chunks and rejects with the signal's reason. */\n signal?: AbortSignal | undefined;\n /** Progress in bytes; `bytesTotal` is known for in-memory input only. */\n onProgress?: ((bytesDone: number, bytesTotal?: number) => void) | undefined;\n /**\n * The character encoding of byte input (a WHATWG label such as \"utf-8\", \"windows-1252\",\n * \"iso-8859-1\", \"utf-16le\"); overrides the byte order mark and any encoding the file declares.\n * Absent: a BOM decides, else the declaration (XML prolog, DOT `charset`), else UTF-8, and\n * bytes that are not valid UTF-8 are read as windows-1252 with a warning. Ignored for text input.\n */\n encoding?: string | undefined;\n}\n\n/**\n * Which graph of an input that holds several to read: by position or by name, never both. An\n * importer of a format that can hold several graphs (a Cytoscape session, a CX collection, a JGF\n * or OBO Graphs `graphs` array) accepts these next to its own options; absent, it reads the first.\n */\nexport interface GraphChoiceOptions {\n /** The 0-based position of the graph, as `GraphListing.index` gives it. */\n graphIndex?: number | undefined;\n /** The name of the graph, as `GraphListing.name` gives it; a name two graphs share is refused. */\n graphName?: string | undefined;\n}\n\n/** One graph of an input that can hold several, as an importer's listGraphs() describes it. */\nexport interface GraphListing {\n /** The value graphIndex takes to read it. */\n readonly index: number;\n /** The value graphName takes to read it, or null when the graph has no name. */\n readonly name: string | null;\n /** The node count when the input states it cheaply, else null. */\n readonly nodes: number | null;\n /** The edge count when the input states it cheaply, else null. */\n readonly edges: number | null;\n}\n\n/**\n * An importer plugin (design section 8.4): pushes scalars into the caller's sink in one pass and\n * never freezes. `Opts` is its format-specific option set; the default `unknown` lets a caller pass\n * the common options to an importer typed without one.\n */\nexport interface GraphImporter<Opts = unknown> {\n /** The format name: \"gexf\", \"graphml\", \"gml\", \"dot\", \"pajek\", \"csv\", \"json\", \"neo4j\". */\n readonly format: string;\n /** File extensions with the leading dot. */\n readonly extensions: readonly string[];\n /** MIME types the format is served as. */\n readonly mimeTypes: readonly string[];\n /**\n * Confidence that `head` is this format, for the registry's sniff().\n * @param head - the first bytes of the input\n * @returns a confidence in 0..1\n */\n sniff?(head: Uint8Array): number;\n /**\n * Read `input` into `sink`; per-element errors are aggregated into the report until the error\n * limit, then the importer throws ImportError with the partial report.\n * @param input - the text, bytes or stream to read\n * @param sink - the builder (or a recording sink) to push into\n * @param options - format-specific and common options\n * @returns the import report\n */\n import(input: ImportInput, sink: GraphSink, options?: Opts & CommonImportOptions): Promise<ImportReport>;\n /**\n * Read every graph of an input that can hold several (a DOT file with several graphs, a\n * Pajek project with several networks, a JGF `graphs` array), each into its own sink. An\n * importer without this method reads one graph per input. `import()` reads the first graph\n * and warns how many it skipped.\n * @param input - the text, bytes or stream to read\n * @param sinkFor - called once per graph, in document order, before that graph's first push\n * @param options - format-specific and common options\n * @returns one report per graph, in document order\n */\n importAll?(\n input: ImportInput,\n sinkFor: (index: number) => GraphSink,\n options?: Opts & CommonImportOptions,\n ): Promise<ImportReport[]>;\n /**\n * List the graphs of an input that can hold several without importing them, so a caller can\n * offer a choice before reading one with `graphIndex` or `graphName`. An importer without this\n * method does not list its graphs; `import()` reads the first.\n * @param input - the text, bytes or stream to read\n * @param options - format-specific and common options\n * @returns one listing per graph, in document order\n */\n listGraphs?(input: ImportInput, options?: Opts & CommonImportOptions): Promise<readonly GraphListing[]>;\n}\n\n/**\n * What a format can express without loss (design section 8.5): the fidelity matrix of research\n * note 07 section 9 as a table, and the acceptance test list for check().\n */\nexport interface ExportCapabilities {\n /** Directed and undirected edges in one file. */\n readonly mixedDirection: boolean;\n /** Parallel edges. */\n readonly multiEdges: boolean;\n /** Self-loops. */\n readonly selfLoops: boolean;\n /** Whether edge ids are required (generated when absent), optional or unsupported. */\n readonly edgeIds: \"required\" | \"optional\" | \"none\";\n /** Which node ids can be written unchanged. */\n readonly idCharset: \"any\" | \"nmtoken\" | \"integer\" | \"dense-1-based\";\n /** The column dtypes the format keeps as declared. */\n readonly dtypes: readonly Dtype[];\n /** Multi-component (stride) columns. */\n readonly components: boolean;\n /** List columns. */\n readonly lists: boolean;\n /** Nested json columns. */\n readonly json: boolean;\n /** Declared defaults. */\n readonly defaults: boolean;\n /** Declared enumerations (GEXF options). */\n readonly options: boolean;\n /** Containment (parent / parents roles). */\n readonly hierarchy: boolean;\n /** Temporal support level. */\n readonly temporal: \"none\" | \"intervals\" | \"spells\" | \"dynamic-values\";\n /** Graph-level attributes. */\n readonly graphAttributes: boolean;\n /** The position role. */\n readonly positions: boolean;\n /** The visual roles (color, size, shape, thickness). */\n readonly viz: boolean;\n}\n\n/** One thing an exporter cannot represent, reported by check() before anything is written (design section 8.5). */\nexport interface LossNote {\n /** A stable code such as \"W_OPEN_INTERVAL\". */\n readonly code: string;\n /** A plain-ASCII human-readable explanation. */\n readonly message: string;\n /** The affected column, or null when the note is not about a column. */\n readonly column: string | null;\n /** How many rows or elements are affected, or null when not counted. */\n readonly count: number | null;\n}\n\n/** The options every exporter accepts next to its format-specific ones (design section 8.5). */\nexport interface CommonExportOptions {\n /** \"error\" (default): never rename a node; \"mangle\": rewrite ids the format cannot hold and keep the original. */\n sanitizeIds?: \"error\" | \"mangle\" | undefined;\n /** For formats without mixed-direction support: refuse (default) or write every edge one way. */\n onMixedDirection?: \"error\" | \"directed\" | \"undirected\" | undefined;\n}\n\n/**\n * An exporter plugin (design section 8.5): iterates nodes and logical edges (never arcs) in index\n * order and reads the role columns of section 3.6 / 3.7 to fold expanded pairs and emit explicit\n * weights only.\n */\nexport interface GraphExporter<Opts = unknown> {\n /** The format name. */\n readonly format: string;\n /** What the format can express. */\n readonly capabilities: ExportCapabilities;\n /**\n * Pre-flight: what export() would lose, without writing anything.\n * @param snapshot - the snapshot to check\n * @param options - format-specific and common options\n * @returns the loss notes, empty when the export is exact\n */\n check(snapshot: GraphSnapshot, options?: Opts & CommonExportOptions): readonly LossNote[];\n /**\n * Write the snapshot as UTF-8 chunks.\n * @param snapshot - the snapshot to write\n * @param options - format-specific and common options\n * @returns the encoded chunks\n */\n export(snapshot: GraphSnapshot, options?: Opts & CommonExportOptions): AsyncIterable<Uint8Array>;\n /**\n * Write the snapshot as one string.\n * @param snapshot - the snapshot to write\n * @param options - format-specific and common options\n * @returns the whole document\n */\n exportToString(snapshot: GraphSnapshot, options?: Opts & CommonExportOptions): Promise<string>;\n}\n\n/** The categories of an ImportIssue (design section 8.6). */\nexport type IssueCategory =\n | \"parse-error\"\n | \"missing-value\"\n | \"validation-error\"\n | \"unsupported\"\n | \"precision\"\n | \"coercion\"\n | \"merged\";\n\n/** One problem found while importing (design section 8.6). */\nexport interface ImportIssue {\n /** The category. */\n readonly category: IssueCategory;\n /** Errors count toward the error limit; warnings do not. */\n readonly severity: \"error\" | \"warning\";\n /** A stable code such as \"E_UNKNOWN_NODE\" or \"W_WIDENED\". */\n readonly code: string;\n /** A plain-ASCII human-readable message. */\n readonly message: string;\n /** The 1-based source line, or null when unknown. */\n readonly line: number | null;\n /** The element (a node or edge id, an attribute name), or null when unknown. */\n readonly element: string | null;\n}\n\n/** What an import produced besides the sink's contents (design section 8.6). */\nexport interface ImportReport {\n /** The importer's format name. */\n readonly format: string;\n /** Element counts. */\n readonly counts: {\n /** Nodes pushed. */\n readonly nodes: number;\n /** Logical edges pushed (both halves of an expanded edge count). */\n readonly edges: number;\n /** Nodes skipped after an error. */\n readonly skippedNodes: number;\n /** Edges skipped after an error. */\n readonly skippedEdges: number;\n /** Edges expanded under onMixedDirection \"expand\" (design section 3.6). */\n readonly expandedMixed: number;\n };\n /** Every issue recorded, in order. */\n readonly issues: readonly ImportIssue[];\n /** Issues with severity \"error\". */\n readonly errorCount: number;\n /** Issues with severity \"warning\". */\n readonly warningCount: number;\n /** Whether the error limit was reached and the import aborted. */\n readonly truncated: boolean;\n /** What the importer could not represent. */\n readonly lossy: readonly LossNote[];\n /** Wall time of the parse phase; the caller's freeze reports separately. */\n readonly durationMs: number;\n}\n\n/**\n * The error an importer throws when the error limit is reached or the input cannot be read at all\n * (design section 8.6): a GraphFormatError with code \"E_IMPORT\" (reserved in the core's union so\n * `err.code === \"E_IMPORT\"` narrows) carrying the partial report.\n */\nexport class ImportError extends GraphFormatError {\n /** The report as it stood when the import aborted. */\n readonly report: ImportReport;\n\n /**\n * Create an ImportError.\n * @param message - a plain-ASCII human-readable message\n * @param report - the partial report\n * @param details - optional machine-readable context\n */\n constructor(message: string, report: ImportReport, details?: Readonly<Record<string, unknown>>) {\n super(\"E_IMPORT\", message, details);\n this.name = \"ImportError\";\n this.report = report;\n }\n}\n","/**\n * The ImportReport builder shared by every importer (design section 8.6): issues by category and\n * severity, the element counts, loss notes, the error limit with truncation, and the ImportError\n * that carries the partial report when the importer aborts.\n *\n * Layering (design section 8.6): the builder throws on the first hard error; the importer catches\n * per element, records an ImportIssue through this class, skips the element and continues until the\n * error limit, then aborts with E_IMPORT. `recordError()` is that catch: it turns a thrown\n * GraphFormatError into an issue with the category its code implies and re-throws everything else\n * (an ImportError, an abort reason, a programming error) unchanged.\n */\n\nimport { GraphFormatError, type GraphFormatErrorCode } from \"@graphty/graph-format\";\n\nimport { ImportError, type ImportIssue, type ImportReport, type IssueCategory, type LossNote } from \"../types.js\";\n\n/**\n * Where an issue was found: the 1-based line and the element (id or attribute name) when known.\n * Consumed by the per-format importers and exporters under src/formats.\n * @public\n */\nexport interface IssueLocation {\n /** The 1-based source line, when known. */\n readonly line?: number | null | undefined;\n /** The element the issue is about, when known. */\n readonly element?: string | null | undefined;\n}\n\n/**\n * The mutable element counters of a report in progress; importers increment them directly in hot loops.\n * Consumed by the per-format importers and exporters under src/formats.\n * @public\n */\nexport interface MutableCounts {\n /** Nodes pushed. */\n nodes: number;\n /** Logical edges pushed (both halves of an expanded edge count). */\n edges: number;\n /** Nodes skipped after an error. */\n skippedNodes: number;\n /** Edges skipped after an error. */\n skippedEdges: number;\n /** Source edges expanded into two logical edges (design section 3.6). */\n expandedMixed: number;\n}\n\n/**\n * The category a thrown GraphFormatError maps to when an importer catches it per element: the codes\n * that mean \"the file referenced something it never declared\" are missing values, a refused\n * direction change is a coercion, size and feature limits are unsupported, everything else is a\n * validation error of the element.\n */\nconst CATEGORY_BY_CODE: Readonly<Partial<Record<GraphFormatErrorCode, IssueCategory>>> = {\n E_UNKNOWN_NODE: \"missing-value\",\n E_UNKNOWN_COLUMN: \"missing-value\",\n E_DIRECTED: \"coercion\",\n E_TOO_LARGE: \"unsupported\",\n E_UNSUPPORTED: \"unsupported\",\n E_GPU_INELIGIBLE: \"unsupported\",\n};\n\n/**\n * The code a report used to give a thrown value that was not a GraphFormatError. Since audit round\n * 1 such a value (a TypeError, a RangeError: a bug in an importer or a sink, never a defect of the\n * input) propagates out of import() untouched, so no importer records this code any more; the\n * constant stays for consumers that switch on the codes of earlier reports.\n */\nexport const PARSE_ERROR_CODE = \"E_PARSE\";\n\n/**\n * Accumulates an ImportReport while an importer runs. Errors count toward the error limit; the\n * error that takes the count beyond the limit is still recorded, `truncated` is set, and an\n * ImportError carrying the report so far is thrown (design section 8.4: \"beyond it the importer\n * aborts with E_IMPORT\"). Warnings never abort.\n */\nexport class ImportReportBuilder {\n /** The importer's format name. */\n readonly format: string;\n\n /** The error limit the report was created with. */\n readonly errorLimit: number;\n\n /** The element counters; importers increment them directly. */\n readonly counts: MutableCounts = { nodes: 0, edges: 0, skippedNodes: 0, skippedEdges: 0, expandedMixed: 0 };\n\n private readonly issueList: ImportIssue[] = [];\n\n private readonly lossList: LossNote[] = [];\n\n private readonly onceCodes = new Set<string>();\n\n private errors = 0;\n\n private warnings = 0;\n\n private truncatedFlag = false;\n\n private readonly startedAt: number;\n\n /**\n * Create a builder for one import call.\n * @param format - the importer's format name\n * @param errorLimit - errors tolerated before the import aborts; Infinity for no limit\n */\n constructor(format: string, errorLimit: number) {\n this.format = format;\n this.errorLimit = errorLimit;\n this.startedAt = now();\n }\n\n /**\n * Issues recorded so far, in order.\n * @returns the live list (not copied; finish() copies)\n */\n get issues(): readonly ImportIssue[] {\n return this.issueList;\n }\n\n /**\n * Issues with severity \"error\".\n * @returns the count\n */\n get errorCount(): number {\n return this.errors;\n }\n\n /**\n * Issues with severity \"warning\".\n * @returns the count\n */\n get warningCount(): number {\n return this.warnings;\n }\n\n /**\n * Whether the error limit was exceeded.\n * @returns true once an error beyond the limit was recorded\n */\n get truncated(): boolean {\n return this.truncatedFlag;\n }\n\n /**\n * Loss notes recorded so far.\n * @returns the live list\n */\n get lossy(): readonly LossNote[] {\n return this.lossList;\n }\n\n /**\n * Record an error. When the count goes beyond the error limit the report is marked truncated\n * and an ImportError carrying it is thrown; the importer does not catch that.\n * @param category - the issue category\n * @param code - a stable code such as \"E_UNKNOWN_NODE\"\n * @param message - a plain-ASCII message\n * @param where - the line and element, when known\n * @returns the recorded issue\n */\n error(category: IssueCategory, code: string, message: string, where?: IssueLocation): ImportIssue {\n const issue = makeIssue(category, \"error\", code, message, where);\n this.issueList.push(issue);\n this.errors++;\n if (this.errors > this.errorLimit) {\n this.truncatedFlag = true;\n throw this.abort(`error limit of ${this.errorLimit} exceeded: ${message}`, {\n code,\n limit: this.errorLimit,\n });\n }\n return issue;\n }\n\n /**\n * Record a warning; warnings never count toward the limit.\n * @param category - the issue category\n * @param code - a stable code such as \"W_WIDENED\"\n * @param message - a plain-ASCII message\n * @param where - the line and element, when known\n * @returns the recorded issue\n */\n warning(category: IssueCategory, code: string, message: string, where?: IssueLocation): ImportIssue {\n const issue = makeIssue(category, \"warning\", code, message, where);\n this.issueList.push(issue);\n this.warnings++;\n return issue;\n }\n\n /**\n * Record a warning the first time its key is seen and ignore later repeats, for conditions\n * that would otherwise produce one warning per row.\n * @param category - the issue category\n * @param code - the stable code\n * @param message - a plain-ASCII message\n * @param where - the line and element, when known\n * @param key - what repeats are deduplicated on; the code itself by default (pass `code:column`\n * to warn once per column)\n * @returns the recorded issue, or null when the key was already recorded\n */\n warnOnce(\n category: IssueCategory,\n code: string,\n message: string,\n where?: IssueLocation,\n key: string = code,\n ): ImportIssue | null {\n if (this.onceCodes.has(key)) {\n return null;\n }\n this.onceCodes.add(key);\n return this.warning(category, code, message, where);\n }\n\n /**\n * Record something the importer could not represent.\n * @param code - a stable code\n * @param message - a plain-ASCII message\n * @param column - the affected column, or null\n * @param count - the affected count, or null\n * @returns the recorded note\n */\n loss(code: string, message: string, column: string | null = null, count: number | null = null): LossNote {\n const note: LossNote = Object.freeze({ code, message, column, count });\n this.lossList.push(note);\n return note;\n }\n\n /**\n * The per-element catch of design section 8.6: record a thrown GraphFormatError as an error\n * issue with its code and the category the code implies. Anything else is re-thrown unchanged:\n * an ImportError (the import already aborted), an abort reason, and any other thrown value (a\n * TypeError or RangeError is a programming error in the importer or the sink, never a defect of\n * the input, so it must surface as an exception rather than as an issue blamed on the file).\n * @param err - the thrown value\n * @param where - the line and element, when known\n * @returns the recorded issue\n */\n recordError(err: unknown, where?: IssueLocation): ImportIssue {\n if (err instanceof GraphFormatError && !(err instanceof ImportError)) {\n const category = CATEGORY_BY_CODE[err.code] ?? \"validation-error\";\n return this.error(category, err.code, err.message, where);\n }\n throw err;\n }\n\n /**\n * Build the ImportError that aborts the import, carrying the report so far. The caller throws\n * it; this method only constructs it so it can be used in expression position.\n * @param message - a plain-ASCII message\n * @param details - optional machine-readable context\n * @returns the error to throw\n */\n abort(message: string, details?: Readonly<Record<string, unknown>>): ImportError {\n return new ImportError(message, this.finish(), details);\n }\n\n /**\n * Record a fatal parse error and abort: the issue is recorded (even beyond the error limit)\n * and an ImportError carrying the report is thrown.\n * @param code - a stable code such as \"E_INVALID_UTF8\"\n * @param message - a plain-ASCII message\n * @param where - the line and element, when known\n * @param details - optional machine-readable context for the ImportError\n */\n fail(code: string, message: string, where?: IssueLocation, details?: Readonly<Record<string, unknown>>): never {\n const issue = makeIssue(\"parse-error\", \"error\", code, message, where);\n this.issueList.push(issue);\n this.errors++;\n if (this.errors > this.errorLimit) {\n this.truncatedFlag = true;\n }\n throw this.abort(message, { code, ...details });\n }\n\n /**\n * The report as it stands: a frozen snapshot with the parse duration so far. Can be called more\n * than once; each call reflects everything recorded up to that point.\n * @returns the report\n */\n finish(): ImportReport {\n const { nodes, edges, skippedNodes, skippedEdges, expandedMixed } = this.counts;\n return Object.freeze({\n format: this.format,\n counts: Object.freeze({ nodes, edges, skippedNodes, skippedEdges, expandedMixed }),\n issues: Object.freeze([...this.issueList]),\n errorCount: this.errors,\n warningCount: this.warnings,\n truncated: this.truncatedFlag,\n lossy: Object.freeze([...this.lossList]),\n durationMs: now() - this.startedAt,\n });\n }\n}\n\n/**\n * Build a frozen ImportIssue.\n * @param category - the category\n * @param severity - error or warning\n * @param code - the stable code\n * @param message - the message\n * @param where - the location, when known\n * @returns the issue\n */\nfunction makeIssue(\n category: IssueCategory,\n severity: \"error\" | \"warning\",\n code: string,\n message: string,\n where: IssueLocation | undefined,\n): ImportIssue {\n return Object.freeze({\n category,\n severity,\n code,\n message,\n line: where?.line ?? null,\n element: where?.element ?? null,\n });\n}\n\n/**\n * Whether a thrown value is an abort reason (the DOMException or Error named \"AbortError\" that\n * AbortSignal.reason holds), which an importer must let through untouched.\n * @param err - the thrown value\n * @returns true for an AbortError\n */\nexport function isAbortError(err: unknown): boolean {\n return typeof err === \"object\" && err !== null && (err as { name?: unknown }).name === \"AbortError\";\n}\n\n/**\n * The message of a thrown value: an Error's message, a string as is, anything else described by type.\n * @param err - the thrown value\n * @returns a plain message\n */\nexport function messageOf(err: unknown): string {\n if (err instanceof Error) {\n return err.message;\n }\n if (typeof err === \"string\") {\n return err;\n }\n return `non-error thrown (${typeof err})`;\n}\n\n/**\n * A monotonic millisecond clock: performance.now() where it exists, Date.now() otherwise.\n * @returns milliseconds\n */\nfunction now(): number {\n return typeof performance === \"object\" ? performance.now() : Date.now();\n}\n","/**\n * Number formatting for exporters (design section 3.7): an f32 weight is written as the shortest\n * decimal that round-trips through Math.fround (never `String(x)`, which prints\n * 0.10000000149011612 for a stored 0.1); an f64 value as its shortest JS text; a GML real always\n * with a decimal point so the dtype survives (design section 8.5); non-finite values as the\n * spelling the target syntax accepts.\n */\n\n/**\n * The shortest decimal text that reads back to the same f32 value through Math.fround.\n * @param value - an f32 value (a JS number holding one)\n * @returns the text; \"Infinity\" / \"-Infinity\" / \"NaN\" for the non-finite values, \"-0\" for negative zero\n */\nexport function formatF32(value: number): string {\n if (!Number.isFinite(value)) {\n return String(value);\n }\n if (value === 0) {\n return Object.is(value, -0) ? \"-0\" : \"0\";\n }\n for (let digits = 1; digits <= 9; digits++) {\n const text = value.toPrecision(digits);\n if (Math.fround(Number(text)) === value) {\n return String(Number(text));\n }\n }\n return String(value);\n}\n\n/**\n * The shortest text of an f64 value: `String(x)`, which is already the shortest round-tripping\n * decimal in JS, except for negative zero, which `String()` writes as \"0\".\n * @param value - the value\n * @returns the text; \"Infinity\" / \"-Infinity\" / \"NaN\" for the non-finite values, \"-0\" for negative zero\n */\nexport function formatF64(value: number): string {\n return Object.is(value, -0) ? \"-0\" : String(value);\n}\n\n/**\n * A decimal text with a decimal point or an exponent guaranteed for a finite value (`2.0`,\n * `1e+21`, `1.5e-7`), so an\n * untyped re-import keeps the column f64 rather than i32 (design section 8.5); negative zero is\n * written `-0.0` so it reads back as -0; non-finite values are the JS spellings (`Infinity`,\n * `-Infinity`, `NaN`), which the CSV / DOT / Pajek importers read back as text. The one\n * implementation of the \"decimal point guaranteed\" rule for every text format; GML has its own\n * spellings of the non-finite values in formatGmlReal().\n * @param value - the value\n * @param dtype - the column dtype the value comes from; f32 values use the shortest fround-round-trip text\n * @returns the text\n */\nexport function formatDecimal(value: number, dtype: \"f32\" | \"f64\" | \"i32\" | \"u32\" | \"u8\" = \"f64\"): string {\n if (!Number.isFinite(value)) {\n return String(value);\n }\n if (Object.is(value, -0)) {\n return \"-0.0\";\n }\n const text = formatNumber(value, dtype);\n // an exponent form (`1e+21`, `1.5e-7`) is already f64 text under the 5.1 grammar\n return text.includes(\".\") || text.includes(\"e\") ? text : `${text}.0`;\n}\n\n/**\n * A GML real: the shortest text with a decimal point guaranteed (`2.0`, `1.0e-7`), so a re-import\n * keeps the column real rather than int. Non-finite values have no GML spelling and are written\n * as the texts NetworkX's writer emits and its reader accepts, `+INF`, `-INF` and `NAN` (the\n * lowercase `inf` / `nan` would lex as keys there).\n * @param value - the value\n * @param dtype - the column dtype the value comes from; f32 values use the shortest fround-round-trip text\n * @returns the text\n */\nexport function formatGmlReal(value: number, dtype: \"f32\" | \"f64\" | \"i32\" | \"u32\" | \"u8\" = \"f64\"): string {\n if (Number.isNaN(value)) {\n return \"NAN\";\n }\n if (!Number.isFinite(value)) {\n return value > 0 ? \"+INF\" : \"-INF\";\n }\n const text = formatDecimal(value, dtype);\n if (text.includes(\".\")) {\n return text;\n }\n // NetworkX's real pattern requires a decimal point even in the exponent form (`1.0e-7`)\n const e = text.indexOf(\"e\");\n return `${text.slice(0, e)}.0${text.slice(e)}`;\n}\n\n/**\n * An integer text for a value known to be integral (an i32 / u32 / u8 cell, an f64 that holds an\n * integer), avoiding the exponent form `String()` uses above 1e21.\n * @param value - an integral value\n * @returns the digits\n */\nexport function formatInteger(value: number): string {\n if (Number.isSafeInteger(value) || !Number.isFinite(value)) {\n return String(value);\n }\n return BigInt(value).toString();\n}\n\n/**\n * The text of a numeric cell of any numeric dtype, dispatching on the dtype: f32 through\n * formatF32, everything else through formatF64.\n * @param value - the value\n * @param dtype - the column dtype the value came from\n * @returns the text\n */\nexport function formatNumber(value: number, dtype: \"f32\" | \"f64\" | \"i32\" | \"u32\" | \"u8\"): string {\n return dtype === \"f32\" ? formatF32(value) : formatF64(value);\n}\n","/**\n * Weight resolution shared by every importer (design sections 3.7 and 8.4): which source field is\n * THE weight (`weightFrom`, per-format default, null = unweighted), how its text or JSON value\n * becomes the number passed to `addEdge`, and the E_INVALID_WEIGHT boundary.\n *\n * An edge whose weight field is absent or blank is pushed WITHOUT a weight argument, never with an\n * explicit 1: the builder's weightSet bitmap then records that the weight was defaulted, and the\n * exporter re-emits no weight for it (decision D-WSET). NaN and non-numeric text are\n * E_INVALID_WEIGHT before the sink is touched, so the importer records the issue and skips the edge\n * with the sink unchanged; Infinity and negative values are legal weights (design section 3.7).\n */\n\nimport { type Column, GraphFormatError, type GraphSnapshot } from \"@graphty/graph-format\";\n\nimport { parseDecimalText } from \"./declared-types.js\";\nimport { formatF32, formatF64, formatInteger } from \"./format.js\";\n\n/** The weight of an edge added without one (design section 3.7). */\nexport const DEFAULT_WEIGHT = 1;\n\n/**\n * Whether a source field is the weight field under the resolved `weightFrom` option.\n * @param name - the field name (attribute title, CSV header, JSON key)\n * @param weightFrom - the resolved option; null means unweighted\n * @returns true when the field is THE weight\n */\nexport function isWeightField(name: string, weightFrom: string | null): boolean {\n return weightFrom !== null && name === weightFrom;\n}\n\n/**\n * The weight argument of addEdge from a text cell: undefined for a blank cell (the weight is\n * omitted), the number otherwise.\n * @param text - the cell text\n * @returns the weight, or undefined when blank; E_INVALID_WEIGHT for NaN or non-numeric text\n */\nexport function parseWeightText(text: string): number | undefined {\n const trimmed = text.trim();\n if (trimmed.length === 0) {\n return undefined;\n }\n let value: number;\n try {\n value = parseDecimalText(trimmed);\n } catch (err) {\n throw invalidWeight(text, err);\n }\n if (Number.isNaN(value)) {\n throw invalidWeight(text, null);\n }\n return value;\n}\n\n/**\n * The weight argument of addEdge from a typed value (JSON, a record field): undefined for null /\n * undefined, the number for a finite or infinite number, the parsed number for numeric text.\n * @param value - the field value\n * @returns the weight, or undefined when absent; E_INVALID_WEIGHT for NaN, a boolean, an object or non-numeric text\n */\nexport function weightFromValue(value: unknown): number | undefined {\n if (value === undefined || value === null) {\n return undefined;\n }\n if (typeof value === \"number\") {\n if (Number.isNaN(value)) {\n throw invalidWeight(value, null);\n }\n return value;\n }\n if (typeof value === \"string\") {\n return parseWeightText(value);\n }\n throw invalidWeight(value, null);\n}\n\n/**\n * The E_INVALID_WEIGHT error of a rejected value.\n * @param value - the rejected value\n * @param cause - the parse error, or null\n * @returns the error\n */\nfunction invalidWeight(value: unknown, cause: unknown): GraphFormatError {\n let shown: string;\n switch (typeof value) {\n case \"string\":\n shown = JSON.stringify(value);\n break;\n case \"number\":\n shown = String(value);\n break;\n default:\n shown = typeof value;\n }\n return new GraphFormatError(\"E_INVALID_WEIGHT\", `invalid edge weight ${shown}`, {\n value: typeof value === \"object\" ? typeof value : value,\n cause: cause instanceof Error ? cause.message : null,\n });\n}\n\n// ============================================================ the exporter side\n\n/**\n * The explicit weights of a snapshot for exporters (design sections 3.7 and 8.5): the weight\n * role column when present (its validity says which edges had an explicit weight, its dtype how\n * the value is written), else `edgeList().weights` as f32 for every edge of a weighted snapshot;\n * nothing for an unweighted one. One implementation for every exporter.\n * Consumed by the per-format exporters under src/formats.\n * @public\n */\nexport interface ExplicitWeights {\n /** Whether any edge can have an explicit weight (the snapshot is weighted). */\n readonly weighted: boolean;\n /** The dtype the values are read from: the shadow column's, or f32 for the arc array. */\n readonly dtype: \"f32\" | \"f64\";\n /**\n * Whether an edge's weight was explicit in the source.\n * @param e - the logical edge index\n * @returns true when the exporter must write it\n */\n isExplicit(e: number): boolean;\n /**\n * The weight value of an edge (meaningful when explicit).\n * @param e - the logical edge index\n * @returns the value\n */\n value(e: number): number;\n /**\n * The weight text of an edge: the shortest round-tripping decimal for its dtype, or the\n * integer digits when `integral` is requested and the value is an integer; null when the\n * weight was defaulted.\n * @param e - the logical edge index\n * @param integral - write an integral value without a decimal part (formats declaring an int weight)\n * @returns the text, or null\n */\n text(e: number, integral?: boolean): string | null;\n}\n\n/** A weight of -0 keeps its sign: every importer's weight grammar reads \"-0\" back as -0. */\nconst NEGATIVE_ZERO_TEXT = \"-0\";\n\n/** The dtypes a weight role column may have (an integer column declared by a caller included). */\nconst NUMERIC_DTYPES: ReadonlySet<string> = new Set([\"f32\", \"f64\", \"i32\", \"u32\", \"u8\"]);\n\n/**\n * The shortest round-tripping text of a weight by the shadow column's dtype.\n * @param dtype - the shadow column's dtype\n * @returns the formatter\n */\nfunction weightFormatter(dtype: string): (value: number) => string {\n switch (dtype) {\n case \"f32\":\n return formatF32;\n case \"f64\":\n return formatF64;\n default:\n return formatInteger;\n }\n}\n\n/**\n * Build the explicit-weight view of a snapshot.\n * @param snapshot - the snapshot\n * @returns the view\n */\nexport function explicitWeights(snapshot: GraphSnapshot): ExplicitWeights {\n const shadowColumn = snapshot.edges.byRole(\"weight\");\n const shadow: Column | null = shadowColumn !== null && NUMERIC_DTYPES.has(shadowColumn.dtype) ? shadowColumn : null;\n if (shadow !== null) {\n const dtype = shadow.dtype === \"f32\" ? \"f32\" : \"f64\";\n const format = weightFormatter(shadow.dtype);\n return {\n weighted: true,\n dtype,\n isExplicit: (e: number): boolean => shadow.isSet(e),\n value: (e: number): number => shadow.value(e) as number,\n text: (e: number, integral = false): string | null => {\n if (!shadow.isSet(e)) {\n return null;\n }\n const value = shadow.value(e) as number;\n if (Object.is(value, -0)) {\n return NEGATIVE_ZERO_TEXT;\n }\n return integral && Number.isInteger(value) ? formatInteger(value) : format(value);\n },\n };\n }\n const { weights } = snapshot.edgeList();\n if (weights === null || !snapshot.flags.weighted) {\n return {\n weighted: false,\n dtype: \"f32\",\n isExplicit: (): boolean => false,\n value: (): number => DEFAULT_WEIGHT,\n text: (): string | null => null,\n };\n }\n return {\n weighted: true,\n dtype: \"f32\",\n isExplicit: (): boolean => true,\n value: (e: number): number => weights[e],\n text: (e: number, integral = false): string => {\n const value = weights[e];\n if (Object.is(value, -0)) {\n return NEGATIVE_ZERO_TEXT;\n }\n return integral && Number.isInteger(value) ? formatInteger(value) : formatF32(value);\n },\n };\n}\n","/**\n * The exporter-side machinery of design section 8.5: the ExportCapabilities table helper, the\n * generic check() that turns capability gaps into LossNotes with shared codes, and id sanitising\n * (`sanitizeIds: \"error\"` by default; an exporter never silently renames a node; \"mangle\" rewrites\n * the ids the format cannot hold and hands the exporter the originals to write into its\n * `graphty:originalId` attribute).\n *\n * Every exporter's check() calls checkCapabilities() first and appends its format-specific notes\n * (design section 8.5 names W_GML_RECORD_NUMBER_TYPE and W_OPEN_INTERVAL); export() calls\n * sanitizeIds() before writing anything.\n */\n\nimport {\n type Column,\n type Dtype,\n GraphFormatError,\n type GraphSnapshot,\n INVALID_INDEX,\n type NodeId,\n} from \"@graphty/graph-format\";\n\nimport { type ExportCapabilities, type LossNote } from \"../types.js\";\nimport {\n COLUMN_RENAMED_LOSS_CODE,\n EMPTY_COLUMN_DROPPED_CODE,\n ID_TEXT_COLLISION_CODE,\n ID_TEXT_TYPE_CODE,\n INTEGRAL_F64_CODE,\n MIXED_DIRECTION_CODE,\n MUTUAL_AS_UNDIRECTED_CODE,\n MUTUAL_EXPANDED_CODE,\n OPTIONS_GAINED_CODE,\n PARENTS_DROPPED_CODE,\n ROLE_ASSUMED_CODE,\n ROLE_DROPPED_CODE,\n STORAGE_CLASS_CODE,\n TEMPORAL_DROPPED_CODE,\n TEMPORAL_TEXT_DROPPED_CODE,\n TEXT_INFERRED_CODE,\n WEIGHT_KEY_CLASH_CODE,\n XML_ILLEGAL_CHAR_CODE,\n} from \"./codes.js\";\nimport { type ResolvedExportOptions } from \"./options.js\";\n\n/** The shared LossNote codes of checkCapabilities(). */\nexport const LOSS = Object.freeze({\n /** The format has no mixed direction; expanded pairs are written per onMixedDirection. */\n MIXED_DIRECTION: \"W_MIXED_DIRECTION\",\n /** The format has no mixed direction and onMixedDirection is \"error\": export() will throw E_DIRECTED. */\n MIXED_DIRECTION_ERROR: MIXED_DIRECTION_CODE,\n /** Parallel edges in a format without them. */\n MULTI_EDGES: \"W_MULTI_EDGES\",\n /** Self-loops in a format without them. */\n SELF_LOOPS: \"W_SELF_LOOPS\",\n /** The format requires edge ids and the snapshot has none; canonical e0..e{E-1} are generated. */\n EDGE_IDS_GENERATED: \"W_EDGE_IDS_GENERATED\",\n /** The snapshot has an edge id column and the format cannot write one. */\n EDGE_IDS_DROPPED: \"W_EDGE_IDS_DROPPED\",\n /** Ids outside the format's charset are rewritten (sanitizeIds \"mangle\"). */\n ID_MANGLED: \"W_ID_MANGLED\",\n /** Ids outside the format's charset and sanitizeIds \"error\": export() will throw E_INVALID_ID. */\n ID_CHARSET: \"E_ID_CHARSET\",\n /** The format numbers nodes 1..N; ids that are not their 1-based index are kept as labels only. */\n ID_RENUMBERED: \"W_ID_RENUMBERED\",\n /** A column dtype the format does not keep as declared. */\n DTYPE: \"W_DTYPE_UNSUPPORTED\",\n /** A multi-component column in a format without strides. */\n COMPONENTS: \"W_COMPONENTS_FLATTENED\",\n /** A list column in a format without lists. */\n LIST: \"W_LIST_UNSUPPORTED\",\n /** A json column in a format without nested values. */\n JSON: \"W_JSON_UNSUPPORTED\",\n /** A declared default in a format without defaults. */\n DEFAULT: \"W_DEFAULT_DROPPED\",\n /** Declared options in a format without enumerations. */\n OPTIONS: \"W_OPTIONS_DROPPED\",\n /** A parent / parents column in a format without containment. */\n HIERARCHY: \"W_HIERARCHY_DROPPED\",\n /** A start / end / timestamp column in a format without temporal support. */\n TEMPORAL: TEMPORAL_DROPPED_CODE,\n /** A `<column>.text` companion (design section 5.1) the format cannot carry. */\n TEMPORAL_TEXT: TEMPORAL_TEXT_DROPPED_CODE,\n /** A role column the format has no slot for; written as a plain attribute, the role lost. */\n ROLE: ROLE_DROPPED_CODE,\n /** A parents (multi-parent) column in a format with single containment only. */\n PARENTS: PARENTS_DROPPED_CODE,\n /** A mutual pair written as two directed edges without the mutual mark. */\n MUTUAL_EXPANDED: MUTUAL_EXPANDED_CODE,\n /** A mutual pair written as one undirected edge; the mark is lost and the pair reads back undirected. */\n MUTUAL_AS_UNDIRECTED: MUTUAL_AS_UNDIRECTED_CODE,\n /** Node ids whose written text reads back as the other type under the importer's id rule. */\n ID_TEXT_TYPE: ID_TEXT_TYPE_CODE,\n /** Two node ids share one written text; export() throws E_INVALID_ID. */\n ID_TEXT_COLLISION: ID_TEXT_COLLISION_CODE,\n /** A plain column named like the importer's weight key reads back as THE weight. */\n WEIGHT_KEY_CLASH: WEIGHT_KEY_CLASH_CODE,\n /** A role-less column whose written name the importer maps to a role. */\n ROLE_ASSUMED: ROLE_ASSUMED_CODE,\n /** A role column written into the format's slot reads back under the importer's fixed name. */\n COLUMN_NAME_CHANGED: COLUMN_RENAMED_LOSS_CODE,\n /** A declared column whose every row is unset vanishes through a format without declarations. */\n EMPTY_COLUMN: EMPTY_COLUMN_DROPPED_CODE,\n /** A string / dict column that reads back as the other storage class (the dictionary heuristic). */\n STORAGE_CLASS: STORAGE_CLASS_CODE,\n /** An f64 column whose set values are all integral reads back as i32 through an untyped format. */\n INTEGRAL_F64: INTEGRAL_F64_CODE,\n /** Text cells that read back as numbers or booleans under the 5.1 grammar. */\n TEXT_INFERRED: TEXT_INFERRED_CODE,\n /** A string cell holding a character XML 1.0 forbids; export() throws E_COLUMN_TYPE. */\n XML_ILLEGAL_CHAR: XML_ILLEGAL_CHAR_CODE,\n /** A dict column without declared options gains one on re-import. */\n OPTIONS_GAINED: OPTIONS_GAINED_CODE,\n /** A spells column in a format without spells. */\n SPELLS: \"W_SPELLS_DROPPED\",\n /** Dynamic attribute values (extension tables) in a format without them. */\n DYNAMIC_VALUES: \"W_DYNAMIC_VALUES_DROPPED\",\n /** An open-interval column in a format without open intervals (design section 5.1). */\n OPEN_INTERVAL: \"W_OPEN_INTERVAL\",\n /** Graph-level attributes in a format without them. */\n GRAPH_ATTRIBUTES: \"W_GRAPH_ATTRIBUTES_DROPPED\",\n /** A position column in a format without positions. */\n POSITIONS: \"W_POSITIONS_DROPPED\",\n /** Visual columns in a format without them. */\n VIZ: \"W_VIZ_DROPPED\",\n /** An extension table the format cannot carry. */\n EXTENSION_TABLE: \"W_EXTENSION_TABLE_DROPPED\",\n});\n\n/** The capabilities of a format that keeps nothing beyond plain topology; the base every exporter overrides. */\nexport const NO_CAPABILITIES: ExportCapabilities = Object.freeze({\n mixedDirection: false,\n multiEdges: false,\n selfLoops: false,\n edgeIds: \"none\",\n idCharset: \"any\",\n dtypes: Object.freeze([]),\n components: false,\n lists: false,\n json: false,\n defaults: false,\n options: false,\n hierarchy: false,\n temporal: \"none\",\n graphAttributes: false,\n positions: false,\n viz: false,\n});\n\n/**\n * Build a capabilities table from the fields a format supports; every field left out is the\n * conservative NO_CAPABILITIES value, so an exporter states what it keeps and nothing is assumed.\n * @param supported - the fields the format supports\n * @returns a frozen table\n */\nexport function capabilities(supported: Partial<ExportCapabilities>): ExportCapabilities {\n return Object.freeze({ ...NO_CAPABILITIES, ...supported, dtypes: Object.freeze([...(supported.dtypes ?? [])]) });\n}\n\n/**\n * Format facts checkCapabilities() needs that the 12.4 table does not carry.\n * Consumed by the per-format importers and exporters under src/formats.\n * @public\n */\nexport interface CheckExtras {\n /** Whether the format can write open intervals (GEXF 1.2 startopen / endopen); default false. */\n readonly openIntervals?: boolean | undefined;\n /**\n * Whether the format carries the `<column>.text` companions of design section 5.1 (the lexical\n * form of a temporal value); default false, and every companion is then reported as\n * W_TEMPORAL_TEXT_DROPPED.\n */\n readonly temporalText?: boolean | undefined;\n /**\n * The dtype the format's importer gives a position column; an f32 / f64 position of the other\n * dtype is reported as W_DTYPE_UNSUPPORTED because its values differ at the other precision.\n * Undefined skips the check.\n */\n readonly positionDtype?: Dtype | undefined;\n /**\n * The roles beyond the structural, position, viz, hierarchy and temporal ones that the format\n * has a slot for (`label`, `kind`, `labels`, `idSpace`, `sourcePort`, `targetPort`, ...); a\n * column with any other role is written as a plain attribute and reported as W_ROLE_DROPPED.\n * Defaults to none.\n */\n readonly roles?: ReadonlySet<string> | undefined;\n /**\n * Roles the format writes into a fixed slot whose importer reads them back under a fixed name;\n * a role column named otherwise is reported as W_COLUMN_NAME_CHANGED (role -> the name the\n * importer gives it). Defaults to none.\n */\n readonly roleNames?: Readonly<Record<string, string>> | undefined;\n}\n\n/** The roles checkCapabilities() treats structurally rather than as attribute columns. */\nconst STRUCTURAL_ROLES: ReadonlySet<string> = new Set([\"directed\", \"pair\", \"mutual\", \"weight\", \"originalId\"]);\nconst VIZ_ROLES: ReadonlySet<string> = new Set([\"color\", \"size\", \"shape\", \"thickness\"]);\nconst TEMPORAL_ROLES: ReadonlySet<string> = new Set([\"start\", \"end\", \"timestamp\", \"timestamps\"]);\nconst HIERARCHY_ROLES: ReadonlySet<string> = new Set([\"parent\", \"parents\"]);\n\n/**\n * The generic pre-flight of design section 8.5: compare a snapshot with a format's capabilities\n * and return one LossNote per gap, with the shared codes of LOSS. Format-specific notes are the\n * exporter's to append.\n * @param snapshot - the snapshot about to be exported\n * @param caps - the exporter's capabilities\n * @param options - the resolved common export options\n * @param extras - format facts the capabilities table does not carry\n * @returns the notes, empty when the export is exact\n */\nexport function checkCapabilities(\n snapshot: GraphSnapshot,\n caps: ExportCapabilities,\n options: ResolvedExportOptions,\n extras: CheckExtras = {},\n): LossNote[] {\n const notes: LossNote[] = [];\n const note = (code: string, message: string, column: string | null = null, count: number | null = null): void => {\n notes.push(Object.freeze({ code, message, column, count }));\n };\n\n // mixed direction (design section 3.6): an expanded snapshot carries the pair / directed roles\n const mixed = countMixedEdges(snapshot);\n if (mixed > 0 && !caps.mixedDirection) {\n if (options.onMixedDirection === \"error\") {\n note(\n LOSS.MIXED_DIRECTION_ERROR,\n `${mixed} undirected edge(s) in a directed graph; the format has no mixed direction and onMixedDirection is \"error\"`,\n null,\n mixed,\n );\n } else {\n note(\n LOSS.MIXED_DIRECTION,\n `${mixed} undirected edge(s) in a directed graph written as ${options.onMixedDirection}`,\n null,\n mixed,\n );\n }\n }\n\n if (snapshot.flags.multigraph && !caps.multiEdges) {\n const parallel = countParallelArcs(snapshot);\n note(LOSS.MULTI_EDGES, `${parallel} parallel edge(s); the format has no parallel edges`, null, parallel);\n }\n if (snapshot.selfLoopCount > 0 && !caps.selfLoops) {\n note(\n LOSS.SELF_LOOPS,\n `${snapshot.selfLoopCount} self-loop(s); the format has no self-loops`,\n null,\n snapshot.selfLoopCount,\n );\n }\n\n const edgeIds = snapshot.edges.byRole(\"id\");\n if (caps.edgeIds === \"required\" && edgeIds === null && snapshot.edgeCount > 0) {\n note(\n LOSS.EDGE_IDS_GENERATED,\n \"the format requires edge ids; canonical e0..e{E-1} are generated and not written back\",\n null,\n snapshot.edgeCount,\n );\n } else if (caps.edgeIds === \"none\" && edgeIds !== null) {\n note(\n LOSS.EDGE_IDS_DROPPED,\n `edge id column \"${edgeIds.meta.name}\" cannot be written`,\n edgeIds.meta.name,\n snapshot.edgeCount,\n );\n }\n\n const unrepresentable = countUnrepresentableIds(snapshot, caps.idCharset);\n if (unrepresentable > 0) {\n if (caps.idCharset === \"dense-1-based\") {\n note(\n LOSS.ID_RENUMBERED,\n options.sanitizeIds === \"mangle\"\n ? `${unrepresentable} node id(s) are not their 1-based index; nodes are numbered 1..N, the originals kept in the exporter's originalId attribute (restored by restoreMangledIds) and as labels of the nodes without a label value`\n : `${unrepresentable} node id(s) are not their 1-based index; nodes are numbered 1..N and ids kept as labels of the nodes without a label value (a node with one loses its id)`,\n null,\n unrepresentable,\n );\n } else if (options.sanitizeIds === \"mangle\") {\n note(\n LOSS.ID_MANGLED,\n `${unrepresentable} node id(s) outside the ${caps.idCharset} charset are rewritten; originals kept in the originalId attribute`,\n null,\n unrepresentable,\n );\n } else {\n note(\n LOSS.ID_CHARSET,\n `${unrepresentable} node id(s) outside the ${caps.idCharset} charset; export() will throw unless sanitizeIds is \"mangle\"`,\n null,\n unrepresentable,\n );\n }\n }\n\n checkColumns(snapshot.nodes, \"node\", caps, extras, note);\n checkColumns(snapshot.edges, \"edge\", caps, extras, note);\n const graphColumns = snapshot.graph.names();\n if (graphColumns.length > 0) {\n if (caps.graphAttributes) {\n checkColumns(snapshot.graph, \"graph\", caps, extras, note);\n } else {\n note(\n LOSS.GRAPH_ATTRIBUTES,\n `${graphColumns.length} graph attribute(s) cannot be written`,\n null,\n graphColumns.length,\n );\n }\n }\n\n for (const [name, table] of snapshot.extensions) {\n if (name.startsWith(\"temporal:\")) {\n if (caps.temporal !== \"dynamic-values\") {\n note(\n LOSS.DYNAMIC_VALUES,\n `dynamic values of \"${name}\" (${table.rowCount} row(s)) cannot be written`,\n name,\n table.rowCount,\n );\n }\n } else {\n note(\n LOSS.EXTENSION_TABLE,\n `extension table \"${name}\" (${table.rowCount} row(s)) cannot be written`,\n name,\n table.rowCount,\n );\n }\n }\n return notes;\n}\n\n/** A note-recording callback. */\ntype NoteFn = (code: string, message: string, column?: string | null, count?: number | null) => void;\n\n/**\n * The per-column checks of checkCapabilities().\n * @param table - the table\n * @param domain - the domain, for messages\n * @param caps - the capabilities\n * @param extras - format extras\n * @param note - the recorder\n */\nfunction checkColumns(\n table: Iterable<Column>,\n domain: string,\n caps: ExportCapabilities,\n extras: CheckExtras,\n note: NoteFn,\n): void {\n for (const column of table) {\n const { meta } = column;\n const { name, role } = meta;\n if (role !== null && STRUCTURAL_ROLES.has(role)) {\n continue;\n }\n const label = `${domain} column \"${name}\"`;\n if (role !== null && extras.roleNames !== undefined) {\n const fixed = extras.roleNames[role];\n if (fixed !== undefined && fixed !== name) {\n note(\n LOSS.COLUMN_NAME_CHANGED,\n `${label} (${role}) is written into the format's ${role} slot and reads back as \"${fixed}\"`,\n name,\n column.length - column.nullCount,\n );\n }\n }\n if (domain === \"edge\" && role === \"id\") {\n continue;\n }\n if (role === \"timeText\") {\n if (extras.temporalText !== true) {\n note(\n LOSS.TEMPORAL_TEXT,\n `${label} (the lexical form of a temporal column, design section 5.1) cannot be written`,\n name,\n column.length - column.nullCount,\n );\n }\n continue;\n }\n if (role === \"position\") {\n if (!caps.positions) {\n note(LOSS.POSITIONS, `${label} (positions) cannot be written`, name, column.length - column.nullCount);\n } else if (extras.positionDtype !== undefined && meta.dtype !== extras.positionDtype) {\n note(\n LOSS.DTYPE,\n `${label} (positions) is ${meta.dtype}; the format reads positions back as ${extras.positionDtype}`,\n name,\n column.length - column.nullCount,\n );\n }\n continue;\n }\n if (role !== null && VIZ_ROLES.has(role)) {\n if (!caps.viz) {\n note(LOSS.VIZ, `${label} (${role}) cannot be written`, name, column.length - column.nullCount);\n }\n continue;\n }\n if (role !== null && HIERARCHY_ROLES.has(role)) {\n if (!caps.hierarchy) {\n note(LOSS.HIERARCHY, `${label} (${role}) cannot be written`, name, column.length - column.nullCount);\n }\n continue;\n }\n if (role !== null && TEMPORAL_ROLES.has(role)) {\n if (caps.temporal === \"none\") {\n note(LOSS.TEMPORAL, `${label} (${role}) cannot be written`, name, column.length - column.nullCount);\n }\n continue;\n }\n if (role === \"spells\") {\n if (caps.temporal !== \"spells\" && caps.temporal !== \"dynamic-values\") {\n note(LOSS.SPELLS, `${label} (spells) cannot be written`, name, column.length - column.nullCount);\n }\n continue;\n }\n if (role === \"open\" || role === \"spellsOpen\") {\n // The open bits are written by the format's own temporal syntax when it has one; the\n // column's u8 storage is never an attribute dtype, so no dtype note either way.\n if (extras.openIntervals !== true) {\n note(\n LOSS.OPEN_INTERVAL,\n `${label} (open intervals) cannot be written`,\n name,\n column.length - column.nullCount,\n );\n }\n continue;\n }\n if (role !== null && !(extras.roles?.has(role) ?? false)) {\n note(\n LOSS.ROLE,\n `${label} (${role}) is written as a plain attribute; the format has no ${role} slot and the role is lost`,\n name,\n column.length - column.nullCount,\n );\n }\n if (meta.dynamic && caps.temporal !== \"dynamic-values\") {\n note(LOSS.DYNAMIC_VALUES, `${label} is dynamic; only its static value can be written`, name, null);\n }\n checkDtype(column, label, caps, note);\n if (meta.default !== undefined && !caps.defaults) {\n note(LOSS.DEFAULT, `${label} declares a default; the format has no defaults`, name, null);\n }\n if (meta.options !== null && !caps.options) {\n note(LOSS.OPTIONS, `${label} declares options; the format has no enumerations`, name, null);\n }\n }\n}\n\n/**\n * The dtype checks of one attribute column: lists, nested values, scalar dtypes and strides\n * against the capability table.\n * @param column - the column\n * @param label - the column's label for messages\n * @param caps - the capabilities\n * @param note - the recorder\n */\nfunction checkDtype(column: Column, label: string, caps: ExportCapabilities, note: NoteFn): void {\n const { meta } = column;\n const { name } = meta;\n const set = column.length - column.nullCount;\n switch (meta.dtype) {\n case \"list\":\n if (!caps.lists) {\n note(LOSS.LIST, `${label} is a list; the format has no lists`, name, set);\n } else if (meta.itemDtype !== null && !caps.dtypes.includes(meta.itemDtype)) {\n note(\n LOSS.DTYPE,\n `${label} holds ${meta.itemDtype} items; the format cannot keep that dtype`,\n name,\n set,\n );\n } else if (meta.itemDtype === \"dict\") {\n // no format declares an enumeration for list items: they read back as strings\n note(LOSS.DTYPE, `${label} holds dict items; list items read back as string`, name, set);\n }\n break;\n case \"json\":\n if (!caps.json) {\n note(LOSS.JSON, `${label} holds nested values; the format has no nested values`, name, set);\n }\n break;\n default:\n if (!caps.dtypes.includes(meta.dtype)) {\n note(LOSS.DTYPE, `${label} is ${meta.dtype}; the format cannot keep that dtype`, name, set);\n }\n if (meta.components > 1 && !caps.components) {\n note(\n LOSS.COMPONENTS,\n `${label} has ${meta.components} components; the format has no strides`,\n name,\n set,\n );\n }\n break;\n }\n}\n\n/**\n * The number of source edges that were undirected in a directed snapshot (the halves of an\n * expanded pair count once; an expanded self-loop has no mirror and counts once).\n * @param snapshot - the snapshot\n * @returns the count; 0 for an undirected snapshot or one without the directed role\n */\nexport function countMixedEdges(snapshot: GraphSnapshot): number {\n if (!snapshot.directed) {\n return 0;\n }\n const directed = snapshot.edges.byRole(\"directed\");\n if (directed === null || directed.dtype !== \"bool\") {\n return 0;\n }\n const pair = snapshot.edges.byRole(\"pair\");\n let undirectedRows = 0;\n let paired = 0;\n for (let e = 0; e < snapshot.edgeCount; e++) {\n if (directed.isSet(e) && directed.value(e) === false) {\n undirectedRows++;\n if (pair !== null && pair.dtype === \"u32\" && pair.isSet(e) && pair.data[e] !== INVALID_INDEX) {\n paired++;\n }\n }\n }\n return paired / 2 + (undirectedRows - paired);\n}\n\n/**\n * The number of arcs that repeat the previous arc's target within a row (parallel edges), counted\n * over the forward CSR; an undirected parallel edge is counted in both rows.\n * @param snapshot - the snapshot\n * @returns the count\n */\nexport function countParallelArcs(snapshot: GraphSnapshot): number {\n const { rowPtr, colIdx, nodeCount } = snapshot;\n let count = 0;\n for (let u = 0; u < nodeCount; u++) {\n for (let a = rowPtr[u] + 1; a < rowPtr[u + 1]; a++) {\n if (colIdx[a] === colIdx[a - 1]) {\n count++;\n }\n }\n }\n return snapshot.directed ? count : Math.ceil(count / 2);\n}\n\n// ============================================================ id sanitising\n\n/**\n * The id charsets of ExportCapabilities.\n * Consumed by the per-format importers and exporters under src/formats.\n * @public\n */\nexport type IdCharset = ExportCapabilities[\"idCharset\"];\n\n/**\n * The ids to write for every node after sanitising (design section 8.5).\n * Consumed by the per-format importers and exporters under src/formats.\n * @public\n */\nexport interface SanitizedIds {\n /** The charset applied. */\n readonly charset: IdCharset;\n /** How many ids differ from the snapshot's. */\n readonly changed: number;\n /**\n * The id to write for a node.\n * @param index - the node index\n * @returns the id as the format will read it back\n */\n idAt(index: number): NodeId;\n /**\n * Whether a node's written id differs from its original.\n * @param index - the node index\n * @returns true when the exporter must record the original\n */\n isChanged(index: number): boolean;\n /**\n * The original id of a node.\n * @param index - the node index\n * @returns the snapshot's id\n */\n originalAt(index: number): NodeId;\n}\n\n/** XML NameChar ranges (XML 1.0 fifth edition), as inclusive code point pairs. */\nconst NAME_CHAR_RANGES: readonly (readonly [number, number])[] = [\n [0x2d, 0x2e],\n [0x30, 0x3a],\n [0x41, 0x5a],\n [0x5f, 0x5f],\n [0x61, 0x7a],\n [0xb7, 0xb7],\n [0xc0, 0xd6],\n [0xd8, 0xf6],\n [0xf8, 0x37d],\n [0x37f, 0x1fff],\n [0x200c, 0x200d],\n [0x203f, 0x2040],\n [0x2070, 0x218f],\n [0x2c00, 0x2fef],\n [0x3001, 0xd7ff],\n [0xf900, 0xfdcf],\n [0xfdf0, 0xfffd],\n [0x10000, 0xeffff],\n];\n\n/**\n * Whether a code point is an XML NameChar.\n * @param cp - the code point\n * @returns true when it may appear in an NMTOKEN\n */\nexport function isNameChar(cp: number): boolean {\n for (const [lo, hi] of NAME_CHAR_RANGES) {\n if (cp < lo) {\n return false;\n }\n if (cp <= hi) {\n return true;\n }\n }\n return false;\n}\n\n/**\n * Whether a text is an XML NMTOKEN (one or more NameChars; GraphML node and edge ids).\n * @param text - the text\n * @returns true for a non-empty text of NameChars\n */\nexport function isNmtoken(text: string): boolean {\n if (text.length === 0) {\n return false;\n }\n for (const ch of text) {\n const cp = ch.codePointAt(0);\n if (cp === undefined || !isNameChar(cp)) {\n return false;\n }\n }\n return true;\n}\n\n/**\n * Whether an id can be written unchanged under a charset.\n * @param id - the id\n * @param charset - the charset\n * @returns true when the id needs no rewriting (\"dense-1-based\" is never true: see sanitizeIds)\n */\nexport function isRepresentableId(id: NodeId, charset: IdCharset): boolean {\n switch (charset) {\n case \"any\":\n return true;\n case \"nmtoken\":\n return isNmtoken(String(id));\n case \"integer\":\n return typeof id === \"number\" && Number.isSafeInteger(id);\n case \"dense-1-based\":\n return false;\n default: {\n const name: string = charset;\n throw new GraphFormatError(\"E_UNSUPPORTED\", `unknown id charset ${name}`, { charset: name });\n }\n }\n}\n\n/**\n * How many node ids a charset cannot hold as they are (for check()); under \"dense-1-based\" the\n * ids that are not their own 1-based index.\n * @param snapshot - the snapshot\n * @param charset - the charset\n * @returns the count\n */\nexport function countUnrepresentableIds(snapshot: GraphSnapshot, charset: IdCharset): number {\n const { ids } = snapshot;\n if (charset === \"any\") {\n return 0;\n }\n if (charset === \"dense-1-based\") {\n if (ids.kind === \"identity\" && ids.offset === 1) {\n return 0;\n }\n let changed = 0;\n for (let i = 0; i < ids.size; i++) {\n if (ids.idOf(i) !== i + 1) {\n changed++;\n }\n }\n return changed;\n }\n let count = 0;\n for (let i = 0; i < ids.size; i++) {\n if (!isRepresentableId(ids.idOf(i), charset)) {\n count++;\n }\n }\n return count;\n}\n\n/**\n * Sanitise the node ids for a charset (design section 8.5). Under \"error\" any id the charset\n * cannot hold is E_INVALID_ID (details.reason \"charset\") and nothing is written; under \"mangle\"\n * such ids are rewritten deterministically and uniquely: NMTOKEN by replacing every other\n * character with `_` (an empty result becomes `_`) and suffixing `_2`, `_3`... on collision;\n * integer by the smallest unused non-negative integers in index order. \"dense-1-based\" always\n * writes the 1-based index (Pajek numbers vertices; the exporter writes the original id as the\n * label), which is a renumbering rather than a mangling, so it never throws under \"error\"; under\n * \"mangle\" the exporter also writes the original id under its originalId attribute.\n * @param snapshot - the snapshot\n * @param charset - the charset\n * @param mode - the resolved sanitizeIds option\n * @returns the ids to write\n */\nexport function sanitizeIds(snapshot: GraphSnapshot, charset: IdCharset, mode: \"error\" | \"mangle\"): SanitizedIds {\n const { ids } = snapshot;\n const n = ids.size;\n if (charset === \"dense-1-based\") {\n const changed = countUnrepresentableIds(snapshot, charset);\n return {\n charset,\n changed,\n idAt: (i: number): NodeId => i + 1,\n isChanged: (i: number): boolean => ids.idOf(i) !== i + 1,\n originalAt: (i: number): NodeId => ids.idOf(i),\n };\n }\n const unchanged: SanitizedIds = {\n charset,\n changed: 0,\n idAt: (i: number): NodeId => ids.idOf(i),\n isChanged: (): boolean => false,\n originalAt: (i: number): NodeId => ids.idOf(i),\n };\n if (charset === \"any\") {\n return unchanged;\n }\n const bad: number[] = [];\n for (let i = 0; i < n; i++) {\n if (!isRepresentableId(ids.idOf(i), charset)) {\n bad.push(i);\n }\n }\n if (bad.length === 0) {\n return unchanged;\n }\n if (mode === \"error\") {\n const first = ids.idOf(bad[0]);\n throw new GraphFormatError(\n \"E_INVALID_ID\",\n `${bad.length} node id(s) cannot be written as ${charset} (first: ${JSON.stringify(first)} at index ${bad[0]}); pass sanitizeIds: \"mangle\" to rewrite them`,\n { reason: \"charset\", charset, count: bad.length, id: first, index: bad[0] },\n );\n }\n const written = new Map<number, NodeId>();\n if (charset === \"nmtoken\") {\n const used = new Set<string>();\n for (let i = 0; i < n; i++) {\n const id = ids.idOf(i);\n if (isRepresentableId(id, charset)) {\n used.add(String(id));\n }\n }\n for (const i of bad) {\n const base = mangleNmtoken(String(ids.idOf(i)));\n let candidate = base;\n for (let k = 2; used.has(candidate); k++) {\n candidate = `${base}_${k}`;\n }\n used.add(candidate);\n written.set(i, candidate);\n }\n } else {\n const used = new Set<number>();\n for (let i = 0; i < n; i++) {\n const id = ids.idOf(i);\n if (typeof id === \"number\" && Number.isSafeInteger(id)) {\n used.add(id);\n }\n }\n let next = 0;\n for (const i of bad) {\n while (used.has(next)) {\n next++;\n }\n used.add(next);\n written.set(i, next);\n next++;\n }\n }\n return {\n charset,\n changed: bad.length,\n idAt: (i: number): NodeId => written.get(i) ?? ids.idOf(i),\n isChanged: (i: number): boolean => written.has(i),\n originalAt: (i: number): NodeId => ids.idOf(i),\n };\n}\n\n/**\n * Rewrite a text as an NMTOKEN: every character that is not a NameChar becomes `_`.\n * @param text - the text\n * @returns a non-empty NMTOKEN\n */\nexport function mangleNmtoken(text: string): string {\n let out = \"\";\n for (const ch of text) {\n const cp = ch.codePointAt(0);\n out += cp !== undefined && isNameChar(cp) ? ch : \"_\";\n }\n return out.length === 0 ? \"_\" : out;\n}\n","/**\n * The output side of the exporter contract (design sections 8.5 and 12.4): an exporter produces\n * its document as a sequence of text parts (a sync or async generator of strings, one per line or\n * element); these helpers turn that sequence into `export()`'s `AsyncIterable<Uint8Array>` of\n * UTF-8 chunks of a bounded size, into `exportToString()`'s one string, or into a\n * `ReadableStream<Uint8Array>` for a caller that wants a stream.\n */\n\n/**\n * Text parts an exporter produces.\n * Consumed by the per-format importers and exporters under src/formats.\n * @public\n */\nexport type TextParts = Iterable<string> | AsyncIterable<string>;\n\n/** The target size of one encoded chunk; parts are coalesced up to it and never split. */\nexport const DEFAULT_CHUNK_BYTES = 64 * 1024;\n\n/**\n * Encode text parts as UTF-8 chunks of about `chunkBytes` each. Small parts are coalesced; a part\n * larger than the chunk size is emitted whole. The last chunk may be short; nothing is emitted for\n * an empty document.\n * @param parts - the text parts\n * @param chunkBytes - the target chunk size in bytes\n * @yields UTF-8 chunks\n * @returns nothing\n */\nexport async function* encodeChunks(\n parts: TextParts,\n chunkBytes: number = DEFAULT_CHUNK_BYTES,\n): AsyncGenerator<Uint8Array, void, undefined> {\n const encoder = new TextEncoder();\n let pending: string[] = [];\n let pendingUnits = 0;\n for await (const part of parts) {\n if (part.length === 0) {\n continue;\n }\n pending.push(part);\n pendingUnits += part.length;\n // UTF-16 code units are a lower bound on the UTF-8 byte count; flush when the lower bound reaches the target\n if (pendingUnits >= chunkBytes) {\n yield encoder.encode(pending.length === 1 ? pending[0] : pending.join(\"\"));\n pending = [];\n pendingUnits = 0;\n }\n }\n if (pending.length > 0) {\n yield encoder.encode(pending.length === 1 ? pending[0] : pending.join(\"\"));\n }\n}\n\n/**\n * Join text parts into one string.\n * @param parts - the text parts\n * @returns the whole document\n */\nexport async function joinText(parts: TextParts): Promise<string> {\n const collected: string[] = [];\n for await (const part of parts) {\n collected.push(part);\n }\n return collected.join(\"\");\n}\n\n/**\n * Decode UTF-8 chunks back into one string (for tests and for callers holding an export() result).\n * @param chunks - the chunks\n * @returns the decoded text\n */\nexport async function decodeChunks(chunks: AsyncIterable<Uint8Array>): Promise<string> {\n const decoder = new TextDecoder(\"utf-8\", { fatal: true });\n const parts: string[] = [];\n for await (const chunk of chunks) {\n parts.push(decoder.decode(chunk, { stream: true }));\n }\n parts.push(decoder.decode());\n return parts.join(\"\");\n}\n\n/**\n * Collect UTF-8 chunks into one Uint8Array.\n * @param chunks - the chunks\n * @returns the concatenated bytes\n */\nexport async function collectBytes(chunks: AsyncIterable<Uint8Array>): Promise<Uint8Array> {\n const parts: Uint8Array[] = [];\n let total = 0;\n for await (const chunk of chunks) {\n parts.push(chunk);\n total += chunk.byteLength;\n }\n const out = new Uint8Array(total);\n let offset = 0;\n for (const part of parts) {\n out.set(part, offset);\n offset += part.byteLength;\n }\n return out;\n}\n\n/**\n * Wrap an async iterable of chunks as a ReadableStream, pulling one chunk per read and cancelling\n * the iterable when the stream is cancelled.\n * @param chunks - the chunks\n * @returns a byte stream\n */\nexport function toReadableStream(chunks: AsyncIterable<Uint8Array>): ReadableStream<Uint8Array> {\n const iterator = chunks[Symbol.asyncIterator]();\n return new ReadableStream<Uint8Array>({\n async pull(controller): Promise<void> {\n const { done, value } = await iterator.next();\n if (done) {\n controller.close();\n return;\n }\n controller.enqueue(value);\n },\n async cancel(): Promise<void> {\n await iterator.return?.(undefined);\n },\n });\n}\n"],"names":["DATE_TIME","TIME","INTEGER_TEXT","list"],"mappings":"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"}
|