@graphty/graph-io 0.3.32 → 0.3.33
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/{choose-BJq_vp1b.js → choose-494CpuXQ.js} +2 -2
- package/dist/chunks/{choose-BJq_vp1b.js.map → choose-494CpuXQ.js.map} +1 -1
- package/dist/chunks/{constants-Bw-6JQuC.js → constants-BBK4rsQZ.js} +2 -2
- package/dist/chunks/{constants-Bw-6JQuC.js.map → constants-BBK4rsQZ.js.map} +1 -1
- package/dist/chunks/{escape-CnTfa_y8.js → escape-wVIEtLv6.js} +6 -6
- package/dist/chunks/escape-wVIEtLv6.js.map +1 -0
- package/dist/chunks/{export-ZucVKiU4.js → export-Cbt4h_0n.js} +8 -8
- package/dist/chunks/export-Cbt4h_0n.js.map +1 -0
- package/dist/chunks/{exporter-DRNkA2k0.js → exporter-BkkfMWGQ.js} +6 -6
- package/dist/chunks/{exporter-DRNkA2k0.js.map → exporter-BkkfMWGQ.js.map} +1 -1
- package/dist/chunks/{exporter-hc2ZuqVe.js → exporter-CqnmKk-f.js} +4 -4
- package/dist/chunks/{exporter-hc2ZuqVe.js.map → exporter-CqnmKk-f.js.map} +1 -1
- package/dist/chunks/{exporter-DgDjwLOm.js → exporter-DMxRy-0l.js} +4 -4
- package/dist/chunks/{exporter-DgDjwLOm.js.map → exporter-DMxRy-0l.js.map} +1 -1
- package/dist/chunks/{exporter-BOLJIzvA.js → exporter-jp43hhXk.js} +3 -3
- package/dist/chunks/{exporter-BOLJIzvA.js.map → exporter-jp43hhXk.js.map} +1 -1
- package/dist/chunks/{importer-WPz-AUz8.js → importer-BESct_Xz.js} +7 -7
- package/dist/chunks/importer-BESct_Xz.js.map +1 -0
- package/dist/chunks/{importer-DsNj_zoG.js → importer-BTSvNJUB.js} +4 -4
- package/dist/chunks/importer-BTSvNJUB.js.map +1 -0
- package/dist/chunks/{importer-ByCd2CAY.js → importer-BTbjwN10.js} +5 -5
- package/dist/chunks/{importer-ByCd2CAY.js.map → importer-BTbjwN10.js.map} +1 -1
- package/dist/chunks/{importer-BAlFKpHP.js → importer-CSmH218L.js} +6 -6
- package/dist/chunks/{importer-BAlFKpHP.js.map → importer-CSmH218L.js.map} +1 -1
- package/dist/chunks/{importer-D7xB8oVV.js → importer-DMgcD1wI.js} +5 -5
- package/dist/chunks/{importer-D7xB8oVV.js.map → importer-DMgcD1wI.js.map} +1 -1
- package/dist/chunks/{importer-CaLIrkjL.js → importer-DoSz--Ip.js} +9 -9
- package/dist/chunks/importer-DoSz--Ip.js.map +1 -0
- package/dist/chunks/{importer-rjFCmKfx.js → importer-DtKPzhVp.js} +5 -5
- package/dist/chunks/importer-DtKPzhVp.js.map +1 -0
- package/dist/chunks/{json-elements-CkC87El2.js → json-elements-CxJF-Szz.js} +6 -6
- package/dist/chunks/json-elements-CxJF-Szz.js.map +1 -0
- package/dist/chunks/{ontology-export-BRErBO6J.js → ontology-export-p1PsPenq.js} +2 -2
- package/dist/chunks/{ontology-export-BRErBO6J.js.map → ontology-export-p1PsPenq.js.map} +1 -1
- package/dist/chunks/{records-DwfSjH8c.js → records-BrfHycmg.js} +2 -2
- package/dist/chunks/{records-DwfSjH8c.js.map → records-BrfHycmg.js.map} +1 -1
- package/dist/chunks/{text-BEEWD-G1.js → text-BD-TzLNm.js} +4 -4
- package/dist/chunks/text-BD-TzLNm.js.map +1 -0
- package/dist/csv.js +4 -4
- package/dist/cx.js +1 -1
- package/dist/cx2.js +2 -2
- package/dist/cys.js +1 -1
- package/dist/dot.js +1 -1
- package/dist/gexf.js +2 -2
- package/dist/gml.js +10 -10
- package/dist/gml.js.map +1 -1
- package/dist/graph-io.js +26 -26
- package/dist/graphml.js +2 -2
- package/dist/json.js +1 -1
- package/dist/neo4j.js +3 -3
- package/dist/obo.js +1 -1
- package/dist/pajek.js +1 -1
- package/dist/src/common/attributes.js +1 -1
- package/dist/src/common/attributes.js.map +1 -1
- package/dist/src/common/declared-types.js +2 -2
- package/dist/src/common/declared-types.js.map +1 -1
- package/dist/src/common/escape.js +2 -2
- package/dist/src/common/escape.js.map +1 -1
- package/dist/src/common/ids.js +1 -1
- package/dist/src/common/ids.js.map +1 -1
- package/dist/src/common/json-elements.d.ts.map +1 -1
- package/dist/src/common/json-elements.js +3 -3
- package/dist/src/common/json-elements.js.map +1 -1
- package/dist/src/common/temporal.js +3 -3
- package/dist/src/common/temporal.js.map +1 -1
- package/dist/src/common/text.js +2 -2
- package/dist/src/common/text.js.map +1 -1
- package/dist/src/common/xml.js +2 -2
- package/dist/src/common/xml.js.map +1 -1
- package/dist/src/formats/cx/importer.js +3 -3
- package/dist/src/formats/cx/importer.js.map +1 -1
- package/dist/src/formats/cx2/importer.js +1 -1
- package/dist/src/formats/cx2/importer.js.map +1 -1
- package/dist/src/formats/gml/exporter.js +1 -1
- package/dist/src/formats/gml/exporter.js.map +1 -1
- package/dist/src/formats/gml/importer.js +2 -2
- package/dist/src/formats/gml/importer.js.map +1 -1
- package/dist/src/formats/gml/syntax.js +4 -4
- package/dist/src/formats/gml/syntax.js.map +1 -1
- package/dist/src/formats/graphml/importer.js +1 -1
- package/dist/src/formats/graphml/importer.js.map +1 -1
- package/dist/src/formats/json/exporter.js +1 -1
- package/dist/src/formats/json/exporter.js.map +1 -1
- package/dist/src/formats/pajek/importer.js +2 -2
- package/dist/src/formats/pajek/importer.js.map +1 -1
- package/dist/src/formats/pajek/syntax.d.ts.map +1 -1
- package/dist/src/formats/pajek/syntax.js +2 -2
- package/dist/src/formats/pajek/syntax.js.map +1 -1
- package/dist/src/formats/xgmml/values.js +1 -1
- package/dist/src/formats/xgmml/values.js.map +1 -1
- package/dist/xgmml.js +2 -2
- package/package.json +2 -2
- package/src/common/attributes.ts +1 -1
- package/src/common/declared-types.ts +2 -2
- package/src/common/escape.ts +2 -2
- package/src/common/ids.ts +1 -1
- package/src/common/json-elements.ts +3 -3
- package/src/common/temporal.ts +3 -3
- package/src/common/text.ts +2 -2
- package/src/common/xml.ts +2 -2
- package/src/formats/cx/importer.ts +3 -3
- package/src/formats/cx2/importer.ts +1 -1
- package/src/formats/gml/exporter.ts +1 -1
- package/src/formats/gml/importer.ts +2 -2
- package/src/formats/gml/syntax.ts +4 -4
- package/src/formats/graphml/importer.ts +1 -1
- package/src/formats/json/exporter.ts +1 -1
- package/src/formats/pajek/importer.ts +2 -2
- package/src/formats/pajek/syntax.ts +2 -3
- package/src/formats/xgmml/values.ts +1 -1
- package/dist/chunks/escape-CnTfa_y8.js.map +0 -1
- package/dist/chunks/export-ZucVKiU4.js.map +0 -1
- package/dist/chunks/importer-CaLIrkjL.js.map +0 -1
- package/dist/chunks/importer-DsNj_zoG.js.map +0 -1
- package/dist/chunks/importer-WPz-AUz8.js.map +0 -1
- package/dist/chunks/importer-rjFCmKfx.js.map +0 -1
- package/dist/chunks/json-elements-CkC87El2.js.map +0 -1
- package/dist/chunks/text-BEEWD-G1.js.map +0 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { GraphFormatError, INVALID_INDEX } from "@graphty/graph-format";
|
|
2
|
-
import { V as BAD_ASPECT_BLOCK_CODE, W as MULTI_ASPECT_FRAGMENT_CODE, Y as ASPECT_ORDER_CODE, j as COUNT_MISMATCH_CODE, Z as STATUS_FAILED_CODE, _ as STATUS_WARNING_CODE, b as plural, $ as agree, a0 as uniqueColumnName, C as COLUMN_RENAMED_CODE, a1 as declareResolved, a2 as JSON_NONSTANDARD_NUMBER_CODE, o as DUPLICATE_ATTRIBUTE_CODE, P as PRECISION_CODE, a3 as BAD_VALUE_CODE } from "./export-
|
|
3
|
-
import { t as trimTrailingZeros } from "./text-
|
|
4
|
-
const MAYBE_UNSAFE_INTEGER = new RegExp("(?<![0-9.])
|
|
2
|
+
import { V as BAD_ASPECT_BLOCK_CODE, W as MULTI_ASPECT_FRAGMENT_CODE, Y as ASPECT_ORDER_CODE, j as COUNT_MISMATCH_CODE, Z as STATUS_FAILED_CODE, _ as STATUS_WARNING_CODE, b as plural, $ as agree, a0 as uniqueColumnName, C as COLUMN_RENAMED_CODE, a1 as declareResolved, a2 as JSON_NONSTANDARD_NUMBER_CODE, o as DUPLICATE_ATTRIBUTE_CODE, P as PRECISION_CODE, a3 as BAD_VALUE_CODE } from "./export-Cbt4h_0n.js";
|
|
3
|
+
import { t as trimTrailingZeros } from "./text-BD-TzLNm.js";
|
|
4
|
+
const MAYBE_UNSAFE_INTEGER = new RegExp("(?<![0-9.])\\d{16}");
|
|
5
5
|
const MAYBE_INEXACT_EXPONENT = new RegExp(
|
|
6
6
|
[
|
|
7
7
|
/\d[eE]\+?0*(?:1[5-9]|[2-9]\d|[1-9]\d{2,})/,
|
|
@@ -18,7 +18,7 @@ const NONSTANDARD_TOKENS = [
|
|
|
18
18
|
["Infinity", Infinity],
|
|
19
19
|
["NaN", Number.NaN]
|
|
20
20
|
];
|
|
21
|
-
const INTEGER_LITERAL = /^-?(0|[1-9]
|
|
21
|
+
const INTEGER_LITERAL = /^-?(0|[1-9]\d*)$/;
|
|
22
22
|
const NUMBER_PARTS = /^(-?)(\d+)(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/;
|
|
23
23
|
function sentinelFor(text) {
|
|
24
24
|
let haystack = text;
|
|
@@ -916,7 +916,7 @@ function reportSharedBlock(report, event) {
|
|
|
916
916
|
);
|
|
917
917
|
}
|
|
918
918
|
}
|
|
919
|
-
const DECIMAL_INTEGER_TEXT = /^-?(0|[1-9]
|
|
919
|
+
const DECIMAL_INTEGER_TEXT = /^-?(0|[1-9]\d*)$/;
|
|
920
920
|
function cxId(raw, inexactLiteral2 = false) {
|
|
921
921
|
if (raw instanceof ExactInteger) {
|
|
922
922
|
return { id: raw.digits, note: "precision" };
|
|
@@ -1218,4 +1218,4 @@ export {
|
|
|
1218
1218
|
scanAspects as s,
|
|
1219
1219
|
zDecl as z
|
|
1220
1220
|
};
|
|
1221
|
-
//# sourceMappingURL=json-elements-
|
|
1221
|
+
//# sourceMappingURL=json-elements-CxJF-Szz.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json-elements-CxJF-Szz.js","sources":["../../src/common/json-elements.ts"],"sourcesContent":["/**\n * The JSON reading the two CX formats share (design section 1.0 of\n * design/graph-io/cytoscape-and-obo/design.md): the exact-integer rewrite (also used by the JSON\n * importer), a streaming scanner that walks a CX document's top-level array and hands over each\n * aspect element as soon as its closing brace arrives (section 1.2.5), and the CX id rule of\n * section 1.0.2.\n *\n * The scanner never holds the document as one string, so a file larger than the longest string a\n * JavaScript engine can hold is still read: it keeps the text of the element being read and\n * nothing else. Each element is parsed with `JSON.parse`; an integer literal beyond 2^53 is kept as\n * an ExactInteger (its digits) so an id never loses a digit.\n */\n\nimport {\n type ColumnDecl,\n type ColumnHandle,\n GraphFormatError,\n type GraphSink,\n INVALID_INDEX,\n type NodeId,\n} from \"@graphty/graph-format\";\n\nimport { declareResolved, uniqueColumnName } from \"./attributes.js\";\nimport {\n ASPECT_ORDER_CODE,\n BAD_ASPECT_BLOCK_CODE,\n BAD_VALUE_CODE,\n COLUMN_RENAMED_CODE,\n COUNT_MISMATCH_CODE,\n DUPLICATE_ATTRIBUTE_CODE,\n JSON_NONSTANDARD_NUMBER_CODE,\n MULTI_ASPECT_FRAGMENT_CODE,\n PRECISION_CODE,\n STATUS_FAILED_CODE,\n STATUS_WARNING_CODE,\n} from \"./codes.js\";\nimport { agree, plural } from \"./plural.js\";\nimport { type ImportReportBuilder } from \"./report.js\";\nimport { trimTrailingZeros } from \"./text.js\";\n\n// ============================================================ exact integers\n\n/**\n * A run of 16 digits not inside a fraction: the shortest integer literal that can exceed 2^53 (9007199254740992).\n * @category Plugin helpers\n */\nexport const MAYBE_UNSAFE_INTEGER = /(?<![0-9.])\\d{16}/;\n\n/**\n * A literal the double read for may not equal: an exponent of 15 or more (`9.007199254740993e15`,\n * `1e400`: an integer beyond 2^53 or an overflow), an exponent of -300 or less (`1e-400`: an\n * underflow to 0), or 16 or more digits split by a decimal point before an exponent\n * (`90071992547409.93e2`). MAYBE_UNSAFE_INTEGER sees none of them.\n * ponytail: a literal that underflows through 300+ leading fraction zeros and no exponent is not\n * gated; add a digit-count check if such files turn up.\n * @category Plugin helpers\n */\nexport const MAYBE_INEXACT_EXPONENT = new RegExp(\n [\n /\\d[eE]\\+?0*(?:1[5-9]|[2-9]\\d|[1-9]\\d{2,})/, // an exponent of 15 or more\n /\\d[eE]-0*(?:[3-9]\\d{2}|[1-9]\\d{3,})/, // an exponent of -300 or less\n /(?<![\\d.])(?=(?:\\d\\.?){16})\\d+\\.\\d+[eE]/, // 16 or more digits split by a decimal point\n ]\n .map((r) => r.source)\n .join(\"|\"),\n);\n\n/**\n * The prefix of the string a non-standard token or an exact integer is rewritten to (a NUL\n * character first, which no sensible attribute value starts with). A document that already holds\n * the text gets a numbered variant, so a genuine string is never revived as a number.\n */\nconst SENTINEL = `${String.fromCodePoint(0)}graph-io`;\n\n/** The non-standard tokens Python's json module writes, longest first so -Infinity wins over a bare minus. */\nconst NONSTANDARD_TOKENS: readonly (readonly [string, number])[] = [\n [\"-Infinity\", -Infinity],\n [\"Infinity\", Infinity],\n [\"NaN\", Number.NaN],\n];\n\n/** A JSON integer literal (no fraction, no exponent, no leading zero), as CANONICAL_INTEGER in common/ids.ts. */\nconst INTEGER_LITERAL = /^-?(0|[1-9]\\d*)$/;\n\n/** A JSON number literal, split into sign, integer digits, fraction digits and exponent. */\nconst NUMBER_PARTS = /^(-?)(\\d+)(?:\\.(\\d+))?(?:[eE]([+-]?\\d+))?$/;\n\n/** What rewriteNumbers() found. */\ninterface RewrittenNumbers {\n /** The rewritten text. */\n readonly text: string;\n /** The non-standard tokens seen (only when they were allowed). */\n readonly tokens: Set<string>;\n /** The integer literals beyond 2^53 that were quoted. */\n readonly bigIntegers: string[];\n /**\n * The literals with a fraction or an exponent that denote an integer beyond 2^53 a double cannot\n * hold (`9007199254740993.0`), and the finite literals that overflow to an infinity (`1e400`) or\n * underflow to 0 (`1e-400`):\n * read as the nearest double, which changes the value.\n */\n readonly inexact: string[];\n /** The JSON.parse reviver that turns the sentinel strings of this rewrite back into numbers. */\n readonly revive: (key: string, value: unknown) => unknown;\n /** The JSON.parse reviver that turns this rewrite's exact sentinels into ExactInteger. */\n readonly reviveExact: (key: string, value: unknown) => unknown;\n}\n\n/**\n * The sentinel prefix of one rewrite: SENTINEL with a colon, or a numbered variant when the document\n * already holds that one. A string can only decode to a NUL by escaping it (`\\u0000`), so when the\n * text holds that escape the escaped strings are decoded and searched too: any other escape in them\n * (`graph\\u002dio:`) would hide the sentinel from a search of the raw text.\n * @param text - the document text\n * @returns the prefix\n */\nfunction sentinelFor(text: string): string {\n let haystack = text;\n if (/\\\\u0000/i.test(text)) {\n const decoded: string[] = [];\n for (const [literal] of text.matchAll(/\"(?:[^\"\\\\]|\\\\.)*\"/g)) {\n if (literal.includes(\"\\\\\")) {\n decoded.push(decodeString(literal));\n }\n }\n haystack = `${decoded.join(\"\\n\")}\\n${text}`;\n }\n let k = 0;\n while (haystack.includes(`graph-io${k === 0 ? \"\" : String(k)}:`)) {\n k++;\n }\n return `${SENTINEL}${k === 0 ? \"\" : String(k)}:`;\n}\n\n/**\n * Decode one JSON string literal, or give it back as written when it is not valid (the parse then\n * reports the syntax error).\n * @param literal - the literal with its quotes\n * @returns the decoded value\n */\nfunction decodeString(literal: string): string {\n try {\n return String(JSON.parse(literal));\n } catch {\n return literal;\n }\n}\n\n/**\n * Whether a number literal with a fraction or an exponent reads back as another value: an integer\n * beyond 2^53 written with more significant digits than a double keeps, which the nearest double\n * misses, or a finite literal beyond the double range or a non-zero one below it.\n * @param literal - the literal as written\n * @returns true when the double read for it is not the value it denotes\n */\nfunction isInexactLiteral(literal: string): boolean {\n const value = Number(literal);\n if (!Number.isFinite(value)) {\n return true;\n }\n if (value === 0) {\n // a non-zero literal below the smallest double underflows to 0\n return /[1-9]/.test(literal.split(/[eE]/)[0]);\n }\n if (Number.isSafeInteger(value) || !Number.isInteger(value)) {\n return false;\n }\n const m = NUMBER_PARTS.exec(literal);\n if (m === null) {\n return false;\n }\n const digits = trimTrailingZeros(m[2] + (m[3] ?? \"\"));\n const exponent = Number(m[4] ?? \"0\") - (m[3] ?? \"\").length + ((m[2] + (m[3] ?? \"\")).length - digits.length);\n if (digits.replace(/^0+/, \"\").length <= 15 || exponent < 0) {\n // up to 15 significant digits the nearest double reads back as the same text (1e39 is the\n // float it says); a fraction that rounds to an integer is ordinary floating-point rounding\n return false;\n }\n const exact = BigInt(digits) * 10n ** BigInt(exponent);\n return exact !== BigInt(Math.abs(value));\n}\n\n/**\n * Rewrite the numbers JSON.parse cannot read exactly, outside strings and in value positions only:\n * NaN / Infinity / -Infinity become sentinel strings (when `nonstandard` is true), an integer\n * literal that is not a safe integer becomes a string of its digits (or, with `exactSentinel`, a\n * sentinel string the result's reviveExact turns into an ExactInteger). A container stack tells a\n * value position (after `:`, `[`, or `,` inside an array) from a key position, so `{NaN: 1}` stays\n * invalid. Literals with a fraction or an exponent that no double holds are listed, not rewritten.\n * @param text - the document text\n * @param options - which rewrites apply\n * @param options.nonstandard - rewrite NaN / Infinity / -Infinity (default true)\n * @param options.exactSentinel - quote big integers as sentinels instead of bare digits (default false)\n * @returns the rewritten text, what was found and the revivers of this rewrite\n * @category Plugin helpers\n */\nexport function rewriteNumbers(\n text: string,\n options: { readonly nonstandard?: boolean; readonly exactSentinel?: boolean } = {},\n): RewrittenNumbers {\n const nonstandard = options.nonstandard ?? true;\n const exactSentinel = options.exactSentinel ?? false;\n const sentinel = sentinelFor(text);\n const exactPrefix = `${sentinel}exact:`;\n const parts: string[] = [];\n const tokens = new Set<string>();\n const bigIntegers: string[] = [];\n const inexact: string[] = [];\n const arrays: boolean[] = [];\n let expectValue = true;\n let copied = 0;\n let i = 0;\n const n = text.length;\n while (i < n) {\n const ch = text[i];\n if (ch === '\"') {\n i++;\n while (i < n && text[i] !== '\"') {\n i += text[i] === \"\\\\\" ? 2 : 1;\n }\n i++;\n expectValue = false;\n continue;\n }\n if (ch === \"{\" || ch === \"[\") {\n arrays.push(ch === \"[\");\n expectValue = ch === \"[\";\n } else if (ch === \"}\" || ch === \"]\") {\n arrays.pop();\n expectValue = false;\n } else if (ch === \":\") {\n expectValue = true;\n } else if (ch === \",\") {\n expectValue = arrays.length > 0 && arrays[arrays.length - 1];\n } else if (expectValue && ch !== \" \" && ch !== \"\\t\" && ch !== \"\\n\" && ch !== \"\\r\") {\n expectValue = false;\n const token = nonstandard ? NONSTANDARD_TOKENS.find(([word]) => text.startsWith(word, i)) : undefined;\n let end = i;\n let replacement: string | null = null;\n if (token !== undefined) {\n end = i + token[0].length;\n tokens.add(token[0]);\n replacement = JSON.stringify(`${sentinel}${token[0]}`);\n } else if (ch === \"-\" || (ch >= \"0\" && ch <= \"9\")) {\n end = i + 1;\n while (end < n && \"0123456789+-.eE\".includes(text[end])) {\n end++;\n }\n const literal = text.slice(i, end);\n if (INTEGER_LITERAL.test(literal)) {\n if (!Number.isSafeInteger(Number(literal))) {\n bigIntegers.push(literal);\n replacement = exactSentinel ? JSON.stringify(`${exactPrefix}${literal}`) : `\"${literal}\"`;\n }\n } else if (isInexactLiteral(literal)) {\n inexact.push(literal);\n }\n }\n if (replacement !== null) {\n parts.push(text.slice(copied, i), replacement);\n copied = end;\n }\n i = Math.max(end, i + 1);\n continue;\n }\n i++;\n }\n parts.push(text.slice(copied));\n const revive = (_key: string, value: unknown): unknown => {\n if (typeof value === \"string\" && value.startsWith(sentinel)) {\n const found = NONSTANDARD_TOKENS.find(([word]) => word === value.slice(sentinel.length));\n return found === undefined ? value : found[1];\n }\n return value;\n };\n const reviveExact = (_key: string, value: unknown): unknown =>\n typeof value === \"string\" && value.startsWith(exactPrefix)\n ? new ExactInteger(value.slice(exactPrefix.length))\n : value;\n return { text: parts.join(\"\"), tokens, bigIntegers, inexact, revive, reviveExact };\n}\n\n/** One key repeated in a JSON object. */\ninterface DuplicateKey {\n /** The key. */\n readonly key: string;\n /** The UTF-16 offset of the repeated occurrence. */\n readonly offset: number;\n}\n\n/** Keys of one object compared pairwise up to this count; a wider object switches to a Set. */\nconst LINEAR_KEYS = 32;\n\n/**\n * The keys that occur twice in one object of a valid JSON text, which JSON.parse silently reduces\n * to the last value (RFC 8259 section 4: names SHOULD be unique). One pass over the characters\n * that jumps over strings; the keys of a small object are compared in place, without\n * slicing (the parse itself costs about as much as this scan, so it allocates nothing per key).\n * Keys are compared as written: `\"\\u0069d\"` and `\"id\"` are not recognized as one key.\n * @param text - a text JSON.parse accepted (or its rewrite)\n * @returns every repetition in document order\n * @category Plugin helpers\n */\nexport function findDuplicateKeys(text: string): DuplicateKey[] {\n const found: DuplicateKey[] = [];\n // per depth: the [start, end) of each key of the open object (reused), or -1 for an array\n const spans: number[][] = [];\n const wide: (Set<string> | null)[] = [];\n let depth = 0;\n const n = text.length;\n let at = 0;\n while (at < n) {\n const c = text.codePointAt(at);\n if (c === 123 || c === 91) {\n // { or [\n openContainer(spans, wide, depth, c === 91);\n depth++;\n } else if (c === 125 || c === 93) {\n depth--;\n } else if (c === 34) {\n const end = closingQuote(text, at + 1);\n const keys = depth > 0 ? spans[depth - 1] : null;\n // an array's span list starts with -1: its strings are values, never keys\n const isObjectKey = keys !== null && keys[0] !== -1 && isKey(text, end + 1);\n if (isObjectKey && isRepeated(text, at + 1, end, keys, wide, depth - 1)) {\n found.push({ key: text.slice(at + 1, end), offset: at });\n }\n at = end;\n }\n at++;\n }\n return found;\n}\n\n/**\n * Start the key list of a container just opened at a depth (reusing the list of an earlier one).\n * @param spans - the key spans per depth\n * @param wide - the key sets per depth, for wide objects\n * @param depth - the container's depth\n * @param isArray - whether it is an array, whose strings are never keys\n */\nfunction openContainer(spans: number[][], wide: (Set<string> | null)[], depth: number, isArray: boolean): void {\n if (spans.length === depth) {\n spans.push([]);\n wide.push(null);\n }\n spans[depth].length = 0;\n if (isArray) {\n spans[depth].push(-1);\n }\n wide[depth] = null;\n}\n\n/**\n * Whether a key repeats one already seen in its object, remembering it otherwise.\n * @param text - the text\n * @param start - the key's first character\n * @param end - the key's closing quote\n * @param keys - the spans of the object's keys so far\n * @param wide - the Set of each depth's keys once the object is wide\n * @param level - the object's depth\n * @returns true for a repetition\n */\nfunction isRepeated(\n text: string,\n start: number,\n end: number,\n keys: number[],\n wide: (Set<string> | null)[],\n level: number,\n): boolean {\n const set = wide[level];\n if (set !== null) {\n const key = text.slice(start, end);\n return set.has(key) || (set.add(key), false);\n }\n const length = end - start;\n for (let k = 0; k < keys.length; k += 2) {\n if (keys[k + 1] - keys[k] === length && sameText(text, keys[k], start, length)) {\n return true;\n }\n }\n keys.push(start, end);\n if (keys.length > 2 * LINEAR_KEYS) {\n const all = new Set<string>();\n for (let k = 0; k < keys.length; k += 2) {\n all.add(text.slice(keys[k], keys[k + 1]));\n }\n wide[level] = all;\n }\n return false;\n}\n\n/**\n * Whether two ranges of one text hold the same characters.\n * @param text - the text\n * @param a - the first range's start\n * @param b - the second range's start\n * @param length - the ranges' length\n * @returns true when equal\n */\nfunction sameText(text: string, a: number, b: number, length: number): boolean {\n for (let i = 0; i < length; i++) {\n if (text.codePointAt(a + i) !== text.codePointAt(b + i)) {\n return false;\n }\n }\n return true;\n}\n\n/**\n * The offset of the quote that closes a JSON string.\n * @param text - the text\n * @param from - the offset after the opening quote\n * @returns the closing quote's offset (the text length when there is none)\n */\nfunction closingQuote(text: string, from: number): number {\n for (let q = text.indexOf('\"', from); q >= 0; q = text.indexOf('\"', q + 1)) {\n let backslashes = 0;\n while (text.codePointAt(q - 1 - backslashes) === 92) {\n backslashes++;\n }\n if (backslashes % 2 === 0) {\n return q;\n }\n }\n return text.length;\n}\n\n/**\n * Whether the string that ends before an offset is an object key: a colon follows after whitespace.\n * @param text - the text\n * @param from - the offset after the closing quote\n * @returns true for a key\n */\nfunction isKey(text: string, from: number): boolean {\n let i = from;\n while (i < text.length && isSpace(text.codePointAt(i))) {\n i++;\n }\n return text.codePointAt(i) === 58;\n}\n\n/**\n * An integer literal beyond 2^53, kept as its exact digits (a CX id must never lose a digit).\n * @category Plugin helpers\n */\nexport class ExactInteger {\n /** The digits, with a leading minus for a negative value. */\n readonly digits: string;\n\n /**\n * Wrap the digits of an integer literal.\n * @param digits - the literal\n */\n constructor(digits: string) {\n this.digits = digits;\n }\n\n /**\n * The nearest number (JSON.stringify writes it as such).\n * @returns the number\n */\n toJSON(): number {\n return Number(this.digits);\n }\n}\n\n/**\n * Parse one JSON value, keeping integer literals beyond 2^53 as ExactInteger.\n * @param text - the JSON text\n * @returns the value and whether it may hold an ExactInteger; SyntaxError when it is not JSON\n * @category Plugin helpers\n */\nexport function parseExact(text: string): { readonly value: unknown; readonly exact: boolean } {\n if (!MAYBE_UNSAFE_INTEGER.test(text)) {\n return { value: JSON.parse(text) as unknown, exact: false };\n }\n const scan = rewriteNumbers(text, { nonstandard: false, exactSentinel: true });\n if (scan.bigIntegers.length === 0) {\n return { value: JSON.parse(text) as unknown, exact: false };\n }\n return { value: JSON.parse(scan.text, scan.reviveExact) as unknown, exact: true };\n}\n\n/**\n * A parsed value with every ExactInteger replaced by its nearest number, for metadata and for\n * values that are not ids.\n * @param value - the value\n * @param onPrecision - called with the digits of each integer that lost precision\n * @returns the plain JSON value\n * @category Plugin helpers\n */\nexport function plainJson(value: unknown, onPrecision?: (digits: string) => void): unknown {\n if (value instanceof ExactInteger) {\n onPrecision?.(value.digits);\n return Number(value.digits);\n }\n if (Array.isArray(value)) {\n return value.map((item) => plainJson(item, onPrecision));\n }\n if (typeof value === \"object\" && value !== null) {\n const out: Record<string, unknown> = {};\n for (const [key, item] of Object.entries(value)) {\n setOwn(out, key, plainJson(item, onPrecision));\n }\n return out;\n }\n return value;\n}\n\n/**\n * Set an own property, also for the key `__proto__` (which an assignment would turn into the\n * object's prototype, losing the entry).\n * @param target - the object\n * @param key - the key\n * @param value - the value\n * @category Plugin helpers\n */\nexport function setOwn(target: Record<string, unknown>, key: string, value: unknown): void {\n if (key === \"__proto__\") {\n Object.defineProperty(target, key, { value, enumerable: true, writable: true, configurable: true });\n } else {\n target[key] = value;\n }\n}\n\n/**\n * Parse a text with the bare tokens NaN / Infinity / -Infinity that Python's json writes.\n * @param text - the JSON text that JSON.parse refused\n * @returns the value, whether it may hold an ExactInteger and the tokens seen; null when the\n * tokens are not what made the text invalid\n */\nfunction parseNonstandard(\n text: string,\n): { readonly value: unknown; readonly exact: boolean; readonly tokens: ReadonlySet<string> } | null {\n if (!/NaN|Infinity/.test(text)) {\n return null;\n }\n const scan = rewriteNumbers(text, { nonstandard: true, exactSentinel: true });\n if (scan.tokens.size === 0) {\n return null;\n }\n try {\n const value = JSON.parse(scan.text, (key, raw) => scan.reviveExact(key, scan.revive(key, raw))) as unknown;\n return { value, exact: scan.bigIntegers.length > 0, tokens: scan.tokens };\n } catch {\n return null;\n }\n}\n\n/** A lone surrogate code unit: a high one not followed by a low one, or a low one not after a high one. */\n/** The escapes of the surrogate range, as a message writes them. */\nconst SURROGATE_ESCAPES = String.raw`\\uD800-\\uDFFF`;\n\nconst LONE_SURROGATE = /[\\ud800-\\udbff](?![\\udc00-\\udfff])|(?<![\\ud800-\\udbff])[\\udc00-\\udfff]/g;\n\n/** Text that may hold a surrogate: an escaped one, or a raw one (string input). */\nconst MAYBE_SURROGATE = /\\\\u[dD][89a-fA-F]|[\\ud800-\\udfff]/;\n\n/**\n * Replace every lone surrogate of a parsed value's strings and keys with U+FFFD, in place.\n * @param value - the parsed value\n * @param fixed - counts the strings repaired and names the keys two repaired keys collapse into\n * @param fixed.count - the count\n * @param fixed.collisions - a key one object holds twice once repaired (the later value is kept)\n * @returns the value (a string, or an object with a repaired key, is returned as a new value)\n */\nfunction repairSurrogates(value: unknown, fixed: { count: number; collisions: string[] }): unknown {\n if (typeof value === \"string\") {\n const repaired = value.replaceAll(LONE_SURROGATE, \"\\ufffd\");\n if (repaired !== value) {\n fixed.count++;\n }\n return repaired;\n }\n if (Array.isArray(value)) {\n for (let i = 0; i < value.length; i++) {\n value[i] = repairSurrogates(value[i], fixed);\n }\n return value;\n }\n if (isRecord(value)) {\n const keys = Object.keys(value);\n const repairedKeys = keys.map((key) => key.replaceAll(LONE_SURROGATE, \"\\ufffd\"));\n const renamed = repairedKeys.some((key, i) => key !== keys[i]);\n const out: Record<string, unknown> = renamed ? {} : value;\n keys.forEach((key, i) => {\n if (repairedKeys[i] !== key) {\n fixed.count++;\n }\n if (renamed && Object.hasOwn(out, repairedKeys[i])) {\n fixed.collisions.push(repairedKeys[i]);\n }\n setOwn(out, repairedKeys[i], repairSurrogates(value[key], fixed));\n });\n return out;\n }\n return value;\n}\n\n/**\n * The number of keys of a parsed value, at every depth.\n * @param value - the value\n * @returns the count\n */\nfunction keyCount(value: unknown): number {\n if (Array.isArray(value)) {\n return value.reduce<number>((n, item) => n + keyCount(item), 0);\n }\n if (isRecord(value)) {\n return Object.keys(value).reduce((n, key) => n + 1 + keyCount(value[key]), 0);\n }\n return 0;\n}\n\n/**\n * The first key an object of a JSON text holds twice (JSON.parse keeps the later value silently).\n * @param text - valid JSON text\n * @returns the key, or null\n */\nfunction duplicateKey(text: string): string | null {\n const stack: (Set<string> | null)[] = [];\n let i = 0;\n while (i < text.length) {\n const c = text[i];\n if (c === \"{\") {\n stack.push(new Set());\n } else if (c === \"[\") {\n stack.push(null);\n } else if (c === \"}\" || c === \"]\") {\n stack.pop();\n } else if (c === '\"') {\n const start = i;\n i = stringEnd(text, i + 1);\n const keys = stack.at(-1) ?? null;\n if (keys !== null && text[skipSpace(text, i + 1)] === \":\") {\n const key = JSON.parse(text.slice(start, i + 1)) as string;\n if (keys.has(key)) {\n return key;\n }\n keys.add(key);\n }\n }\n i++;\n }\n return null;\n}\n\n/**\n * The offset of the quote that ends a JSON string, skipping escaped characters.\n * @param text - the text\n * @param from - the offset after the opening quote\n * @returns the closing quote's offset, or the text length (or one past it) when there is none\n */\nfunction stringEnd(text: string, from: number): number {\n let i = from;\n while (i < text.length && text[i] !== '\"') {\n i += text[i] === \"\\\\\" ? 2 : 1;\n }\n return i;\n}\n\n/**\n * The index of the first character at or after `from` that is not JSON whitespace.\n * @param text - the text\n * @param from - the first index\n * @returns the index (text.length at the end)\n */\nfunction skipSpace(text: string, from: number): number {\n let i = from;\n while (i < text.length && isSpace(text.codePointAt(i))) {\n i++;\n }\n return i;\n}\n\n/** A key followed by its colon, for the cheap duplicate-key check. */\nconst KEY_COLON = /\"\\s*:/g;\n\n/**\n * The checks of a parsed element that JSON.parse cannot make, recorded in the report: lone\n * surrogates (replaced with U+FFFD, E_BAD_VALUE) and a key held twice by one object\n * (W_DUPLICATE_ATTRIBUTE; the later value is the one read, also for two keys that a repair makes one).\n * @param text - the element text\n * @param parsed - the parsed element\n * @param line - its line\n * @param report - the report\n * @returns the value, repaired\n */\nfunction checkParsed(text: string, parsed: unknown, line: number, report: ImportReportBuilder): unknown {\n let value = parsed;\n if (MAYBE_SURROGATE.test(text)) {\n const fixed = { count: 0, collisions: [] as string[] };\n value = repairSurrogates(value, fixed);\n for (const key of fixed.collisions) {\n report.warnOnce(\n \"validation-error\",\n DUPLICATE_ATTRIBUTE_CODE,\n `an object holds two keys that are the same key ${JSON.stringify(key)} once their lone surrogates are replaced with U+FFFD; the later value is read`,\n { line, element: key },\n `${DUPLICATE_ATTRIBUTE_CODE}:json:${key}`,\n );\n }\n if (fixed.count > 0) {\n report.error(\n \"validation-error\",\n BAD_VALUE_CODE,\n `${fixed.count} string${plural(fixed.count)} ${agree(fixed.count, \"holds\", \"hold\")} a lone surrogate (an unpaired ${SURROGATE_ESCAPES} escape); each is read with U+FFFD in its place`,\n { line },\n );\n }\n }\n if (typeof value === \"object\" && value !== null && (text.match(KEY_COLON)?.length ?? 0) > keyCount(value)) {\n const key = duplicateKey(text);\n if (key !== null) {\n report.warnOnce(\n \"validation-error\",\n DUPLICATE_ATTRIBUTE_CODE,\n `an object holds the key ${JSON.stringify(key)} twice; the later value is read`,\n { line, element: key },\n `${DUPLICATE_ATTRIBUTE_CODE}:json:${key}`,\n );\n }\n }\n return value;\n}\n\n// ============================================================ the streaming aspect scanner\n\n/**\n * A problem with the document's JSON; the importer turns it into a fatal E_SYNTAX or E_EMPTY_INPUT.\n * @category Plugin helpers\n */\nexport class JsonScanError extends Error {\n /** The 1-based line of the problem. */\n readonly line: number;\n\n /** Whether the document holds nothing but whitespace. */\n readonly empty: boolean;\n\n /**\n * Create the error.\n * @param message - what is wrong\n * @param line - the 1-based line\n * @param empty - whether the input is empty\n */\n constructor(message: string, line: number, empty = false) {\n super(message);\n this.name = \"JsonScanError\";\n this.line = line;\n this.empty = empty;\n }\n}\n\n/**\n * One thing the scanner found in a CX document.\n * @category Plugin helpers\n */\nexport type AspectEvent =\n | {\n /**\n * A top-level value that is not an array: a scalar document, parsed; an object is not\n * read at all (object true, value undefined), however large it is.\n */\n readonly kind: \"root\";\n readonly value: unknown;\n readonly object: boolean;\n readonly line: number;\n }\n | {\n /** A member `{\"<aspect>\": [` whose elements follow one by one. */\n readonly kind: \"block\";\n readonly aspect: string;\n readonly block: number;\n /** Whether the aspect is not the member's first key (`{\"nodes\": [...], \"edges\": [...]}`). */\n readonly shared: boolean;\n readonly line: number;\n }\n | {\n /** One element of the current block, parsed. */\n readonly kind: \"element\";\n readonly aspect: string;\n readonly block: number;\n readonly value: unknown;\n /** Whether the value may hold an ExactInteger. */\n readonly exact: boolean;\n /** The element's JSON text (for lexical checks of its ids). */\n readonly text: string;\n readonly line: number;\n }\n | {\n /** The keys of a block member whose values are not arrays (`{\"nodes\": [...], \"x\": 1}`, in any order); skipped. */\n readonly kind: \"extraKeys\";\n readonly aspect: string;\n readonly block: number;\n readonly keys: readonly string[];\n readonly line: number;\n }\n | {\n /**\n * An element, or a member, nested deeper than MAX_ELEMENT_DEPTH: not parsed, so nothing\n * downstream recurses into it (aspect: the block's aspect, null for a member).\n */\n readonly kind: \"deep\";\n readonly aspect: string | null;\n readonly block: number;\n readonly depth: number;\n readonly line: number;\n }\n | {\n /** Any other member of the top-level array (a CX2 descriptor, `{\"ndexStatus\": {...}}`, `1`), parsed. */\n readonly kind: \"member\";\n readonly block: number;\n readonly value: unknown;\n readonly exact: boolean;\n /** The member's JSON text (for lexical checks of its ids). */\n readonly text: string;\n readonly line: number;\n };\n\n/**\n * Whether a character code is whitespace to JSON.\n * @param c - the character code\n * @returns true for space, line feed, carriage return and tab\n */\nconst isSpace = (c: number | undefined): boolean => c === 32 || c === 10 || c === 13 || c === 9;\n\n/**\n * Whether a character code ends a bare scalar (number, true, false, null).\n * @param c - the character code\n * @returns true for whitespace, a comma, a closing bracket or brace, or a colon\n */\nconst endsScalar = (c: number): boolean => isSpace(c) || c === 44 || c === 93 || c === 125 || c === 58;\n\nconst QUOTE_OR_BACKSLASH = /[\"\\\\]/g;\n\n/**\n * The deepest nesting of an element the scanner parses. graph-format refuses JSON values (a json\n * cell, meta.extra) nested deeper than 256 levels, and a kept element sits a few levels down\n * meta.extra; a deeper element is reported instead, before anything recurses into it.\n */\nconst MAX_ELEMENT_DEPTH = 200;\n\n/**\n * A cursor over text chunks with capture: the text of the value being read is kept across chunk\n * boundaries as a list of parts, so a long element costs linear time.\n */\nclass ChunkCursor {\n private readonly iterator: AsyncIterator<string>;\n\n private buf = \"\";\n\n /** The read position in buf. */\n pos = 0;\n\n /** The line number of buf's first character. */\n private linesBefore = 1;\n\n private parts: string[] | null = null;\n\n private captureStart = 0;\n\n /** The deepest nesting the last skipValue() reached. */\n deepest = 0;\n\n /**\n * Wrap text chunks.\n * @param chunks - the decoded text\n */\n constructor(chunks: AsyncIterable<string>) {\n this.iterator = chunks[Symbol.asyncIterator]();\n }\n\n /**\n * Read the next chunk once the current one is consumed.\n * @returns false at the end of the input\n */\n async fill(): Promise<boolean> {\n if (this.parts !== null) {\n this.parts.push(this.buf.slice(this.captureStart));\n this.captureStart = 0;\n }\n this.linesBefore += countNewlines(this.buf, 0, this.buf.length);\n const endsWithCr = this.buf.endsWith(\"\\r\");\n for (;;) {\n const next = await this.iterator.next();\n if (next.done === true) {\n this.buf = \"\";\n this.pos = 0;\n return false;\n }\n if (next.value.length > 0) {\n if (endsWithCr && next.value.startsWith(\"\\n\")) {\n // a CR LF split across two chunks is one line break, counted with the CR\n this.linesBefore--;\n }\n this.buf = next.value;\n this.pos = 0;\n return true;\n }\n }\n }\n\n /**\n * The 1-based line of the read position.\n * @returns the line\n */\n line(): number {\n return this.linesBefore + countNewlines(this.buf, 0, Math.min(this.pos, this.buf.length));\n }\n\n /**\n * The text from the read position to the end of the current chunk, at most `length` characters.\n * @param length - the most characters\n * @returns the text\n */\n ahead(length: number): string {\n return this.buf.slice(this.pos, this.pos + length);\n }\n\n /**\n * Skip whitespace and return the next character without consuming it.\n * @returns the character, or \"\" at the end of the input\n */\n async peek(): Promise<string> {\n for (;;) {\n while (this.pos < this.buf.length && isSpace(this.buf.charCodeAt(this.pos))) {\n this.pos++;\n }\n if (this.pos < this.buf.length) {\n return this.buf[this.pos];\n }\n if (!(await this.fill())) {\n return \"\";\n }\n }\n }\n\n /** Start keeping the text from the read position. */\n beginCapture(): void {\n this.parts = [];\n this.captureStart = this.pos;\n }\n\n /**\n * Stop keeping text.\n * @returns the text kept since beginCapture()\n */\n endCapture(): string {\n const parts = this.parts ?? [];\n parts.push(this.buf.slice(this.captureStart, this.pos));\n this.parts = null;\n return parts.length === 1 ? parts[0] : parts.join(\"\");\n }\n\n /** Drop the capture without building its text. */\n dropCapture(): void {\n this.parts = null;\n }\n\n /**\n * Advance past one JSON value starting at the read position (which holds its first\n * character), tracking strings and nesting only; the value is validated when it is parsed.\n * @param startDepth - the nesting depth already entered (1 when the opening brace was consumed)\n */\n async skipValue(startDepth = 0): Promise<void> {\n let depth = startDepth;\n this.deepest = depth;\n if (depth === 0) {\n const c = this.buf.charCodeAt(this.pos);\n if (c === 34) {\n this.pos++;\n await this.skipString();\n return;\n }\n if (c !== 123 && c !== 91) {\n await this.skipScalar();\n return;\n }\n }\n for (;;) {\n if (this.pos >= this.buf.length && !(await this.fill())) {\n throw new JsonScanError(\"the document ends inside a value\", this.line());\n }\n const c = this.buf.charCodeAt(this.pos);\n this.pos++;\n if (c === 34) {\n await this.skipString();\n } else if (c === 123 || c === 91) {\n depth++;\n if (depth > this.deepest) {\n this.deepest = depth;\n }\n } else if (c === 125 || c === 93) {\n depth--;\n if (depth === 0) {\n return;\n }\n }\n }\n }\n\n /** Advance past the rest of a string whose opening quote was consumed. */\n private async skipString(): Promise<void> {\n for (;;) {\n QUOTE_OR_BACKSLASH.lastIndex = this.pos;\n const found = QUOTE_OR_BACKSLASH.exec(this.buf);\n if (found === null) {\n this.pos = this.buf.length;\n if (!(await this.fill())) {\n throw new JsonScanError(\"the document ends inside a string\", this.line());\n }\n continue;\n }\n this.pos = found.index + 1;\n if (found[0] === '\"') {\n return;\n }\n // a backslash: skip the escaped character, which may be in the next chunk\n if (this.pos >= this.buf.length && !(await this.fill())) {\n throw new JsonScanError(\"the document ends inside a string\", this.line());\n }\n this.pos++;\n }\n }\n\n /** Advance past a bare scalar (a number, true, false, null or a stray word). */\n private async skipScalar(): Promise<void> {\n for (;;) {\n while (this.pos < this.buf.length && !endsScalar(this.buf.charCodeAt(this.pos))) {\n this.pos++;\n }\n if (this.pos < this.buf.length || !(await this.fill())) {\n return;\n }\n }\n }\n\n /**\n * Read one JSON string literal at the read position (its opening quote).\n * @returns the decoded string\n */\n async readString(): Promise<string> {\n this.beginCapture();\n this.pos++;\n await this.skipString();\n const literal = this.endCapture();\n try {\n return JSON.parse(literal) as string;\n } catch (err) {\n throw new JsonScanError(`invalid string: ${messageOf(err)}`, this.line());\n }\n }\n}\n\n/**\n * The number of line breaks in a slice of a string: LF, CR LF and a CR alone (old Mac files).\n * @param text - the string\n * @param from - the first index\n * @param to - one past the last index\n * @returns the count\n */\nfunction countNewlines(text: string, from: number, to: number): number {\n let count = 0;\n let i = text.indexOf(\"\\n\", from);\n while (i >= 0 && i < to) {\n count++;\n i = text.indexOf(\"\\n\", i + 1);\n }\n i = text.indexOf(\"\\r\", from);\n while (i >= 0 && i < to) {\n if (text[i + 1] !== \"\\n\") {\n count++;\n }\n i = text.indexOf(\"\\r\", i + 1);\n }\n return count;\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/**\n * Parse a captured value, turning a parse failure into a JsonScanError at its line. With a report,\n * the bare tokens NaN / Infinity / -Infinity are read as numbers (W_JSON_NONSTANDARD_NUMBER), and\n * lone surrogates and repeated keys are recorded (checkParsed()).\n * @param text - the value text\n * @param line - the line the value starts on\n * @param report - the report, or null to only parse\n * @returns the value and whether it may hold an ExactInteger\n */\nfunction parseAt(\n text: string,\n line: number,\n report: ImportReportBuilder | null,\n): { readonly value: unknown; readonly exact: boolean } {\n let parsed: { readonly value: unknown; readonly exact: boolean };\n try {\n parsed = parseExact(text);\n } catch (err) {\n const recovered = report === null ? null : parseNonstandard(text);\n if (recovered === null) {\n throw new JsonScanError(`invalid JSON: ${messageOf(err)}`, line);\n }\n report?.warnOnce(\n \"coercion\",\n JSON_NONSTANDARD_NUMBER_CODE,\n `the document uses the non-standard token${plural(recovered.tokens.size)} ${[...recovered.tokens].join(\", \")}, which strict JSON does not allow; read as numbers`,\n { line },\n );\n parsed = recovered;\n }\n if (report !== null) {\n parsed = { ...parsed, value: checkParsed(text, parsed.value, line, report) };\n }\n return parsed;\n}\n\n/**\n * What a document that does not start with \"[\" looks like, for the syntax error: HTML or XML (an\n * error page saved under the file's name), a ZIP archive, or nothing in particular.\n * @param head - the first characters\n * @returns a sentence to append, or \"\"\n */\nfunction notJsonHint(head: string): string {\n if (head.startsWith(\"<\")) {\n return \"; the input looks like HTML or XML (an error page saved as the file?), not JSON\";\n }\n if (head.startsWith(\"PK\\u0003\\u0004\")) {\n return \"; the input is a ZIP archive (a Cytoscape session .cys is read by the cys importer), not JSON\";\n }\n return \"\";\n}\n\n/**\n * Walk a CX document (CX1 or CX2): a top-level array of members, each normally a one-key object\n * `{\"<aspect>\": [elements]}`. The elements of such a block are parsed and yielded one at a time;\n * any other member is parsed whole and yielded as a \"member\". A document that is not an array is\n * yielded as one \"root\" event (an object without reading it). Syntax errors throw JsonScanError.\n * @param chunks - the decoded text\n * @param report - where NaN tokens, lone surrogates and repeated keys are recorded (parseAt()); null to only parse\n * @yields the events in document order\n * @returns nothing\n */\nexport async function* scanAspects(\n chunks: AsyncIterable<string>,\n report: ImportReportBuilder | null = null,\n): AsyncGenerator<AspectEvent, void, undefined> {\n const cur = new ChunkCursor(chunks);\n const first = await cur.peek();\n if (first === \"\") {\n throw new JsonScanError(\"the input is empty\", 1, true);\n }\n const hint = notJsonHint(cur.ahead(16));\n if (hint === \"\" && cur.ahead(8).includes(String.fromCodePoint(0))) {\n throw new JsonScanError(\n 'the input holds NUL characters: UTF-16 without a byte order mark (pass the encoding option, such as \"utf-16le\"), or binary data; not JSON',\n cur.line(),\n );\n }\n if (first === \"[\") {\n cur.pos++;\n yield* members(cur, report);\n return;\n }\n const line = cur.line();\n if (first === \"{\") {\n yield { kind: \"root\", value: undefined, object: true, line };\n return;\n }\n yield { kind: \"root\", value: await scalarRoot(cur, line, hint), object: false, line };\n}\n\n/**\n * Read a document that is neither an array nor an object: one value, and nothing after it.\n * @param cur - the cursor at the value\n * @param line - the value's line\n * @param hint - what the input looks like when it is not JSON, for the error\n * @returns the value\n */\nasync function scalarRoot(cur: ChunkCursor, line: number, hint: string): Promise<unknown> {\n cur.beginCapture();\n await cur.skipValue();\n let value: unknown;\n try {\n ({ value } = parseAt(cur.endCapture(), line, null));\n } catch (err) {\n if (err instanceof JsonScanError && hint !== \"\") {\n throw new JsonScanError(`${err.message}${hint}`, err.line);\n }\n throw err;\n }\n if ((await cur.peek()) !== \"\") {\n throw new JsonScanError(\"unexpected text after the document\", cur.line());\n }\n return value;\n}\n\n/**\n * Read the members of the top-level array, and check that nothing follows it.\n * @param cur - the cursor after the opening bracket\n * @param report - the report of parseAt(), or null\n * @yields the members' events\n * @returns nothing\n */\nasync function* members(\n cur: ChunkCursor,\n report: ImportReportBuilder | null,\n): AsyncGenerator<AspectEvent, void, undefined> {\n let block = 0;\n let next = await cur.peek();\n if (next === \"]\") {\n cur.pos++;\n }\n while (next !== \"]\") {\n yield* member(cur, block, report);\n block++;\n next = await cur.peek();\n if (next !== \",\" && next !== \"]\") {\n throw new JsonScanError(\n next === \"\" ? \"the document ends before its closing bracket\" : `expected \",\" or \"]\", found \"${next}\"`,\n cur.line(),\n );\n }\n cur.pos++;\n }\n if ((await cur.peek()) !== \"\") {\n throw new JsonScanError(\"unexpected text after the closing bracket\", cur.line());\n }\n}\n\n/**\n * Read one member of the top-level array.\n * @param cur - the cursor at the member's first character\n * @param block - the member's position among the members\n * @param report - the report of parseAt(), or null\n * @yields the member's events\n * @returns nothing\n */\nasync function* member(\n cur: ChunkCursor,\n block: number,\n report: ImportReportBuilder | null,\n): AsyncGenerator<AspectEvent, void, undefined> {\n const c = await cur.peek();\n const line = cur.line();\n if (c === \"\" || c === \"]\" || c === \",\") {\n throw new JsonScanError(c === \"\" ? \"the document ends inside its array\" : `unexpected \"${c}\"`, line);\n }\n cur.beginCapture();\n if (c !== \"{\") {\n await cur.skipValue();\n yield wholeMember(cur, block, line, report);\n return;\n }\n cur.pos++;\n if ((await cur.peek()) !== '\"') {\n // `{}` or not JSON: parse the whole member so a syntax error is reported as such\n await cur.skipValue(1);\n yield wholeMember(cur, block, line, report);\n return;\n }\n // every array-valued key is a block whose elements stream, whatever the key order; any other\n // value is kept as text, so a member without an array is parsed whole (a CX2 descriptor, a\n // one-object aspect) and one with an array names its other keys (extraKeys), skipped\n const outer = cur.endCapture();\n const firstLine = cur.line();\n const keys: MemberKeys = { others: [], firstBlock: null, deep: 0 };\n let next = \",\";\n let index = 0;\n while (next === \",\") {\n const key = await readKey(cur);\n yield* keyValue(cur, key, index, block, keys, report);\n index++;\n next = await cur.peek();\n if (next !== \",\" && next !== \"}\") {\n throw new JsonScanError(\n next === \"\" ? \"the document ends inside a member\" : `expected \",\" or \"}\" after the key \"${key.name}\"`,\n cur.line(),\n );\n }\n cur.pos++;\n }\n yield* memberEnd(keys, block, line, { outer, firstLine }, report);\n}\n\n/** What one-object member's keys held: the non-array values as text, the first block, the deepest value. */\ninterface MemberKeys {\n readonly others: { key: string; text: string | null; line: number }[];\n firstBlock: string | null;\n deep: number;\n}\n\n/**\n * The event of a member read whole (its capture already taken): the member, or \"deep\" when it\n * nests too deep to parse.\n * @param cur - the cursor after the member\n * @param block - the member's position among the members\n * @param line - the member's line\n * @param report - the report of parseAt(), or null\n * @returns the event\n */\nfunction wholeMember(cur: ChunkCursor, block: number, line: number, report: ImportReportBuilder | null): AspectEvent {\n if (cur.deepest > MAX_ELEMENT_DEPTH) {\n cur.dropCapture();\n return { kind: \"deep\", aspect: null, block, depth: cur.deepest, line };\n }\n const text = cur.endCapture();\n const parsed = parseAt(text, line, report);\n return { kind: \"member\", block, value: parsed.value, exact: parsed.exact, text, line };\n}\n\n/**\n * Read a member's key and the colon after it.\n * @param cur - the cursor at the key\n * @returns the key and its line\n */\nasync function readKey(cur: ChunkCursor): Promise<{ name: string; line: number }> {\n if ((await cur.peek()) !== '\"') {\n throw new JsonScanError(\"expected a key\", cur.line());\n }\n const line = cur.line();\n const name = await cur.readString();\n if ((await cur.peek()) !== \":\") {\n throw new JsonScanError(`expected \":\" after the key \"${name}\"`, cur.line());\n }\n cur.pos++;\n return { name, line };\n}\n\n/**\n * Read one key's value: an array is a block whose elements stream; any other value is kept as text\n * (or, when it nests too deep to parse, only its depth).\n * @param cur - the cursor at the value\n * @param key - the key\n * @param key.name - its name\n * @param key.line - its line\n * @param index - the key's position in the member\n * @param block - the member's position among the members\n * @param keys - what the member's keys held so far\n * @param report - the report of parseAt(), or null\n * @yields the block's events\n * @returns nothing\n */\nasync function* keyValue(\n cur: ChunkCursor,\n key: { name: string; line: number },\n index: number,\n block: number,\n keys: MemberKeys,\n report: ImportReportBuilder | null,\n): AsyncGenerator<AspectEvent, void, undefined> {\n if ((await cur.peek()) === \"[\") {\n cur.pos++;\n yield { kind: \"block\", aspect: key.name, block, shared: index > 0, line: key.line };\n keys.firstBlock ??= key.name;\n yield* blockElements(cur, key.name, block, report);\n return;\n }\n cur.beginCapture();\n await cur.skipValue();\n // the member's own brace is one level more\n if (cur.deepest + 1 > MAX_ELEMENT_DEPTH) {\n // never parse (recursively) what no one reads\n cur.dropCapture();\n keys.deep = Math.max(keys.deep, cur.deepest + 1);\n keys.others.push({ key: key.name, text: null, line: key.line });\n } else {\n keys.others.push({ key: key.name, text: cur.endCapture(), line: key.line });\n }\n}\n\n/**\n * The events after a one-object member's keys: with a block, its other keys (checked, then named\n * as extraKeys); without one, the member parsed whole from its kept text.\n * @param keys - what the member's keys held\n * @param block - the member's position among the members\n * @param line - the member's line\n * @param start - the member's opening text and the line after it\n * @param start.outer - the text up to the first key\n * @param start.firstLine - the line of the first key\n * @param report - the report of parseAt(), or null\n * @yields the events\n * @returns nothing\n */\nfunction* memberEnd(\n keys: MemberKeys,\n block: number,\n line: number,\n start: { outer: string; firstLine: number },\n report: ImportReportBuilder | null,\n): Generator<AspectEvent, void, undefined> {\n const { others, firstBlock, deep } = keys;\n if (firstBlock !== null) {\n for (const other of others) {\n if (other.text !== null) {\n parseAt(other.text, other.line, null);\n }\n }\n if (others.length > 0) {\n yield {\n kind: \"extraKeys\",\n aspect: firstBlock,\n block,\n keys: others.map((o) => o.key),\n line: others[0].line,\n };\n }\n return;\n }\n if (deep > 0) {\n yield { kind: \"deep\", aspect: others[0].key, block, depth: deep, line };\n return;\n }\n const members = others.map((o) => [JSON.stringify(o.key), o.text ?? \"\"].join(\":\"));\n const text = `${start.outer}${members.join(\",\")}}`;\n const parsed = parseAt(text, start.firstLine, report);\n yield { kind: \"member\", block, value: parsed.value, exact: parsed.exact, text, line };\n}\n\n/**\n * Read the elements of a block whose opening bracket was consumed, through its closing bracket.\n * @param cur - the cursor after the opening bracket\n * @param aspect - the block's aspect\n * @param block - the member's position among the members\n * @param report - the report of parseAt(), or null\n * @yields an element (or deep) event per element\n * @returns nothing\n */\nasync function* blockElements(\n cur: ChunkCursor,\n aspect: string,\n block: number,\n report: ImportReportBuilder | null,\n): AsyncGenerator<AspectEvent, void, undefined> {\n if ((await cur.peek()) === \"]\") {\n cur.pos++;\n return;\n }\n for (;;) {\n const e = await cur.peek();\n if (e === \"\") {\n throw new JsonScanError(`the document ends inside the \"${aspect}\" block`, cur.line());\n }\n const elementLine = cur.line();\n cur.beginCapture();\n await cur.skipValue();\n if (cur.deepest > MAX_ELEMENT_DEPTH) {\n cur.dropCapture();\n yield { kind: \"deep\", aspect, block, depth: cur.deepest, line: elementLine };\n } else {\n const text = cur.endCapture();\n const parsed = parseAt(text, elementLine, report);\n yield {\n kind: \"element\",\n aspect,\n block,\n value: parsed.value,\n exact: parsed.exact,\n text,\n line: elementLine,\n };\n }\n const next = await cur.peek();\n if (next === \",\") {\n cur.pos++;\n continue;\n }\n if (next === \"]\") {\n cur.pos++;\n return;\n }\n throw new JsonScanError(\n next === \"\"\n ? `the document ends inside the \"${aspect}\" block`\n : `expected \",\" or \"]\" in the \"${aspect}\" block, found \"${next}\"`,\n cur.line(),\n );\n }\n}\n\n/**\n * Report an element or member the scanner refused for its depth (E_BAD_ASPECT_BLOCK; skipped).\n * @param report - the report\n * @param event - the \"deep\" event\n * @category Plugin helpers\n */\nexport function reportTooDeep(report: ImportReportBuilder, event: Extract<AspectEvent, { kind: \"deep\" }>): void {\n report.error(\n \"parse-error\",\n BAD_ASPECT_BLOCK_CODE,\n `${event.aspect === null ? \"a member of the document\" : `an element of \"${event.aspect}\"`} is nested ${event.depth} levels deep, more than the ${MAX_ELEMENT_DEPTH} a graph keeps; skipped`,\n { line: event.line, element: event.aspect },\n );\n}\n\n/**\n * The precision callback of plainJson() for an aspect kept verbatim in the metadata: W_PRECISION\n * once, since the digits stored there are not the file's.\n * @param report - the report\n * @param where - where the aspect is kept (meta.extra.cx, ...)\n * @returns the callback\n * @category Plugin helpers\n */\nexport function keptPrecision(report: ImportReportBuilder, where: string): (digits: string) => void {\n return (digits) => {\n report.warnOnce(\n \"precision\",\n PRECISION_CODE,\n `an aspect kept in ${where} holds ${digits}, beyond 2^53; it is kept as the nearest double`,\n { element: where },\n `${PRECISION_CODE}:kept`,\n );\n };\n}\n\n/**\n * Warn once (W_MULTI_ASPECT_FRAGMENT) about a block that shares its array member with another\n * aspect (`{\"nodes\": [...], \"edges\": [...]}`); a block of its own needs nothing.\n * @param report - the report\n * @param event - the \"block\" event\n * @category Plugin helpers\n */\nexport function reportSharedBlock(report: ImportReportBuilder, event: Extract<AspectEvent, { kind: \"block\" }>): void {\n if (event.shared) {\n report.warnOnce(\n \"coercion\",\n MULTI_ASPECT_FRAGMENT_CODE,\n `the \"${event.aspect}\" aspect shares an array member with another aspect; each is read as its own fragment`,\n { line: event.line, element: event.aspect },\n );\n }\n}\n\n// ============================================================ the CX id rule (design section 1.0.2)\n\n/** How an id was spelled, when it was not a plain safe integer. */\ntype CxIdNote = \"text\" | \"precision\" | null;\n\n/** A CX id, decided per id: a safe integer is a number, a larger one its exact digits. */\ninterface CxId {\n /** The node or edge id. */\n readonly id: NodeId;\n /** \"text\": spelled as a string or a non-integer literal (W_ID_TEXT_TYPE); \"precision\": beyond 2^53 (W_PRECISION). */\n readonly note: CxIdNote;\n}\n\nconst DECIMAL_INTEGER_TEXT = /^-?(0|[1-9]\\d*)$/;\n\n/**\n * Apply the CX id rule (design section 1.0.2) to a parsed value: a safe integer is the id; an\n * integer beyond 2^53 is its exact digit string; a string spelling a decimal integer is that\n * integer (as Jackson coerces it); anything else is E_INVALID_ID.\n * @param raw - the parsed value\n * @param inexactLiteral - whether the number was written as a non-integer literal (`5.0`, `1e3`)\n * @returns the id and how it was spelled\n * @category Plugin helpers\n */\nexport function cxId(raw: unknown, inexactLiteral = false): CxId {\n if (raw instanceof ExactInteger) {\n return { id: raw.digits, note: \"precision\" };\n }\n if (typeof raw === \"number\") {\n if (Number.isSafeInteger(raw)) {\n return { id: raw === 0 ? 0 : raw, note: inexactLiteral ? \"text\" : null };\n }\n throw invalidCxId(raw, Number.isInteger(raw) ? \"an integer beyond 2^53 written inexactly\" : \"not an integer\");\n }\n if (typeof raw === \"string\" && raw !== \"-0\" && DECIMAL_INTEGER_TEXT.test(raw)) {\n const n = Number(raw);\n return Number.isSafeInteger(n) ? { id: n, note: \"text\" } : { id: raw, note: \"precision\" };\n }\n throw invalidCxId(raw, \"a CX id is an integer\");\n}\n\n/**\n * The E_INVALID_ID error of a rejected CX id.\n * @param raw - the value\n * @param reason - why\n * @returns the error\n */\nfunction invalidCxId(raw: unknown, reason: string): GraphFormatError {\n const shown = typeof raw === \"string\" || typeof raw === \"number\" ? JSON.stringify(raw) : typeof raw;\n return new GraphFormatError(\"E_INVALID_ID\", `invalid id ${raw === null ? \"null\" : shown}: ${reason}`, {\n reason,\n });\n}\n\n/** A number literal at lastIndex (sticky). */\nconst NUMBER_LITERAL = /-?\\d[\\d.eE+-]*/y;\n\n/**\n * Whether the element text writes a top-level key's number as a non-integer literal (`\"id\": 5.0`,\n * `\"@id\": 1e3`). A lexical check, so the parsed value (5) cannot tell. Only a key of the element\n * itself counts, not one nested in its `v` (where `s` and `id` are ordinary attribute names).\n * @param text - the element's JSON text\n * @param key - the key\n * @param keyDepth - the nesting depth of the element's own keys: 1, or 2 for an element written as\n * a member's single object (`{\"nodes\": {\"@id\": 1.0}}`)\n * @returns true when the literal holds a fraction or an exponent\n * @category Plugin helpers\n */\nexport function inexactLiteral(text: string, key: string, keyDepth = 1): boolean {\n const quoted = JSON.stringify(key);\n let depth = 0;\n let i = 0;\n while (i < text.length) {\n const c = text[i];\n if (c === \"{\" || c === \"[\") {\n depth++;\n } else if (c === \"}\" || c === \"]\") {\n depth--;\n } else if (c === '\"') {\n const start = i;\n i = stringEnd(text, i + 1);\n // the key itself (a string at depth 1 followed by a colon), not a value spelled like it\n const colon = skipSpace(text, i + 1);\n if (depth === keyDepth && text.startsWith(quoted, start) && text[colon] === \":\") {\n return inexactNumberAt(text, skipSpace(text, colon + 1));\n }\n }\n i++;\n }\n return false;\n}\n\n/**\n * Whether a number literal at an offset holds a fraction or an exponent.\n * @param text - the text\n * @param at - the offset\n * @returns true when it does; false for an integer or no number\n */\nfunction inexactNumberAt(text: string, at: number): boolean {\n NUMBER_LITERAL.lastIndex = at;\n const match = NUMBER_LITERAL.exec(text);\n return match !== null && /[.eE]/.test(match[0]);\n}\n\n// ============================================================ Cytoscape positions (design section 1.0.2)\n\n/**\n * The name of the position column of every Cytoscape-family importer.\n * @category Plugin helpers\n */\nexport const POSITION_COLUMN = \"position\";\n\n/** The name of the stacking-order column (Cytoscape's NODE_Z_LOCATION). */\nconst Z_COLUMN = \"z\";\n\n/**\n * The position column of a Cytoscape-family importer: f64 x3, y-up, 2 source dimensions.\n * @param format - the importer's format name\n * @param sourceDims - 3 when z goes into the position (zAs \"position\")\n * @returns the declaration\n * @category Plugin helpers\n */\nexport function positionDecl(format: string, sourceDims = 2): ColumnDecl {\n return {\n name: POSITION_COLUMN,\n dtype: \"f64\",\n components: 3,\n role: \"position\",\n mutable: true,\n nullable: true,\n extra: { sourceDims, units: \"file\" },\n origin: { format, namespace: \"cytoscape\" },\n };\n}\n\n/**\n * The stacking-order column `z` (f64, origin namespace \"cytoscape\").\n * @param format - the importer's format name\n * @returns the declaration\n * @category Plugin helpers\n */\nexport function zDecl(format: string): ColumnDecl {\n return {\n name: Z_COLUMN,\n dtype: \"f64\",\n nullable: true,\n origin: { format, id: null, namespace: \"cytoscape\" },\n extra: { cytoscape: \"z\" },\n };\n}\n\n/**\n * The head of an input as text for a sniff: UTF-16 by its byte order mark, else UTF-8, never\n * failing, without the BOM.\n * @param head - the first bytes\n * @returns the text\n * @category Plugin helpers\n */\nexport function headText(head: Uint8Array): string {\n let encoding = \"utf-8\";\n if (head.byteLength >= 2 && head[0] === 0xff && head[1] === 0xfe) {\n encoding = \"utf-16le\";\n } else if (head.byteLength >= 2 && head[0] === 0xfe && head[1] === 0xff) {\n encoding = \"utf-16be\";\n }\n return new TextDecoder(encoding).decode(head).replace(/^\\uFEFF/, \"\");\n}\n\n/**\n * Cytoscape's screen y (growing downward) as graph-io's y (growing upward), and back: a negation\n * that never yields -0.\n * @param y - the coordinate\n * @returns the flipped coordinate\n * @category Plugin helpers\n */\nexport function flipY(y: number): number {\n return y === 0 ? 0 : -y;\n}\n\n// ============================================================ stream structure shared by CX1 and CX2\n\n/** The aspect names of the stream structure, not of the network. */\nconst STRUCTURE_ASPECTS: ReadonlySet<string> = new Set([\"metaData\", \"status\", \"numberVerification\"]);\n\n/**\n * The order, metadata and status rules CX1 and CX2 share (design section 1.0.1): a third\n * `metaData` or an aspect after the post-metadata or after `status` is W_ASPECT_ORDER; declared\n * element counts are compared with what was read (W_COUNT_MISMATCH); `status.success: false` is\n * fatal (E_STATUS_FAILED) and `success: true` with an error text a warning (W_STATUS_WARNING).\n * @category Plugin helpers\n */\nexport class CxStructure {\n private readonly report: ImportReportBuilder;\n\n /** Elements read per aspect name. */\n readonly counts = new Map<string, number>();\n\n /** Blocks read per aspect name. */\n readonly blocks = new Map<string, number>();\n\n /** The element counts the metadata declares, by aspect name (a later declaration wins). */\n private readonly declared = new Map<string, number>();\n\n private metaDataBlocks = 0;\n\n private networkBlocks = 0;\n\n private postMetadata = false;\n\n private statusSeen = false;\n\n /** The status element, when one was read. */\n status: unknown = undefined;\n\n /**\n * Whether a status block was read.\n * @returns true once a status block began\n */\n get hasStatus(): boolean {\n return this.statusSeen;\n }\n\n /** The name an aspect is counted under (CX1 reads old Cytoscape names under their cy names). */\n private readonly canonical: (name: string) => string;\n\n /**\n * Create the checker.\n * @param report - the report\n * @param canonical - the name an aspect named in metaData is counted under (default: itself)\n */\n constructor(report: ImportReportBuilder, canonical: (name: string) => string = (name) => name) {\n this.report = report;\n this.canonical = canonical;\n }\n\n /**\n * Record the start of a block (or a member holding one aspect).\n * @param aspect - the aspect name\n * @param line - its line\n */\n block(aspect: string, line: number): void {\n this.blocks.set(aspect, (this.blocks.get(aspect) ?? 0) + 1);\n if (this.statusSeen) {\n this.report.warnOnce(\n \"validation-error\",\n ASPECT_ORDER_CODE,\n `the \"${aspect}\" block comes after the status block, which must be last; it is read`,\n { line, element: aspect },\n `${ASPECT_ORDER_CODE}:status`,\n );\n }\n if (aspect === \"metaData\") {\n this.metaDataBlocks++;\n if (this.networkBlocks > 0) {\n this.postMetadata = true;\n }\n if (this.metaDataBlocks > 2) {\n this.report.warnOnce(\n \"validation-error\",\n ASPECT_ORDER_CODE,\n `${this.metaDataBlocks} metaData blocks; a document has at most two (pre and post)`,\n { line, element: aspect },\n `${ASPECT_ORDER_CODE}:metaData`,\n );\n }\n return;\n }\n if (aspect === \"status\") {\n this.statusSeen = true;\n return;\n }\n if (STRUCTURE_ASPECTS.has(aspect)) {\n return;\n }\n this.networkBlocks++;\n if (this.postMetadata) {\n this.report.warnOnce(\n \"validation-error\",\n ASPECT_ORDER_CODE,\n `the \"${aspect}\" block comes after the post-metadata, where only status is allowed; it is read`,\n { line, element: aspect },\n `${ASPECT_ORDER_CODE}:post`,\n );\n }\n }\n\n /**\n * Record one element of a block; metaData and status elements are checked here.\n * @param aspect - the aspect name\n * @param value - the parsed element\n * @param line - its line\n */\n element(aspect: string, value: unknown, line: number): void {\n this.counts.set(aspect, (this.counts.get(aspect) ?? 0) + 1);\n if (aspect === \"metaData\") {\n this.readCount(value, line);\n return;\n }\n if (aspect === \"status\") {\n this.readStatus(value, line);\n }\n }\n\n /**\n * Record the element count a metaData element declares; a count that is not an integer (text,\n * a fraction) or that names no aspect is W_COUNT_MISMATCH and not checked.\n * @param value - the metaData element\n * @param line - its line\n */\n private readCount(value: unknown, line: number): void {\n if (!isRecord(value) || value.elementCount === undefined || value.elementCount === null) {\n return;\n }\n const raw = value.elementCount;\n let count: number | null = null;\n if (raw instanceof ExactInteger) {\n count = Number(raw.digits);\n } else if (typeof raw === \"number\" && Number.isInteger(raw)) {\n count = raw;\n }\n if (typeof value.name !== \"string\" || count === null) {\n const shownCount = raw instanceof ExactInteger ? raw.digits : JSON.stringify(raw);\n this.report.warning(\n \"validation-error\",\n COUNT_MISMATCH_CODE,\n `a metaData element declares the elementCount ${shownCount} for the name ${JSON.stringify(value.name) ?? \"undefined\"}; not a count of a named aspect, not checked`,\n { line, element: \"metaData\" },\n );\n return;\n }\n this.declared.set(this.canonical(value.name), count);\n }\n\n /**\n * Check a status element: success false is fatal, an error text with success true a warning.\n * @param value - the element\n * @param line - its line\n */\n private readStatus(value: unknown, line: number): void {\n if (this.status !== undefined) {\n this.report.warnOnce(\n \"validation-error\",\n ASPECT_ORDER_CODE,\n \"more than one status element; the last is used\",\n { line, element: \"status\" },\n `${ASPECT_ORDER_CODE}:status2`,\n );\n }\n this.status = value;\n if (!isRecord(value)) {\n return;\n }\n const error = typeof value.error === \"string\" ? value.error : \"\";\n if (value.success === false) {\n const message = `the producer marked the document as failed${error.length > 0 ? `: ${error}` : \"\"}`;\n this.report.error(\"validation-error\", STATUS_FAILED_CODE, message, { line, element: \"status\" });\n throw this.report.abort(message, { code: STATUS_FAILED_CODE });\n }\n if (value.success === true && error.length > 0) {\n this.report.warning(\"validation-error\", STATUS_WARNING_CODE, `the producer reports a warning: ${error}`, {\n line,\n element: \"status\",\n });\n }\n }\n\n /**\n * Whether the status element is one object with a boolean success.\n * @returns true for a well-formed status\n */\n statusWellFormed(): boolean {\n return isRecord(this.status) && typeof this.status.success === \"boolean\";\n }\n\n /** Compare the declared element counts with what was read (W_COUNT_MISMATCH per aspect). */\n checkCounts(): void {\n for (const [name, declared] of this.declared) {\n const read = this.counts.get(name) ?? 0;\n if (read !== declared) {\n this.report.warning(\n \"validation-error\",\n COUNT_MISMATCH_CODE,\n `metaData declares ${declared} \"${name}\" element${plural(declared)}; ${read} ${agree(read, \"was\", \"were\")} read`,\n { element: name },\n );\n }\n }\n }\n}\n\n/**\n * Whether a value is a plain JSON object.\n * @param value - any value\n * @returns true for a non-null, non-array object\n * @category Plugin helpers\n */\nexport function isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value) && !(value instanceof ExactInteger);\n}\n\n/**\n * Declare a column under a name no column of the table holds yet: a per-element visual property\n * whose name an attribute already has gets `<name>#2` (W_COLUMN_RENAMED), even when the two share a\n * shape, so the visual value never overwrites the attribute.\n * @param sink - the sink\n * @param domain - node or edge\n * @param decl - the declaration\n * @param report - the report the rename is recorded in\n * @returns the handle\n * @category Plugin helpers\n */\nexport function declareFresh(\n sink: GraphSink,\n domain: \"node\" | \"edge\",\n decl: ColumnDecl,\n report: ImportReportBuilder,\n): ColumnHandle {\n const taken = (name: string): boolean =>\n (domain === \"node\" ? sink.nodeColumn(name) : sink.edgeColumn(name)) !== INVALID_INDEX;\n let fresh = decl;\n if (taken(decl.name)) {\n fresh = { ...decl, name: uniqueColumnName(decl.name, null, taken) };\n report.warning(\n \"coercion\",\n COLUMN_RENAMED_CODE,\n `${domain} column \"${decl.name}\" renamed to \"${fresh.name}\": an attribute holds that name`,\n { element: decl.name },\n );\n }\n return declareResolved(sink, domain, fresh, report).handle;\n}\n"],"names":["members","inexactLiteral"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { GraphFormatError } from "@graphty/graph-format";
|
|
2
|
-
import { a as checkCapabilities, L as LOSS, at as COLUMN_AS_PROPERTY_VALUE_CODE, au as ROLE_ASSUMED_CODE, av as formatNumber } from "./export-
|
|
2
|
+
import { a as checkCapabilities, L as LOSS, at as COLUMN_AS_PROPERTY_VALUE_CODE, au as ROLE_ASSUMED_CODE, av as formatNumber } from "./export-Cbt4h_0n.js";
|
|
3
3
|
const OBO_NODE_COLUMNS = Object.freeze({
|
|
4
4
|
type: { dtype: "dict" },
|
|
5
5
|
name: { dtype: "string", role: "label" },
|
|
@@ -356,4 +356,4 @@ export {
|
|
|
356
356
|
textOf as t,
|
|
357
357
|
valuesOf as v
|
|
358
358
|
};
|
|
359
|
-
//# sourceMappingURL=ontology-export-
|
|
359
|
+
//# sourceMappingURL=ontology-export-p1PsPenq.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ontology-export-BRErBO6J.js","sources":["../../src/common/ontology.ts","../../src/common/ontology-export.ts"],"sourcesContent":["/**\n * What the OBO importer and the JSON importer's `obographs` dialect share (design section 1.0, the\n * `ontology.ts` building block): the OBO column vocabulary (names, dtypes, roles), so the `.obo` and\n * the `.json` of one ontology give the same columns, and the OBO 1.4 rule for turning the IRIs\n * OBO Graphs writes back into the identifiers the `.obo` file writes (section 4.6).\n */\n\nimport { type ColumnDecl } from \"@graphty/graph-format\";\n\n/** The dtypes the OBO vocabulary uses. */\ntype OboDtype = \"string\" | \"dict\" | \"bool\" | \"list\" | \"json\";\n\n/** One column of the OBO vocabulary. */\ninterface OboColumnSpec {\n /** The dtype. */\n readonly dtype: OboDtype;\n /** The role, when the column carries one. */\n readonly role?: \"label\" | \"kind\" | undefined;\n}\n\n/**\n * The node columns of the OBO vocabulary, keyed by column name (design section 4.2). The names are\n * the OBO tag names, so a Gene Ontology user finds `namespace`, `def` and `is_obsolete` under the\n * names the GO documentation uses.\n * @category Plugin helpers\n */\nexport const OBO_NODE_COLUMNS: Readonly<Record<string, OboColumnSpec>> = Object.freeze({\n type: { dtype: \"dict\" },\n name: { dtype: \"string\", role: \"label\" },\n namespace: { dtype: \"dict\" },\n def: { dtype: \"string\" },\n \"def.xrefs\": { dtype: \"list\" },\n comment: { dtype: \"string\" },\n synonym: { dtype: \"json\" },\n xref: { dtype: \"list\" },\n \"xref.descriptions\": { dtype: \"json\" },\n alt_id: { dtype: \"list\" },\n subset: { dtype: \"list\" },\n replaced_by: { dtype: \"list\" },\n consider: { dtype: \"list\" },\n is_obsolete: { dtype: \"bool\" },\n is_anonymous: { dtype: \"bool\" },\n builtin: { dtype: \"bool\" },\n created_by: { dtype: \"string\" },\n creation_date: { dtype: \"string\" },\n intersection_of: { dtype: \"json\" },\n union_of: { dtype: \"list\" },\n equivalent_to: { dtype: \"list\" },\n disjoint_from: { dtype: \"list\" },\n property_value: { dtype: \"json\" },\n // Typedef frames, under typedefs: \"nodes\"\n domain: { dtype: \"string\" },\n range: { dtype: \"string\" },\n inverse_of: { dtype: \"string\" },\n transitive_over: { dtype: \"list\" },\n disjoint_over: { dtype: \"list\" },\n holds_over_chain: { dtype: \"json\" },\n equivalent_to_chain: { dtype: \"json\" },\n expand_assertion_to: { dtype: \"json\" },\n expand_expression_to: { dtype: \"json\" },\n is_cyclic: { dtype: \"bool\" },\n is_reflexive: { dtype: \"bool\" },\n is_symmetric: { dtype: \"bool\" },\n is_anti_symmetric: { dtype: \"bool\" },\n is_asymmetric: { dtype: \"bool\" },\n is_transitive: { dtype: \"bool\" },\n is_functional: { dtype: \"bool\" },\n is_inverse_functional: { dtype: \"bool\" },\n is_metadata_tag: { dtype: \"bool\" },\n is_class_level: { dtype: \"bool\" },\n // OBO Graphs only\n propertyType: { dtype: \"dict\" },\n // what has no column of its own\n \"obo.qualifiers\": { dtype: \"json\" },\n \"obo.unrecognized\": { dtype: \"json\" },\n});\n\n/** The edge columns of the OBO vocabulary. */\nconst OBO_EDGE_COLUMNS: Readonly<Record<string, OboColumnSpec>> = Object.freeze({\n relation: { dtype: \"dict\", role: \"kind\" },\n qualifiers: { dtype: \"json\" },\n meta: { dtype: \"json\" },\n});\n\n/**\n * The node column that marks a node made for an undeclared reference (design section 4.2).\n * @category Plugin helpers\n */\nexport const PLACEHOLDER_COLUMN = \"graphty.placeholder\";\n\n/**\n * The declaration of an OBO vocabulary column.\n * @param domain - node or edge\n * @param name - the column name (a key of OBO_NODE_COLUMNS / OBO_EDGE_COLUMNS, or the placeholder column)\n * @returns the declaration, nullable, with origin `{ format: \"obo\", id: name }`\n * @category Plugin helpers\n */\nexport function oboColumnDecl(domain: \"node\" | \"edge\", name: string): ColumnDecl {\n if (name === PLACEHOLDER_COLUMN) {\n return { name, dtype: \"bool\", nullable: true, origin: { format: \"graphty\", id: \"placeholder\" } };\n }\n const spec = (domain === \"node\" ? OBO_NODE_COLUMNS : OBO_EDGE_COLUMNS)[name];\n const decl: ColumnDecl = { name, dtype: spec.dtype, nullable: true, origin: { format: \"obo\", id: name } };\n if (spec.dtype === \"list\") {\n decl.itemDtype = \"string\";\n }\n if (spec.role !== undefined) {\n decl.role = spec.role;\n }\n return decl;\n}\n\n/**\n * The OBO PURL base every OBO Foundry IRI starts with.\n * @category Plugin helpers\n */\nexport const OBO_PURL = \"http://purl.obolibrary.org/obo/\"; // NOSONAR(S5332): an identifier the OBO standard fixes, never fetched\n\n/** The same base under https, which newer OBO Graphs writers use. */\nconst OBO_PURL_HTTPS = \"https://purl.obolibrary.org/obo/\";\n\n/**\n * The oboInOwl namespace of the OBO-to-OWL mapping's annotation properties.\n * @category Plugin helpers\n */\nexport const OBO_IN_OWL = \"http://www.geneontology.org/formats/oboInOwl#\"; // NOSONAR(S5332): an identifier the OBO standard fixes, never fetched\n\n/**\n * An IRI as the identifier the `.obo` file writes (the OBO 1.4 mapping, section 5.9, read\n * backwards): `http://purl.obolibrary.org/obo/GO_0008150` is `GO:0008150` (the prefix is the text\n * before the first underscore), and `http://purl.obolibrary.org/obo/go#regulates` (how the OWL\n * translation writes an unprefixed OBO id: subsets, relations, synonym types) is `regulates`; the\n * same under `https://purl.obolibrary.org/obo/`.\n * Every other IRI, and an OBO PURL that fits neither form (`.../obo/T/Female`), is kept.\n * @param iri - the IRI\n * @returns the CURIE or local id, or the IRI unchanged\n * @category Plugin helpers\n */\nexport function compactOboIri(iri: string): string {\n const base = [OBO_PURL, OBO_PURL_HTTPS].find((b) => iri.startsWith(b));\n if (base === undefined) {\n return iri;\n }\n const rest = iri.slice(base.length);\n const hash = rest.indexOf(\"#\");\n if (hash > 0) {\n const local = rest.slice(hash + 1);\n return local.length > 0 && !rest.slice(0, hash).includes(\"/\") ? local : iri;\n }\n const underscore = rest.indexOf(\"_\");\n if (underscore <= 0 || rest.includes(\"/\") || underscore === rest.length - 1) {\n return iri;\n }\n return `${rest.slice(0, underscore)}:${rest.slice(underscore + 1)}`;\n}\n\n/**\n * The OBO synonym scopes.\n * @category Plugin helpers\n */\nexport const SYNONYM_SCOPES: ReadonlySet<string> = new Set([\"EXACT\", \"BROAD\", \"NARROW\", \"RELATED\"]);\n\n/**\n * The OBO synonym scope of an OBO Graphs synonym predicate (`hasExactSynonym`, with or without the\n * oboInOwl namespace).\n * @param pred - the predicate\n * @returns the scope, or null for a predicate that is not one of the four\n * @category Plugin helpers\n */\nexport function synonymScopeOf(pred: string): string | null {\n const local = pred.startsWith(OBO_IN_OWL) ? pred.slice(OBO_IN_OWL.length) : pred;\n const match = /^has(Exact|Broad|Narrow|Related)Synonym$/.exec(local);\n return match === null ? null : match[1].toUpperCase();\n}\n\n/**\n * The OBO tag a `basicPropertyValues` predicate of OBO Graphs came from (the OBO-to-OWL mapping of\n * the tags that are annotations), so the `.json` of an ontology fills the same columns as its\n * `.obo`. `shorthand` is the relation's short name; every predicate not listed is a\n * `property_value`.\n * @category Plugin helpers\n */\nexport const OBOGRAPHS_PREDICATE_TAGS: ReadonlyMap<string, string> = new Map([\n [`${OBO_IN_OWL}hasOBONamespace`, \"namespace\"],\n [`${OBO_IN_OWL}hasAlternativeId`, \"alt_id\"],\n [`${OBO_IN_OWL}created_by`, \"created_by\"],\n [`${OBO_IN_OWL}creation_date`, \"creation_date\"],\n [`${OBO_PURL}IAO_0100001`, \"replaced_by\"],\n [`${OBO_IN_OWL}consider`, \"consider\"],\n [`${OBO_IN_OWL}shorthand`, \"shorthand\"],\n]);\n","/**\n * What the two ontology exporters share (the OBO flat file and the JSON exporter's `obographs`\n * dialect): the snapshot columns that fill the OBO slots (the label as `name`, the edge kind as\n * `relation`), the placeholder nodes a re-import makes again by itself, the order a re-import gives\n * the nodes, and the text of a cell. Both read the snapshot through the column vocabulary of\n * ontology.ts, so a column means the same thing in both files.\n */\n\nimport { type Column, GraphFormatError, type GraphSnapshot } from \"@graphty/graph-format\";\n\nimport { type ExportCapabilities } from \"../types.js\";\nimport { COLUMN_AS_PROPERTY_VALUE_CODE, ROLE_ASSUMED_CODE } from \"./codes.js\";\nimport { checkCapabilities, LOSS } from \"./export.js\";\nimport { formatNumber } from \"./format.js\";\nimport { PLACEHOLDER_COLUMN } from \"./ontology.js\";\nimport { type ResolvedExportOptions } from \"./options.js\";\n\n/**\n * A note recorder.\n * @category Plugin helpers\n */\nexport type NoteFn = (code: string, message: string, column?: string | null, count?: number | null) => void;\n\n/** The generic notes the ontology formats replace with their own (see capabilityNotes()). */\nconst SUPERSEDED: ReadonlySet<string> = new Set([\n LOSS.DTYPE,\n LOSS.LIST,\n LOSS.JSON,\n LOSS.COMPONENTS,\n LOSS.GRAPH_ATTRIBUTES,\n]);\n\n/** The roles the ontology formats have a slot for, and the column names their importers give them. */\nconst SLOT_ROLES: ReadonlySet<string> = new Set([\"label\", \"kind\"]);\nconst NODE_ROLE_NAMES: Readonly<Record<string, string>> = Object.freeze({ label: \"name\" });\nconst EDGE_ROLE_NAMES: Readonly<Record<string, string>> = Object.freeze({ kind: \"relation\" });\n\n/**\n * The roles whose columns are never written as values (their loss notes come from checkCapabilities()).\n * @category Plugin helpers\n */\nexport const UNWRITTEN_ROLES: ReadonlySet<string> = new Set([\n \"directed\",\n \"pair\",\n \"mutual\",\n \"weight\",\n \"timeText\",\n \"originalId\",\n \"parent\",\n \"parents\",\n \"start\",\n \"end\",\n \"timestamp\",\n \"timestamps\",\n \"spells\",\n \"open\",\n \"spellsOpen\",\n \"position\",\n \"color\",\n \"size\",\n \"shape\",\n \"thickness\",\n]);\n\n/**\n * The OBO frame types.\n * @category Plugin helpers\n */\nexport type FrameKind = \"Term\" | \"Instance\" | \"Typedef\";\n\n/**\n * The frame types as a set, for checking a `type` cell.\n * @category Plugin helpers\n */\nexport const FRAME_KINDS: ReadonlySet<string> = new Set([\"Term\", \"Instance\", \"Typedef\"]);\n\n/**\n * The value of a set cell (a multi-component value as a plain array), or undefined when unset; a\n * declared default is not a value here (the formats have no defaults and say so).\n * @param column - the column\n * @param row - the row\n * @returns the value or undefined\n * @category Plugin helpers\n */\nexport function cellOf(column: Column, row: number): unknown {\n if (!column.isSet(row)) {\n return undefined;\n }\n const value: unknown = column.value(row);\n return ArrayBuffer.isView(value) ? Array.from(value as unknown as ArrayLike<number>) : value;\n}\n\n/**\n * The text of a scalar value: a number by its dtype's shortest round-tripping form (`-0` kept), a\n * boolean as `true` / `false`, a string as it is, anything else as its JSON text.\n * @param value - the value\n * @param dtype - the dtype it came from (the item dtype for a list item)\n * @returns the text\n * @category Plugin helpers\n */\nexport function textOf(value: unknown, dtype: string): string {\n switch (typeof value) {\n case \"string\":\n return value;\n case \"boolean\":\n return value ? \"true\" : \"false\";\n case \"number\":\n return formatNumber(\n value,\n dtype === \"f32\" || dtype === \"i32\" || dtype === \"u32\" || dtype === \"u8\" ? dtype : \"f64\",\n );\n default:\n return JSON.stringify(value) ?? \"null\";\n }\n}\n\n/**\n * Whether a column has the dtype of a vocabulary column (string and dict both fit a text column;\n * the other text dtype is reported, not refused).\n * @param want - the vocabulary dtype\n * @param column - the column\n * @returns true when the column can be written into the vocabulary slot\n * @category Plugin helpers\n */\nexport function fitsVocabulary(want: string, column: Column): boolean {\n switch (want) {\n case \"list\":\n case \"bool\":\n case \"json\":\n return column.dtype === want;\n default:\n return isText(column);\n }\n}\n\n/**\n * The values of a cell that may hold one value or a list of them.\n * @param value - the cell value, or undefined\n * @returns the values\n * @category Plugin helpers\n */\nexport function valuesOf(value: unknown): readonly unknown[] {\n if (value === undefined) {\n return [];\n }\n return Array.isArray(value) ? value : [value];\n}\n\n/** A column chosen for an OBO slot. */\ninterface Slot {\n /** The column, or null when the snapshot has none for the slot. */\n readonly column: Column | null;\n /** Whether a role-less column was chosen by its name; it reads back with the role (W_ROLE_ASSUMED). */\n readonly assumed: boolean;\n}\n\n/**\n * The column of a slot: the column with the role when it holds text, else a role-less text column\n * of the slot's name (which the importer reads back with the role).\n * @param table - the node or edge table\n * @param role - the role (`label` for `name`, `kind` for `relation`)\n * @param name - the name the importer gives the slot\n * @returns the column and whether its role is assumed\n * @category Plugin helpers\n */\nexport function slotColumn(table: GraphSnapshot[\"nodes\"], role: \"label\" | \"kind\", name: string): Slot {\n const byRole = table.byRole(role);\n if (byRole !== null) {\n return { column: isText(byRole) ? byRole : null, assumed: false };\n }\n const byName = table.get(name);\n if (byName !== null && byName.meta.role === null && isText(byName)) {\n return { column: byName, assumed: true };\n }\n return { column: null, assumed: false };\n}\n\n/**\n * Whether a column holds text (string or dict).\n * @param column - the column\n * @returns true for string and dict\n */\nfunction isText(column: Column): boolean {\n return column.dtype === \"string\" || column.dtype === \"dict\";\n}\n\n/**\n * The placeholder column (`graphty.placeholder`, a bool), or null.\n * @param snapshot - the snapshot\n * @returns the column\n */\nfunction placeholderColumn(snapshot: GraphSnapshot): Column | null {\n const column = snapshot.nodes.get(PLACEHOLDER_COLUMN);\n return column !== null && column.dtype === \"bool\" ? column : null;\n}\n\n/**\n * The nodes written without a frame (OBO) or a node record (OBO Graphs) because the re-import makes\n * them again as placeholders: a `graphty.placeholder` true cell, no other set cell, an id written\n * as it is, an edge that references it, and (in the flat file, where an edge is written on its\n * source's frame) no edge of its own.\n * @param snapshot - the snapshot\n * @param written - the logical edges written\n * @param options - `outgoingAllowed`: whether a placeholder may be an edge's source; `changed`: whether a node's id is rewritten\n * @param options.outgoingAllowed - whether a placeholder may be an edge's source\n * @param options.changed - whether a node's id is rewritten\n * @returns one flag per node, 1 for a node written without a frame\n * @category Plugin helpers\n */\nexport function framelessNodes(\n snapshot: GraphSnapshot,\n written: readonly number[],\n options: { readonly outgoingAllowed: boolean; readonly changed: (i: number) => boolean },\n): Uint8Array {\n const flags = new Uint8Array(snapshot.nodeCount);\n const placeholder = placeholderColumn(snapshot);\n if (placeholder === null) {\n return flags;\n }\n const { src, dst } = snapshot.edgeList();\n const referenced = new Uint8Array(snapshot.nodeCount);\n const sources = new Uint8Array(snapshot.nodeCount);\n for (const e of written) {\n referenced[dst[e]] = 1;\n if (options.outgoingAllowed) {\n referenced[src[e]] = 1;\n } else {\n sources[src[e]] = 1;\n }\n }\n const others = [...snapshot.nodes].filter((c) => c !== placeholder);\n for (let i = 0; i < snapshot.nodeCount; i++) {\n if (\n placeholder.isSet(i) &&\n placeholder.value(i) === true &&\n referenced[i] === 1 &&\n sources[i] === 0 &&\n !options.changed(i) &&\n others.every((c) => !c.isSet(i))\n ) {\n flags[i] = 1;\n }\n }\n return flags;\n}\n\n/**\n * How many nodes a re-import puts at another index: the written nodes keep their order and the\n * placeholders follow in the order the edges first reference them.\n * @param frameless - the framelessNodes() flags\n * @param references - the node indices in the order the written edges reference them\n * @returns the number of nodes whose index changes\n * @category Plugin helpers\n */\nexport function movedNodes(frameless: Uint8Array, references: Iterable<number>): number {\n const order: number[] = [];\n for (let i = 0; i < frameless.length; i++) {\n if (frameless[i] === 0) {\n order.push(i);\n }\n }\n const seen = new Uint8Array(frameless.length);\n for (const i of references) {\n if (frameless[i] === 1 && seen[i] === 0) {\n seen[i] = 1;\n order.push(i);\n }\n }\n let moved = 0;\n for (let k = 0; k < order.length; k++) {\n if (order[k] !== k) {\n moved++;\n }\n }\n return moved;\n}\n\n/**\n * Whether a value is a qualifier record as the importers make it: a non-empty object of names to a\n * text or a list of two or more texts (a name given once reads back as a text, never as a\n * one-item list), every name passing `nameOk`.\n * @param value - the value\n * @param nameOk - the name rule\n * @returns true when the record is written and read back unchanged\n * @category Plugin helpers\n */\nexport function isQualifierRecord(value: unknown, nameOk: (name: string) => boolean): boolean {\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) {\n return false;\n }\n const entries = Object.entries(value);\n return (\n entries.length > 0 &&\n entries.every(\n ([name, v]) =>\n nameOk(name) &&\n (typeof v === \"string\" ||\n (Array.isArray(v) && v.length >= 2 && v.every((item) => typeof item === \"string\"))),\n )\n );\n}\n\n/** What capabilityNotes() needs to know about the export. */\ninterface CapabilityNoteSpec {\n /** The format's capabilities. */\n readonly caps: ExportCapabilities;\n /** The label column written as the name, or null. */\n readonly label: Column | null;\n /** Whether the label is a role-less `name` column. */\n readonly labelAssumed: boolean;\n /** Where an edge column without a slot goes, for messages (\"a qualifier\"). */\n readonly edgeSlot: string;\n /** Records a note. */\n readonly note: NoteFn;\n}\n\n/**\n * The generic notes of checkCapabilities() as the ontology formats see them. No column of the\n * snapshot's own survives as a column (the formats keep only the OBO vocabulary), so the generic\n * dtype, list, json, strides and graph-attribute notes give way to the formats' own, which say\n * where each column goes (a vocabulary column written into its slot needs no note; any other\n * becomes property values, edge qualifiers or metadata). The name-change notes stand only for the\n * label and kind columns actually written into their slot. Added: the roles without a slot (a\n * node kind, an edge label) and a role-less `name` column taking the label role.\n * @param snapshot - the snapshot\n * @param common - the common options\n * @param spec - the export's facts\n * @returns the fatal error of a mixed graph under onMixedDirection \"error\", or null\n * @category Plugin helpers\n */\nexport function capabilityNotes(\n snapshot: GraphSnapshot,\n common: ResolvedExportOptions,\n spec: CapabilityNoteSpec,\n): GraphFormatError | null {\n const { label, note } = spec;\n let fatal: GraphFormatError | null = null;\n const kind = snapshot.edges.byRole(\"kind\");\n // a node label goes into the name slot and an edge kind into the relation slot, when written there;\n // an edge label has no slot (it becomes edge qualifiers or metadata), so it is never renamed\n const extras = {\n roles: SLOT_ROLES,\n nodeRoleNames: label === null ? {} : NODE_ROLE_NAMES,\n edgeRoleNames: kind !== null && isText(kind) ? EDGE_ROLE_NAMES : {},\n };\n for (const gen of checkCapabilities(snapshot, spec.caps, common, extras)) {\n if (SUPERSEDED.has(gen.code)) {\n continue;\n }\n if (gen.code === LOSS.MIXED_DIRECTION_ERROR && fatal === null) {\n fatal = new GraphFormatError(\"E_DIRECTED\", gen.message, { reason: \"mixed direction\" });\n }\n note(gen.code, gen.message, gen.column, gen.count);\n }\n slotlessRoleNotes(snapshot, spec);\n return fatal;\n}\n\n/**\n * Note the roles the ontology formats have no slot for (a node kind, an edge label), and a\n * role-less `name` column taking the label role.\n * @param snapshot - the snapshot\n * @param spec - the export's facts\n */\nfunction slotlessRoleNotes(snapshot: GraphSnapshot, spec: CapabilityNoteSpec): void {\n const { label, note } = spec;\n const nodeKind = snapshot.nodes.byRole(\"kind\");\n if (nodeKind !== null) {\n note(\n LOSS.ROLE,\n `node column \"${nodeKind.meta.name}\" (kind) is written as property values; the format has no node kind slot`,\n nodeKind.meta.name,\n nodeKind.length - nodeKind.nullCount,\n );\n }\n const edgeLabel = snapshot.edges.byRole(\"label\");\n if (edgeLabel !== null) {\n note(\n LOSS.ROLE,\n `edge column \"${edgeLabel.meta.name}\" (label) is written as ${spec.edgeSlot}; the format has no edge label slot`,\n edgeLabel.meta.name,\n edgeLabel.length - edgeLabel.nullCount,\n );\n }\n if (label !== null && spec.labelAssumed) {\n note(\n ROLE_ASSUMED_CODE,\n `node column \"name\" is written as each node's name and reads back as the label`,\n \"name\",\n label.length - label.nullCount,\n );\n }\n}\n\n/**\n * Record the columns that read back absent: a node or edge column without a set cell on a written\n * element (the importers declare a column when a value needs it).\n * @param snapshot - the snapshot\n * @param rows - the written nodes\n * @param frameless - the frameless flags (a placeholder column set only there reads back)\n * @param written - the written edges\n * @param note - records a note\n * @category Plugin helpers\n */\nexport function emptyColumnNotes(\n snapshot: GraphSnapshot,\n rows: readonly number[],\n frameless: Uint8Array,\n written: readonly number[],\n note: NoteFn,\n): void {\n const tables = [\n [\n \"node\",\n snapshot.nodes,\n (c: Column): boolean =>\n rows.some((i) => c.isSet(i)) ||\n (c.meta.name === PLACEHOLDER_COLUMN && frameless.some((f, i) => f === 1 && c.isSet(i))),\n ],\n [\"edge\", snapshot.edges, (c: Column): boolean => written.some((e) => c.isSet(e))],\n ] as const;\n for (const [domain, table, used] of tables) {\n for (const column of table) {\n const { role, name } = column.meta;\n if (\n (role !== null && (UNWRITTEN_ROLES.has(role) || (domain === \"edge\" && role === \"id\"))) ||\n used(column)\n ) {\n continue;\n }\n note(LOSS.EMPTY_COLUMN, `${domain} column \"${name}\" has no value to write; it reads back absent`, name, 0);\n }\n }\n}\n\n/**\n * Record the note of a node column written as property values.\n * @param note - the recorder\n * @param column - the column\n * @param rows - the written nodes\n * @param how - how the values are written, for the message\n * @category Plugin helpers\n */\nexport function notePropertyColumn(note: NoteFn, column: Column, rows: readonly number[], how: string): void {\n const count = rows.filter((i) => column.isSet(i)).length;\n if (count === 0) {\n return;\n }\n const role = column.meta.role === null ? \"\" : ` (its ${column.meta.role} role is lost)`;\n note(\n COLUMN_AS_PROPERTY_VALUE_CODE,\n `node column \"${column.meta.name}\" is written as ${how} and reads back inside the property_value column, not as its own column${role}`,\n column.meta.name,\n count,\n );\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ontology-export-p1PsPenq.js","sources":["../../src/common/ontology.ts","../../src/common/ontology-export.ts"],"sourcesContent":["/**\n * What the OBO importer and the JSON importer's `obographs` dialect share (design section 1.0, the\n * `ontology.ts` building block): the OBO column vocabulary (names, dtypes, roles), so the `.obo` and\n * the `.json` of one ontology give the same columns, and the OBO 1.4 rule for turning the IRIs\n * OBO Graphs writes back into the identifiers the `.obo` file writes (section 4.6).\n */\n\nimport { type ColumnDecl } from \"@graphty/graph-format\";\n\n/** The dtypes the OBO vocabulary uses. */\ntype OboDtype = \"string\" | \"dict\" | \"bool\" | \"list\" | \"json\";\n\n/** One column of the OBO vocabulary. */\ninterface OboColumnSpec {\n /** The dtype. */\n readonly dtype: OboDtype;\n /** The role, when the column carries one. */\n readonly role?: \"label\" | \"kind\" | undefined;\n}\n\n/**\n * The node columns of the OBO vocabulary, keyed by column name (design section 4.2). The names are\n * the OBO tag names, so a Gene Ontology user finds `namespace`, `def` and `is_obsolete` under the\n * names the GO documentation uses.\n * @category Plugin helpers\n */\nexport const OBO_NODE_COLUMNS: Readonly<Record<string, OboColumnSpec>> = Object.freeze({\n type: { dtype: \"dict\" },\n name: { dtype: \"string\", role: \"label\" },\n namespace: { dtype: \"dict\" },\n def: { dtype: \"string\" },\n \"def.xrefs\": { dtype: \"list\" },\n comment: { dtype: \"string\" },\n synonym: { dtype: \"json\" },\n xref: { dtype: \"list\" },\n \"xref.descriptions\": { dtype: \"json\" },\n alt_id: { dtype: \"list\" },\n subset: { dtype: \"list\" },\n replaced_by: { dtype: \"list\" },\n consider: { dtype: \"list\" },\n is_obsolete: { dtype: \"bool\" },\n is_anonymous: { dtype: \"bool\" },\n builtin: { dtype: \"bool\" },\n created_by: { dtype: \"string\" },\n creation_date: { dtype: \"string\" },\n intersection_of: { dtype: \"json\" },\n union_of: { dtype: \"list\" },\n equivalent_to: { dtype: \"list\" },\n disjoint_from: { dtype: \"list\" },\n property_value: { dtype: \"json\" },\n // Typedef frames, under typedefs: \"nodes\"\n domain: { dtype: \"string\" },\n range: { dtype: \"string\" },\n inverse_of: { dtype: \"string\" },\n transitive_over: { dtype: \"list\" },\n disjoint_over: { dtype: \"list\" },\n holds_over_chain: { dtype: \"json\" },\n equivalent_to_chain: { dtype: \"json\" },\n expand_assertion_to: { dtype: \"json\" },\n expand_expression_to: { dtype: \"json\" },\n is_cyclic: { dtype: \"bool\" },\n is_reflexive: { dtype: \"bool\" },\n is_symmetric: { dtype: \"bool\" },\n is_anti_symmetric: { dtype: \"bool\" },\n is_asymmetric: { dtype: \"bool\" },\n is_transitive: { dtype: \"bool\" },\n is_functional: { dtype: \"bool\" },\n is_inverse_functional: { dtype: \"bool\" },\n is_metadata_tag: { dtype: \"bool\" },\n is_class_level: { dtype: \"bool\" },\n // OBO Graphs only\n propertyType: { dtype: \"dict\" },\n // what has no column of its own\n \"obo.qualifiers\": { dtype: \"json\" },\n \"obo.unrecognized\": { dtype: \"json\" },\n});\n\n/** The edge columns of the OBO vocabulary. */\nconst OBO_EDGE_COLUMNS: Readonly<Record<string, OboColumnSpec>> = Object.freeze({\n relation: { dtype: \"dict\", role: \"kind\" },\n qualifiers: { dtype: \"json\" },\n meta: { dtype: \"json\" },\n});\n\n/**\n * The node column that marks a node made for an undeclared reference (design section 4.2).\n * @category Plugin helpers\n */\nexport const PLACEHOLDER_COLUMN = \"graphty.placeholder\";\n\n/**\n * The declaration of an OBO vocabulary column.\n * @param domain - node or edge\n * @param name - the column name (a key of OBO_NODE_COLUMNS / OBO_EDGE_COLUMNS, or the placeholder column)\n * @returns the declaration, nullable, with origin `{ format: \"obo\", id: name }`\n * @category Plugin helpers\n */\nexport function oboColumnDecl(domain: \"node\" | \"edge\", name: string): ColumnDecl {\n if (name === PLACEHOLDER_COLUMN) {\n return { name, dtype: \"bool\", nullable: true, origin: { format: \"graphty\", id: \"placeholder\" } };\n }\n const spec = (domain === \"node\" ? OBO_NODE_COLUMNS : OBO_EDGE_COLUMNS)[name];\n const decl: ColumnDecl = { name, dtype: spec.dtype, nullable: true, origin: { format: \"obo\", id: name } };\n if (spec.dtype === \"list\") {\n decl.itemDtype = \"string\";\n }\n if (spec.role !== undefined) {\n decl.role = spec.role;\n }\n return decl;\n}\n\n/**\n * The OBO PURL base every OBO Foundry IRI starts with.\n * @category Plugin helpers\n */\nexport const OBO_PURL = \"http://purl.obolibrary.org/obo/\"; // NOSONAR(S5332): an identifier the OBO standard fixes, never fetched\n\n/** The same base under https, which newer OBO Graphs writers use. */\nconst OBO_PURL_HTTPS = \"https://purl.obolibrary.org/obo/\";\n\n/**\n * The oboInOwl namespace of the OBO-to-OWL mapping's annotation properties.\n * @category Plugin helpers\n */\nexport const OBO_IN_OWL = \"http://www.geneontology.org/formats/oboInOwl#\"; // NOSONAR(S5332): an identifier the OBO standard fixes, never fetched\n\n/**\n * An IRI as the identifier the `.obo` file writes (the OBO 1.4 mapping, section 5.9, read\n * backwards): `http://purl.obolibrary.org/obo/GO_0008150` is `GO:0008150` (the prefix is the text\n * before the first underscore), and `http://purl.obolibrary.org/obo/go#regulates` (how the OWL\n * translation writes an unprefixed OBO id: subsets, relations, synonym types) is `regulates`; the\n * same under `https://purl.obolibrary.org/obo/`.\n * Every other IRI, and an OBO PURL that fits neither form (`.../obo/T/Female`), is kept.\n * @param iri - the IRI\n * @returns the CURIE or local id, or the IRI unchanged\n * @category Plugin helpers\n */\nexport function compactOboIri(iri: string): string {\n const base = [OBO_PURL, OBO_PURL_HTTPS].find((b) => iri.startsWith(b));\n if (base === undefined) {\n return iri;\n }\n const rest = iri.slice(base.length);\n const hash = rest.indexOf(\"#\");\n if (hash > 0) {\n const local = rest.slice(hash + 1);\n return local.length > 0 && !rest.slice(0, hash).includes(\"/\") ? local : iri;\n }\n const underscore = rest.indexOf(\"_\");\n if (underscore <= 0 || rest.includes(\"/\") || underscore === rest.length - 1) {\n return iri;\n }\n return `${rest.slice(0, underscore)}:${rest.slice(underscore + 1)}`;\n}\n\n/**\n * The OBO synonym scopes.\n * @category Plugin helpers\n */\nexport const SYNONYM_SCOPES: ReadonlySet<string> = new Set([\"EXACT\", \"BROAD\", \"NARROW\", \"RELATED\"]);\n\n/**\n * The OBO synonym scope of an OBO Graphs synonym predicate (`hasExactSynonym`, with or without the\n * oboInOwl namespace).\n * @param pred - the predicate\n * @returns the scope, or null for a predicate that is not one of the four\n * @category Plugin helpers\n */\nexport function synonymScopeOf(pred: string): string | null {\n const local = pred.startsWith(OBO_IN_OWL) ? pred.slice(OBO_IN_OWL.length) : pred;\n const match = /^has(Exact|Broad|Narrow|Related)Synonym$/.exec(local);\n return match === null ? null : match[1].toUpperCase();\n}\n\n/**\n * The OBO tag a `basicPropertyValues` predicate of OBO Graphs came from (the OBO-to-OWL mapping of\n * the tags that are annotations), so the `.json` of an ontology fills the same columns as its\n * `.obo`. `shorthand` is the relation's short name; every predicate not listed is a\n * `property_value`.\n * @category Plugin helpers\n */\nexport const OBOGRAPHS_PREDICATE_TAGS: ReadonlyMap<string, string> = new Map([\n [`${OBO_IN_OWL}hasOBONamespace`, \"namespace\"],\n [`${OBO_IN_OWL}hasAlternativeId`, \"alt_id\"],\n [`${OBO_IN_OWL}created_by`, \"created_by\"],\n [`${OBO_IN_OWL}creation_date`, \"creation_date\"],\n [`${OBO_PURL}IAO_0100001`, \"replaced_by\"],\n [`${OBO_IN_OWL}consider`, \"consider\"],\n [`${OBO_IN_OWL}shorthand`, \"shorthand\"],\n]);\n","/**\n * What the two ontology exporters share (the OBO flat file and the JSON exporter's `obographs`\n * dialect): the snapshot columns that fill the OBO slots (the label as `name`, the edge kind as\n * `relation`), the placeholder nodes a re-import makes again by itself, the order a re-import gives\n * the nodes, and the text of a cell. Both read the snapshot through the column vocabulary of\n * ontology.ts, so a column means the same thing in both files.\n */\n\nimport { type Column, GraphFormatError, type GraphSnapshot } from \"@graphty/graph-format\";\n\nimport { type ExportCapabilities } from \"../types.js\";\nimport { COLUMN_AS_PROPERTY_VALUE_CODE, ROLE_ASSUMED_CODE } from \"./codes.js\";\nimport { checkCapabilities, LOSS } from \"./export.js\";\nimport { formatNumber } from \"./format.js\";\nimport { PLACEHOLDER_COLUMN } from \"./ontology.js\";\nimport { type ResolvedExportOptions } from \"./options.js\";\n\n/**\n * A note recorder.\n * @category Plugin helpers\n */\nexport type NoteFn = (code: string, message: string, column?: string | null, count?: number | null) => void;\n\n/** The generic notes the ontology formats replace with their own (see capabilityNotes()). */\nconst SUPERSEDED: ReadonlySet<string> = new Set([\n LOSS.DTYPE,\n LOSS.LIST,\n LOSS.JSON,\n LOSS.COMPONENTS,\n LOSS.GRAPH_ATTRIBUTES,\n]);\n\n/** The roles the ontology formats have a slot for, and the column names their importers give them. */\nconst SLOT_ROLES: ReadonlySet<string> = new Set([\"label\", \"kind\"]);\nconst NODE_ROLE_NAMES: Readonly<Record<string, string>> = Object.freeze({ label: \"name\" });\nconst EDGE_ROLE_NAMES: Readonly<Record<string, string>> = Object.freeze({ kind: \"relation\" });\n\n/**\n * The roles whose columns are never written as values (their loss notes come from checkCapabilities()).\n * @category Plugin helpers\n */\nexport const UNWRITTEN_ROLES: ReadonlySet<string> = new Set([\n \"directed\",\n \"pair\",\n \"mutual\",\n \"weight\",\n \"timeText\",\n \"originalId\",\n \"parent\",\n \"parents\",\n \"start\",\n \"end\",\n \"timestamp\",\n \"timestamps\",\n \"spells\",\n \"open\",\n \"spellsOpen\",\n \"position\",\n \"color\",\n \"size\",\n \"shape\",\n \"thickness\",\n]);\n\n/**\n * The OBO frame types.\n * @category Plugin helpers\n */\nexport type FrameKind = \"Term\" | \"Instance\" | \"Typedef\";\n\n/**\n * The frame types as a set, for checking a `type` cell.\n * @category Plugin helpers\n */\nexport const FRAME_KINDS: ReadonlySet<string> = new Set([\"Term\", \"Instance\", \"Typedef\"]);\n\n/**\n * The value of a set cell (a multi-component value as a plain array), or undefined when unset; a\n * declared default is not a value here (the formats have no defaults and say so).\n * @param column - the column\n * @param row - the row\n * @returns the value or undefined\n * @category Plugin helpers\n */\nexport function cellOf(column: Column, row: number): unknown {\n if (!column.isSet(row)) {\n return undefined;\n }\n const value: unknown = column.value(row);\n return ArrayBuffer.isView(value) ? Array.from(value as unknown as ArrayLike<number>) : value;\n}\n\n/**\n * The text of a scalar value: a number by its dtype's shortest round-tripping form (`-0` kept), a\n * boolean as `true` / `false`, a string as it is, anything else as its JSON text.\n * @param value - the value\n * @param dtype - the dtype it came from (the item dtype for a list item)\n * @returns the text\n * @category Plugin helpers\n */\nexport function textOf(value: unknown, dtype: string): string {\n switch (typeof value) {\n case \"string\":\n return value;\n case \"boolean\":\n return value ? \"true\" : \"false\";\n case \"number\":\n return formatNumber(\n value,\n dtype === \"f32\" || dtype === \"i32\" || dtype === \"u32\" || dtype === \"u8\" ? dtype : \"f64\",\n );\n default:\n return JSON.stringify(value) ?? \"null\";\n }\n}\n\n/**\n * Whether a column has the dtype of a vocabulary column (string and dict both fit a text column;\n * the other text dtype is reported, not refused).\n * @param want - the vocabulary dtype\n * @param column - the column\n * @returns true when the column can be written into the vocabulary slot\n * @category Plugin helpers\n */\nexport function fitsVocabulary(want: string, column: Column): boolean {\n switch (want) {\n case \"list\":\n case \"bool\":\n case \"json\":\n return column.dtype === want;\n default:\n return isText(column);\n }\n}\n\n/**\n * The values of a cell that may hold one value or a list of them.\n * @param value - the cell value, or undefined\n * @returns the values\n * @category Plugin helpers\n */\nexport function valuesOf(value: unknown): readonly unknown[] {\n if (value === undefined) {\n return [];\n }\n return Array.isArray(value) ? value : [value];\n}\n\n/** A column chosen for an OBO slot. */\ninterface Slot {\n /** The column, or null when the snapshot has none for the slot. */\n readonly column: Column | null;\n /** Whether a role-less column was chosen by its name; it reads back with the role (W_ROLE_ASSUMED). */\n readonly assumed: boolean;\n}\n\n/**\n * The column of a slot: the column with the role when it holds text, else a role-less text column\n * of the slot's name (which the importer reads back with the role).\n * @param table - the node or edge table\n * @param role - the role (`label` for `name`, `kind` for `relation`)\n * @param name - the name the importer gives the slot\n * @returns the column and whether its role is assumed\n * @category Plugin helpers\n */\nexport function slotColumn(table: GraphSnapshot[\"nodes\"], role: \"label\" | \"kind\", name: string): Slot {\n const byRole = table.byRole(role);\n if (byRole !== null) {\n return { column: isText(byRole) ? byRole : null, assumed: false };\n }\n const byName = table.get(name);\n if (byName !== null && byName.meta.role === null && isText(byName)) {\n return { column: byName, assumed: true };\n }\n return { column: null, assumed: false };\n}\n\n/**\n * Whether a column holds text (string or dict).\n * @param column - the column\n * @returns true for string and dict\n */\nfunction isText(column: Column): boolean {\n return column.dtype === \"string\" || column.dtype === \"dict\";\n}\n\n/**\n * The placeholder column (`graphty.placeholder`, a bool), or null.\n * @param snapshot - the snapshot\n * @returns the column\n */\nfunction placeholderColumn(snapshot: GraphSnapshot): Column | null {\n const column = snapshot.nodes.get(PLACEHOLDER_COLUMN);\n return column !== null && column.dtype === \"bool\" ? column : null;\n}\n\n/**\n * The nodes written without a frame (OBO) or a node record (OBO Graphs) because the re-import makes\n * them again as placeholders: a `graphty.placeholder` true cell, no other set cell, an id written\n * as it is, an edge that references it, and (in the flat file, where an edge is written on its\n * source's frame) no edge of its own.\n * @param snapshot - the snapshot\n * @param written - the logical edges written\n * @param options - `outgoingAllowed`: whether a placeholder may be an edge's source; `changed`: whether a node's id is rewritten\n * @param options.outgoingAllowed - whether a placeholder may be an edge's source\n * @param options.changed - whether a node's id is rewritten\n * @returns one flag per node, 1 for a node written without a frame\n * @category Plugin helpers\n */\nexport function framelessNodes(\n snapshot: GraphSnapshot,\n written: readonly number[],\n options: { readonly outgoingAllowed: boolean; readonly changed: (i: number) => boolean },\n): Uint8Array {\n const flags = new Uint8Array(snapshot.nodeCount);\n const placeholder = placeholderColumn(snapshot);\n if (placeholder === null) {\n return flags;\n }\n const { src, dst } = snapshot.edgeList();\n const referenced = new Uint8Array(snapshot.nodeCount);\n const sources = new Uint8Array(snapshot.nodeCount);\n for (const e of written) {\n referenced[dst[e]] = 1;\n if (options.outgoingAllowed) {\n referenced[src[e]] = 1;\n } else {\n sources[src[e]] = 1;\n }\n }\n const others = [...snapshot.nodes].filter((c) => c !== placeholder);\n for (let i = 0; i < snapshot.nodeCount; i++) {\n if (\n placeholder.isSet(i) &&\n placeholder.value(i) === true &&\n referenced[i] === 1 &&\n sources[i] === 0 &&\n !options.changed(i) &&\n others.every((c) => !c.isSet(i))\n ) {\n flags[i] = 1;\n }\n }\n return flags;\n}\n\n/**\n * How many nodes a re-import puts at another index: the written nodes keep their order and the\n * placeholders follow in the order the edges first reference them.\n * @param frameless - the framelessNodes() flags\n * @param references - the node indices in the order the written edges reference them\n * @returns the number of nodes whose index changes\n * @category Plugin helpers\n */\nexport function movedNodes(frameless: Uint8Array, references: Iterable<number>): number {\n const order: number[] = [];\n for (let i = 0; i < frameless.length; i++) {\n if (frameless[i] === 0) {\n order.push(i);\n }\n }\n const seen = new Uint8Array(frameless.length);\n for (const i of references) {\n if (frameless[i] === 1 && seen[i] === 0) {\n seen[i] = 1;\n order.push(i);\n }\n }\n let moved = 0;\n for (let k = 0; k < order.length; k++) {\n if (order[k] !== k) {\n moved++;\n }\n }\n return moved;\n}\n\n/**\n * Whether a value is a qualifier record as the importers make it: a non-empty object of names to a\n * text or a list of two or more texts (a name given once reads back as a text, never as a\n * one-item list), every name passing `nameOk`.\n * @param value - the value\n * @param nameOk - the name rule\n * @returns true when the record is written and read back unchanged\n * @category Plugin helpers\n */\nexport function isQualifierRecord(value: unknown, nameOk: (name: string) => boolean): boolean {\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) {\n return false;\n }\n const entries = Object.entries(value);\n return (\n entries.length > 0 &&\n entries.every(\n ([name, v]) =>\n nameOk(name) &&\n (typeof v === \"string\" ||\n (Array.isArray(v) && v.length >= 2 && v.every((item) => typeof item === \"string\"))),\n )\n );\n}\n\n/** What capabilityNotes() needs to know about the export. */\ninterface CapabilityNoteSpec {\n /** The format's capabilities. */\n readonly caps: ExportCapabilities;\n /** The label column written as the name, or null. */\n readonly label: Column | null;\n /** Whether the label is a role-less `name` column. */\n readonly labelAssumed: boolean;\n /** Where an edge column without a slot goes, for messages (\"a qualifier\"). */\n readonly edgeSlot: string;\n /** Records a note. */\n readonly note: NoteFn;\n}\n\n/**\n * The generic notes of checkCapabilities() as the ontology formats see them. No column of the\n * snapshot's own survives as a column (the formats keep only the OBO vocabulary), so the generic\n * dtype, list, json, strides and graph-attribute notes give way to the formats' own, which say\n * where each column goes (a vocabulary column written into its slot needs no note; any other\n * becomes property values, edge qualifiers or metadata). The name-change notes stand only for the\n * label and kind columns actually written into their slot. Added: the roles without a slot (a\n * node kind, an edge label) and a role-less `name` column taking the label role.\n * @param snapshot - the snapshot\n * @param common - the common options\n * @param spec - the export's facts\n * @returns the fatal error of a mixed graph under onMixedDirection \"error\", or null\n * @category Plugin helpers\n */\nexport function capabilityNotes(\n snapshot: GraphSnapshot,\n common: ResolvedExportOptions,\n spec: CapabilityNoteSpec,\n): GraphFormatError | null {\n const { label, note } = spec;\n let fatal: GraphFormatError | null = null;\n const kind = snapshot.edges.byRole(\"kind\");\n // a node label goes into the name slot and an edge kind into the relation slot, when written there;\n // an edge label has no slot (it becomes edge qualifiers or metadata), so it is never renamed\n const extras = {\n roles: SLOT_ROLES,\n nodeRoleNames: label === null ? {} : NODE_ROLE_NAMES,\n edgeRoleNames: kind !== null && isText(kind) ? EDGE_ROLE_NAMES : {},\n };\n for (const gen of checkCapabilities(snapshot, spec.caps, common, extras)) {\n if (SUPERSEDED.has(gen.code)) {\n continue;\n }\n if (gen.code === LOSS.MIXED_DIRECTION_ERROR && fatal === null) {\n fatal = new GraphFormatError(\"E_DIRECTED\", gen.message, { reason: \"mixed direction\" });\n }\n note(gen.code, gen.message, gen.column, gen.count);\n }\n slotlessRoleNotes(snapshot, spec);\n return fatal;\n}\n\n/**\n * Note the roles the ontology formats have no slot for (a node kind, an edge label), and a\n * role-less `name` column taking the label role.\n * @param snapshot - the snapshot\n * @param spec - the export's facts\n */\nfunction slotlessRoleNotes(snapshot: GraphSnapshot, spec: CapabilityNoteSpec): void {\n const { label, note } = spec;\n const nodeKind = snapshot.nodes.byRole(\"kind\");\n if (nodeKind !== null) {\n note(\n LOSS.ROLE,\n `node column \"${nodeKind.meta.name}\" (kind) is written as property values; the format has no node kind slot`,\n nodeKind.meta.name,\n nodeKind.length - nodeKind.nullCount,\n );\n }\n const edgeLabel = snapshot.edges.byRole(\"label\");\n if (edgeLabel !== null) {\n note(\n LOSS.ROLE,\n `edge column \"${edgeLabel.meta.name}\" (label) is written as ${spec.edgeSlot}; the format has no edge label slot`,\n edgeLabel.meta.name,\n edgeLabel.length - edgeLabel.nullCount,\n );\n }\n if (label !== null && spec.labelAssumed) {\n note(\n ROLE_ASSUMED_CODE,\n `node column \"name\" is written as each node's name and reads back as the label`,\n \"name\",\n label.length - label.nullCount,\n );\n }\n}\n\n/**\n * Record the columns that read back absent: a node or edge column without a set cell on a written\n * element (the importers declare a column when a value needs it).\n * @param snapshot - the snapshot\n * @param rows - the written nodes\n * @param frameless - the frameless flags (a placeholder column set only there reads back)\n * @param written - the written edges\n * @param note - records a note\n * @category Plugin helpers\n */\nexport function emptyColumnNotes(\n snapshot: GraphSnapshot,\n rows: readonly number[],\n frameless: Uint8Array,\n written: readonly number[],\n note: NoteFn,\n): void {\n const tables = [\n [\n \"node\",\n snapshot.nodes,\n (c: Column): boolean =>\n rows.some((i) => c.isSet(i)) ||\n (c.meta.name === PLACEHOLDER_COLUMN && frameless.some((f, i) => f === 1 && c.isSet(i))),\n ],\n [\"edge\", snapshot.edges, (c: Column): boolean => written.some((e) => c.isSet(e))],\n ] as const;\n for (const [domain, table, used] of tables) {\n for (const column of table) {\n const { role, name } = column.meta;\n if (\n (role !== null && (UNWRITTEN_ROLES.has(role) || (domain === \"edge\" && role === \"id\"))) ||\n used(column)\n ) {\n continue;\n }\n note(LOSS.EMPTY_COLUMN, `${domain} column \"${name}\" has no value to write; it reads back absent`, name, 0);\n }\n }\n}\n\n/**\n * Record the note of a node column written as property values.\n * @param note - the recorder\n * @param column - the column\n * @param rows - the written nodes\n * @param how - how the values are written, for the message\n * @category Plugin helpers\n */\nexport function notePropertyColumn(note: NoteFn, column: Column, rows: readonly number[], how: string): void {\n const count = rows.filter((i) => column.isSet(i)).length;\n if (count === 0) {\n return;\n }\n const role = column.meta.role === null ? \"\" : ` (its ${column.meta.role} role is lost)`;\n note(\n COLUMN_AS_PROPERTY_VALUE_CODE,\n `node column \"${column.meta.name}\" is written as ${how} and reads back inside the property_value column, not as its own column${role}`,\n column.meta.name,\n count,\n );\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { GraphFormatError } from "@graphty/graph-format";
|
|
2
|
-
import { a4 as textChunks, a5 as MAX_TEXT_LENGTH, a6 as tooLarge } from "./export-
|
|
2
|
+
import { a4 as textChunks, a5 as MAX_TEXT_LENGTH, a6 as tooLarge } from "./export-Cbt4h_0n.js";
|
|
3
3
|
const UNCLOSED_QUOTE_CODE = "E_CSV_UNCLOSED_QUOTE";
|
|
4
4
|
const BAD_QUOTE_CODE = "E_CSV_QUOTE";
|
|
5
5
|
const DELIMITER_CANDIDATES = Object.freeze([",", " ", ";", "|", " "]);
|
|
@@ -799,4 +799,4 @@ export {
|
|
|
799
799
|
splitRecords as d,
|
|
800
800
|
stripLeadingComments as s
|
|
801
801
|
};
|
|
802
|
-
//# sourceMappingURL=records-
|
|
802
|
+
//# sourceMappingURL=records-BrfHycmg.js.map
|