@graphty/graph-io 0.3.28 → 0.3.30

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (142) hide show
  1. package/dist/chunks/{choose-DrXtu_96.js → choose-BfOLq6OX.js} +2 -2
  2. package/dist/chunks/{choose-DrXtu_96.js.map → choose-BfOLq6OX.js.map} +1 -1
  3. package/dist/chunks/{constants-ikG85dT8.js → constants-M8Qsjz1C.js} +2 -2
  4. package/dist/chunks/{constants-ikG85dT8.js.map → constants-M8Qsjz1C.js.map} +1 -1
  5. package/dist/chunks/{escape-D1HPTUrP.js → escape-UMMpQZqs.js} +2 -2
  6. package/dist/chunks/{escape-D1HPTUrP.js.map → escape-UMMpQZqs.js.map} +1 -1
  7. package/dist/chunks/{export-CHd4tQE2.js → export-Dq4U8Ubq.js} +165 -148
  8. package/dist/chunks/{export-CHd4tQE2.js.map → export-Dq4U8Ubq.js.map} +1 -1
  9. package/dist/chunks/{exporter-DhtW6FxK.js → exporter-BUosqV0K.js} +34 -34
  10. package/dist/chunks/exporter-BUosqV0K.js.map +1 -0
  11. package/dist/chunks/{exporter-D23CKNqF.js → exporter-Bd_VZ9ph.js} +9 -10
  12. package/dist/chunks/exporter-Bd_VZ9ph.js.map +1 -0
  13. package/dist/chunks/{exporter-DfWTgrti.js → exporter-COgVm-ff.js} +8 -7
  14. package/dist/chunks/{exporter-DfWTgrti.js.map → exporter-COgVm-ff.js.map} +1 -1
  15. package/dist/chunks/{exporter-Cl021ZIE.js → exporter-DEk_XLLs.js} +4 -4
  16. package/dist/chunks/{exporter-Cl021ZIE.js.map → exporter-DEk_XLLs.js.map} +1 -1
  17. package/dist/chunks/{importer-BZB7iP9r.js → importer-AQ3KpNHz.js} +11 -20
  18. package/dist/chunks/importer-AQ3KpNHz.js.map +1 -0
  19. package/dist/chunks/{importer-BVRE--Un.js → importer-BsZa2Phx.js} +5 -5
  20. package/dist/chunks/importer-BsZa2Phx.js.map +1 -0
  21. package/dist/chunks/{importer-DpEW5zeG.js → importer-CV8au8gH.js} +4 -4
  22. package/dist/chunks/{importer-DpEW5zeG.js.map → importer-CV8au8gH.js.map} +1 -1
  23. package/dist/chunks/{importer-BSALvkui.js → importer-Cj4-lXlv.js} +10 -9
  24. package/dist/chunks/importer-Cj4-lXlv.js.map +1 -0
  25. package/dist/chunks/{importer-B2W_58pz.js → importer-DQsgmhxc.js} +5 -5
  26. package/dist/chunks/{importer-B2W_58pz.js.map → importer-DQsgmhxc.js.map} +1 -1
  27. package/dist/chunks/{importer-CIAzt-wo.js → importer-Dkn79TjB.js} +6 -6
  28. package/dist/chunks/importer-Dkn79TjB.js.map +1 -0
  29. package/dist/chunks/{importer-z_FL4VMb.js → importer-DwSZvMDq.js} +10 -19
  30. package/dist/chunks/importer-DwSZvMDq.js.map +1 -0
  31. package/dist/chunks/{json-elements-BAmNBZok.js → json-elements-CreeKoaH.js} +12 -16
  32. package/dist/chunks/{json-elements-BAmNBZok.js.map → json-elements-CreeKoaH.js.map} +1 -1
  33. package/dist/chunks/{ontology-export-Bab4eUA8.js → ontology-export-C5Xd3W-7.js} +2 -2
  34. package/dist/chunks/{ontology-export-Bab4eUA8.js.map → ontology-export-C5Xd3W-7.js.map} +1 -1
  35. package/dist/chunks/{records-CdlvL4RO.js → records-BwaH_2ll.js} +2 -2
  36. package/dist/chunks/{records-CdlvL4RO.js.map → records-BwaH_2ll.js.map} +1 -1
  37. package/dist/chunks/{text-DzXjAiTl.js → text-4HHe6YH3.js} +2 -2
  38. package/dist/chunks/{text-DzXjAiTl.js.map → text-4HHe6YH3.js.map} +1 -1
  39. package/dist/csv.js +22 -15
  40. package/dist/csv.js.map +1 -1
  41. package/dist/cx.js +1 -1
  42. package/dist/cx2.js +2 -2
  43. package/dist/cys.js +1 -1
  44. package/dist/dot.js +1 -1
  45. package/dist/gexf.js +9 -8
  46. package/dist/gexf.js.map +1 -1
  47. package/dist/gml.js +3 -3
  48. package/dist/graph-io.js +69 -69
  49. package/dist/graphml.js +2 -2
  50. package/dist/json.js +1 -1
  51. package/dist/neo4j.js +3 -3
  52. package/dist/obo.js +1 -1
  53. package/dist/pajek.js +1 -1
  54. package/dist/src/common/export.d.ts +6 -0
  55. package/dist/src/common/export.d.ts.map +1 -1
  56. package/dist/src/common/export.js +62 -28
  57. package/dist/src/common/export.js.map +1 -1
  58. package/dist/src/common/format.d.ts +0 -8
  59. package/dist/src/common/format.d.ts.map +1 -1
  60. package/dist/src/common/format.js +0 -10
  61. package/dist/src/common/format.js.map +1 -1
  62. package/dist/src/common/json-elements.d.ts +1 -9
  63. package/dist/src/common/json-elements.d.ts.map +1 -1
  64. package/dist/src/common/json-elements.js +2 -12
  65. package/dist/src/common/json-elements.js.map +1 -1
  66. package/dist/src/formats/csv/exporter.d.ts.map +1 -1
  67. package/dist/src/formats/csv/exporter.js +18 -7
  68. package/dist/src/formats/csv/exporter.js.map +1 -1
  69. package/dist/src/formats/cx/importer.d.ts.map +1 -1
  70. package/dist/src/formats/cx/importer.js +3 -3
  71. package/dist/src/formats/cx/importer.js.map +1 -1
  72. package/dist/src/formats/cx2/importer.d.ts.map +1 -1
  73. package/dist/src/formats/cx2/importer.js +3 -3
  74. package/dist/src/formats/cx2/importer.js.map +1 -1
  75. package/dist/src/formats/cys/exporter.d.ts.map +1 -1
  76. package/dist/src/formats/cys/exporter.js +4 -3
  77. package/dist/src/formats/cys/exporter.js.map +1 -1
  78. package/dist/src/formats/dot/exporter.js +1 -1
  79. package/dist/src/formats/dot/importer.d.ts +2 -2
  80. package/dist/src/formats/dot/importer.d.ts.map +1 -1
  81. package/dist/src/formats/dot/importer.js +7 -11
  82. package/dist/src/formats/dot/importer.js.map +1 -1
  83. package/dist/src/formats/gexf/exporter.d.ts +2 -2
  84. package/dist/src/formats/gexf/exporter.d.ts.map +1 -1
  85. package/dist/src/formats/gexf/exporter.js +7 -5
  86. package/dist/src/formats/gexf/exporter.js.map +1 -1
  87. package/dist/src/formats/gexf/schema.js +1 -1
  88. package/dist/src/formats/json/exporter.js +1 -1
  89. package/dist/src/formats/json/importer.d.ts.map +1 -1
  90. package/dist/src/formats/json/importer.js +4 -6
  91. package/dist/src/formats/json/importer.js.map +1 -1
  92. package/dist/src/formats/obo/syntax.d.ts +4 -0
  93. package/dist/src/formats/obo/syntax.d.ts.map +1 -1
  94. package/dist/src/formats/obo/syntax.js +35 -31
  95. package/dist/src/formats/obo/syntax.js.map +1 -1
  96. package/dist/src/formats/pajek/exporter.d.ts.map +1 -1
  97. package/dist/src/formats/pajek/exporter.js +5 -4
  98. package/dist/src/formats/pajek/exporter.js.map +1 -1
  99. package/dist/src/formats/pajek/importer.d.ts.map +1 -1
  100. package/dist/src/formats/pajek/importer.js +3 -7
  101. package/dist/src/formats/pajek/importer.js.map +1 -1
  102. package/dist/src/formats/pajek/syntax.d.ts +1 -1
  103. package/dist/src/formats/pajek/syntax.js +1 -1
  104. package/dist/src/formats/xgmml/constants.d.ts +1 -1
  105. package/dist/src/formats/xgmml/constants.js +1 -1
  106. package/dist/src/formats/xgmml/emit.js +1 -1
  107. package/dist/src/formats/xgmml/exporter.d.ts.map +1 -1
  108. package/dist/src/formats/xgmml/exporter.js +4 -3
  109. package/dist/src/formats/xgmml/exporter.js.map +1 -1
  110. package/dist/src/types.d.ts +6 -0
  111. package/dist/src/types.d.ts.map +1 -1
  112. package/dist/src/types.js.map +1 -1
  113. package/dist/xgmml.js +2 -2
  114. package/package.json +1 -1
  115. package/src/common/export.ts +105 -62
  116. package/src/common/format.ts +0 -11
  117. package/src/common/json-elements.ts +2 -13
  118. package/src/formats/csv/exporter.ts +19 -15
  119. package/src/formats/cx/importer.ts +2 -3
  120. package/src/formats/cx2/importer.ts +2 -3
  121. package/src/formats/cys/exporter.ts +4 -3
  122. package/src/formats/dot/exporter.ts +1 -1
  123. package/src/formats/dot/importer.ts +7 -17
  124. package/src/formats/gexf/exporter.ts +7 -5
  125. package/src/formats/gexf/schema.ts +1 -1
  126. package/src/formats/json/exporter.ts +1 -1
  127. package/src/formats/json/importer.ts +4 -7
  128. package/src/formats/obo/syntax.ts +35 -31
  129. package/src/formats/pajek/exporter.ts +5 -4
  130. package/src/formats/pajek/importer.ts +3 -13
  131. package/src/formats/pajek/syntax.ts +1 -1
  132. package/src/formats/xgmml/constants.ts +1 -1
  133. package/src/formats/xgmml/emit.ts +1 -1
  134. package/src/formats/xgmml/exporter.ts +4 -3
  135. package/src/types.ts +6 -0
  136. package/dist/chunks/exporter-D23CKNqF.js.map +0 -1
  137. package/dist/chunks/exporter-DhtW6FxK.js.map +0 -1
  138. package/dist/chunks/importer-BSALvkui.js.map +0 -1
  139. package/dist/chunks/importer-BVRE--Un.js.map +0 -1
  140. package/dist/chunks/importer-BZB7iP9r.js.map +0 -1
  141. package/dist/chunks/importer-CIAzt-wo.js.map +0 -1
  142. package/dist/chunks/importer-z_FL4VMb.js.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"exporter-DhtW6FxK.js","sources":["../../src/formats/obo/syntax.ts","../../src/formats/obo/importer.ts","../../src/formats/obo/exporter.ts"],"sourcesContent":["/**\n * The lexical layer of the OBO importer (research-obo.md section 4.1): the tag-value line, the\n * hidden `!` comment, the trailing `{name=\"value\", ...}` qualifier block, the escapes of the OBO\n * guides, quoted strings and bracketed xref lists. Pure functions over one logical line; the\n * importer joins backslash continuations and splits form feeds before calling them.\n *\n * Every function works on the RAW text (escapes still in place) and unescapes only the pieces it\n * hands back, so an escaped quote, colon, comma, brace or `!` never ends a construct.\n */\n\n/** The OBO escapes with a meaning of their own; any other `\\x` is `x` (the guides). */\nconst ESCAPES: Readonly<Record<string, string>> = Object.freeze({\n n: \"\\n\",\n t: \"\\t\",\n // the guides read `\\W` as a space; the 1.4 BNF (and fastobo) as the letter W (design 4.1)\n W: \" \",\n});\n\n/**\n * Remove the OBO escapes: `\\n` newline, `\\t` tab, `\\W` space, any other `\\x` the character x; a\n * backslash at the very end is dropped.\n * @param text - raw text\n * @returns the unescaped text\n * @category Plugin helpers\n */\nexport function unescapeObo(text: string): string {\n if (!text.includes(\"\\\\\")) {\n return text;\n }\n let out = \"\";\n for (let i = 0; i < text.length; i++) {\n const ch = text[i];\n if (ch !== \"\\\\\") {\n out += ch;\n continue;\n }\n i++;\n if (i < text.length) {\n const next = text[i];\n out += ESCAPES[next] ?? next;\n }\n }\n return out;\n}\n\n/**\n * Whether the character at `index` is escaped (preceded by an odd run of backslashes).\n * @param text - the text\n * @param index - the character's index\n * @returns true when escaped\n */\nfunction isEscaped(text: string, index: number): boolean {\n let run = 0;\n for (let i = index - 1; i >= 0 && text[i] === \"\\\\\"; i--) {\n run++;\n }\n return run % 2 === 1;\n}\n\n/**\n * Split a line at the form feeds outside quotes (the 1.4 grammar counts a form feed as a line end;\n * one inside a quoted value is text).\n * @param line - the raw line\n * @returns the pieces, the line itself when it holds no such form feed\n * @category Plugin helpers\n */\nexport function splitFormFeeds(line: string): string[] {\n if (!line.includes(\"\\f\")) {\n return [line];\n }\n const pieces: string[] = [];\n let quoted = false;\n let start = 0;\n for (let i = 0; i < line.length; i += line[i] === \"\\\\\" ? 2 : 1) {\n const ch = line[i];\n if (ch === '\"') {\n quoted = !quoted;\n } else if (ch === \"\\f\" && !quoted) {\n pieces.push(line.slice(start, i));\n start = i + 1;\n }\n }\n pieces.push(line.slice(start));\n return pieces;\n}\n\n/**\n * Whether a raw line ends with an unescaped backslash (the 1.0 / 1.2 line continuation).\n * @param line - the raw line, trailing whitespace included\n * @returns true when the line continues on the next one\n * @category Plugin helpers\n */\nexport function endsWithContinuation(line: string): boolean {\n return line.endsWith(\"\\\\\") && !isEscaped(line, line.length - 1);\n}\n\n/** A tag-value line split at its first unescaped colon. */\ninterface TagValue {\n /** The tag, unescaped and trimmed. */\n readonly tag: string;\n /** The raw text after the colon, leading whitespace removed. */\n readonly rest: string;\n}\n\n/**\n * Split a line at its first unescaped colon (values contain colons freely: `is_a: GO:0000001`).\n * @param line - the raw line, trimmed\n * @returns the tag and the rest, or null when the line has no colon\n * @category Plugin helpers\n */\nexport function splitTagValue(line: string): TagValue | null {\n for (let i = 0; i < line.length; i++) {\n if (line[i] === \"\\\\\") {\n i++;\n continue;\n }\n if (line[i] === \":\") {\n return { tag: unescapeObo(line.slice(0, i).trim()), rest: line.slice(i + 1).trimStart() };\n }\n }\n return null;\n}\n\n/**\n * Strip the hidden comment: an unescaped `!` outside quotes that starts the value or follows\n * whitespace begins a comment running to the end of the line. A `!` glued to the text before it\n * (`#!/`, `Hello!`) is text, so URLs and names are never cut. A quote opens a string only where a\n * token starts, as tokenize() reads it, so the `\"` of an unquoted `5\" pipe` is text and does not\n * hide the comment after it.\n * @param rest - the raw value\n * @returns the value before the comment, trailing whitespace removed\n * @category Plugin helpers\n */\nexport function stripComment(rest: string): string {\n let quoted = false;\n for (let i = 0; i < rest.length; i++) {\n const ch = rest[i];\n if (ch === \"\\\\\") {\n i++;\n continue;\n }\n const atStart = i === 0 || rest[i - 1] === \" \" || rest[i - 1] === \"\\t\";\n if (ch === '\"' && (quoted || atStart)) {\n quoted = !quoted;\n } else if (ch === \"!\" && !quoted && atStart) {\n return rest.slice(0, i).trimEnd();\n }\n }\n return rest.trimEnd();\n}\n\n/**\n * The qualifiers of a clause: name to value (a list when a name repeats).\n * @category Plugin helpers\n */\nexport type Qualifiers = Record<string, string | string[]>;\n\n/** A value with its trailing qualifier blocks split off. */\ninterface QualifiedValue {\n /** The raw value without the blocks, trimmed. */\n readonly value: string;\n /** The qualifiers, or null when the value has none. */\n readonly qualifiers: Qualifiers | null;\n /** A block that closes the value but does not parse, kept in `value` as text. */\n readonly badBlock: string | null;\n}\n\n/**\n * Split the trailing qualifier blocks off a value: a `{...}` is a block only when it closes the\n * value (after the comment was stripped); several blocks (`{a=\"1\"}{b=\"2\"}`, 1.2 examples) are\n * merged. A closing brace whose block does not parse is left in the value and reported. The value\n * is scanned once, so a value of many blocks costs its length, not its length times its blocks.\n * @param value - the raw value without its comment\n * @returns the value and its qualifiers\n * @category Plugin helpers\n */\nexport function splitQualifiers(value: string): QualifiedValue {\n if (!value.endsWith(\"}\")) {\n return { value, qualifiers: null, badBlock: null };\n }\n const blocks = braceBlocks(value);\n // the blocks read right to left, merged left to right below\n const parsed: Qualifiers[] = [];\n let end = value.length;\n let badBlock: string | null = null;\n while (end > 0 && value[end - 1] === \"}\" && !isEscaped(value, end - 1)) {\n const open = blocks.get(end - 1) ?? -1;\n const block = open < 0 ? null : parseQualifiers(value.slice(open + 1, end - 1));\n if (block === null) {\n badBlock = value.slice(Math.max(open, 0), end);\n break;\n }\n parsed.push(block);\n end = open;\n while (end > 0 && /\\s/.test(value[end - 1])) {\n end--;\n }\n }\n let qualifiers: Qualifiers | null = null;\n for (let i = parsed.length - 1; i >= 0; i--) {\n qualifiers ??= Object.create(null) as Qualifiers;\n for (const [name, v] of Object.entries(parsed[i])) {\n addQualifier(qualifiers, name, v);\n }\n }\n return { value: value.slice(0, end), qualifiers, badBlock };\n}\n\n/**\n * The qualifier blocks of a value in one scan: for every unescaped `}` outside quotes, the index of\n * the unescaped `{` outside quotes that opens it (-1 when a `}` came after that `{`, or none did).\n * @param value - a raw value\n * @returns the opening index by closing index\n */\nfunction braceBlocks(value: string): Map<number, number> {\n const blocks = new Map<number, number>();\n let quoted = false;\n let open = -1;\n for (let i = 0; i < value.length; i++) {\n const ch = value[i];\n if (ch === \"\\\\\") {\n i++;\n continue;\n }\n if (ch === '\"') {\n quoted = !quoted;\n } else if (!quoted && ch === \"{\") {\n open = i;\n } else if (!quoted && ch === \"}\") {\n blocks.set(i, open);\n open = -1;\n }\n }\n return blocks;\n}\n\n/**\n * The index of an unescaped `{` outside quotes that no `}` closes: a qualifier block cut short (a\n * file truncated inside it).\n * @param value - a raw value, closing blocks already split off\n * @returns the index, or -1 when every brace is closed\n * @category Plugin helpers\n */\nexport function unclosedBlock(value: string): number {\n let quoted = false;\n let open = -1;\n for (let i = 0; i < value.length; i += value[i] === \"\\\\\" ? 2 : 1) {\n const ch = value[i];\n if (ch === \"\\\\\") {\n continue;\n }\n if (ch === '\"' && open < 0) {\n quoted = !quoted;\n } else if (!quoted && ch === \"{\") {\n open = i;\n } else if (!quoted && ch === \"}\") {\n open = -1;\n }\n }\n return open;\n}\n\n/**\n * Add one qualifier, turning a repeated name into a list (a list the record owns, appended to in\n * place). The record must have a null prototype, so a name such as `__proto__` is an own key.\n * @param record - the record\n * @param name - the name\n * @param value - the value (or values)\n */\nfunction addQualifier(record: Qualifiers, name: string, value: string | string[]): void {\n const values = Array.isArray(value) ? value : [value];\n if (!Object.prototype.hasOwnProperty.call(record, name)) {\n record[name] = Array.isArray(value) ? [...value] : value;\n return;\n }\n const before = record[name];\n if (Array.isArray(before)) {\n for (const v of values) {\n before.push(v);\n }\n } else {\n record[name] = [before, ...values];\n }\n}\n\n/**\n * Parse the inside of a qualifier block: `name=\"value\"` pairs separated by commas, the 1.2\n * unquoted form (`source=PMID:1`) and missing spaces accepted. A name is everything up to `=`\n * (qualifier names may be IRIs with colons).\n * @param inner - the text between the braces\n * @returns the qualifiers, or null when the block does not parse (a pair without `=`, an unclosed quote)\n * @category Plugin helpers\n */\nexport function parseQualifiers(inner: string): Qualifiers | null {\n const out: Qualifiers = Object.create(null) as Qualifiers;\n let i = 0;\n const n = inner.length;\n let any = false;\n while (i < n) {\n while (i < n && (inner[i] === \" \" || inner[i] === \"\\t\" || inner[i] === \",\")) {\n i++;\n }\n if (i >= n) {\n break;\n }\n const eq = inner.indexOf(\"=\", i);\n if (eq < 0) {\n return null;\n }\n const name = unescapeObo(inner.slice(i, eq).trim());\n if (name.length === 0 || name.includes('\"')) {\n return null;\n }\n i = eq + 1;\n while (i < n && (inner[i] === \" \" || inner[i] === \"\\t\")) {\n i++;\n }\n let value: string;\n if (inner[i] === '\"') {\n const end = closingQuote(inner, i + 1);\n if (end < 0) {\n return null;\n }\n value = unescapeObo(inner.slice(i + 1, end));\n i = end + 1;\n } else {\n let end = i;\n while (end < n && inner[end] !== \",\") {\n end += inner[end] === \"\\\\\" ? 2 : 1;\n }\n value = unescapeObo(inner.slice(i, end).trim());\n i = end;\n }\n addQualifier(out, name, value);\n any = true;\n }\n return any ? out : null;\n}\n\n/**\n * The index of the unescaped closing quote.\n * @param text - the text\n * @param from - the index after the opening quote\n * @returns the index, or -1 when the text ends first\n */\nfunction closingQuote(text: string, from: number): number {\n for (let i = from; i < text.length; i++) {\n if (text[i] === \"\\\\\") {\n i++;\n } else if (text[i] === '\"') {\n return i;\n }\n }\n return -1;\n}\n\n/**\n * One token of a value.\n * @category Plugin helpers\n */\nexport interface Token {\n /** A bare word, a quoted string or a bracketed list. */\n readonly kind: \"word\" | \"quoted\" | \"list\";\n /** The token's text: unescaped for a word or a quoted string, raw inside the brackets for a list. */\n readonly text: string;\n /** Whether the quote or bracket was never closed (the token runs to the end of the value). */\n readonly unterminated: boolean;\n}\n\n/**\n * Split a value (comment and qualifiers removed) into words, quoted strings and bracketed lists.\n * Whitespace separates tokens; an escaped space belongs to its word.\n * @param value - the raw value\n * @returns the tokens\n * @category Plugin helpers\n */\nexport function tokenize(value: string): Token[] {\n const tokens: Token[] = [];\n const n = value.length;\n let i = 0;\n while (i < n) {\n const ch = value[i];\n if (ch === \" \" || ch === \"\\t\") {\n i++;\n continue;\n }\n if (ch === '\"') {\n const end = closingQuote(value, i + 1);\n const stop = end < 0 ? n : end;\n // a 1.4 language tag glued to the closing quote (\"chat\"@fr) is kept with the text, as an\n // unquoted chat@fr is (research-obo.md 4.1: no language is split out)\n let after = stop + 1;\n if (end >= 0 && value[after] === \"@\") {\n while (after < n && value[after] !== \" \" && value[after] !== \"\\t\") {\n after++;\n }\n }\n const suffix = end < 0 ? \"\" : value.slice(stop + 1, after);\n tokens.push({\n kind: \"quoted\",\n text: unescapeObo(value.slice(i + 1, stop)) + suffix,\n unterminated: end < 0,\n });\n i = after;\n continue;\n }\n if (ch === \"[\") {\n const end = closingBracket(value, i + 1);\n const stop = end < 0 ? n : end;\n tokens.push({ kind: \"list\", text: value.slice(i + 1, stop), unterminated: end < 0 });\n i = stop + 1;\n continue;\n }\n let end = i;\n while (end < n && value[end] !== \" \" && value[end] !== \"\\t\") {\n end += value[end] === \"\\\\\" ? 2 : 1;\n }\n tokens.push({ kind: \"word\", text: unescapeObo(value.slice(i, Math.min(end, n))), unterminated: false });\n i = end;\n }\n return tokens;\n}\n\n/**\n * The index of the unescaped `]` outside quotes closing a list.\n * @param text - the text\n * @param from - the index after `[`\n * @returns the index, or -1 when the text ends first\n */\nfunction closingBracket(text: string, from: number): number {\n let quoted = false;\n for (let i = from; i < text.length; i++) {\n const ch = text[i];\n if (ch === \"\\\\\") {\n i++;\n } else if (ch === '\"') {\n quoted = !quoted;\n } else if (ch === \"]\" && !quoted) {\n return i;\n }\n }\n return -1;\n}\n\n/**\n * One cross-reference: `ID \"description\" {qualifiers}`.\n * @category Plugin helpers\n */\nexport interface Xref {\n /** The id (may hold spaces: `NIST Chemistry WebBook:110-63-4`, which owlapi reads). */\n readonly id: string;\n /** The description, or null. */\n readonly description: string | null;\n /** Per-xref qualifiers (OBO 1.2 inside a list), or null. */\n readonly qualifiers: Qualifiers | null;\n /** Whether the description's quote was never closed (it runs to the end). */\n readonly unterminated: boolean;\n}\n\n/**\n * Read one cross-reference: the id is the text before the first unescaped quote, the quoted\n * string its description, a closing block its qualifiers.\n * @param raw - the raw text of one xref\n * @returns the xref, or null when it has no id\n * @category Plugin helpers\n */\nexport function parseXref(raw: string): Xref | null {\n const { value, qualifiers } = splitQualifiers(raw.trim());\n let quote = -1;\n for (let i = 0; i < value.length; i++) {\n if (value[i] === \"\\\\\") {\n i++;\n } else if (value[i] === '\"') {\n quote = i;\n break;\n }\n }\n const id = unescapeObo((quote < 0 ? value : value.slice(0, quote)).trim());\n if (id.length === 0) {\n return null;\n }\n let description: string | null = null;\n let unterminated = false;\n if (quote >= 0) {\n const end = closingQuote(value, quote + 1);\n unterminated = end < 0;\n description = unescapeObo(value.slice(quote + 1, end < 0 ? value.length : end));\n }\n return { id, description, qualifiers, unterminated };\n}\n\n/**\n * Split the inside of a bracketed list into xrefs at the unescaped commas outside quotes and\n * braces (a solitary xref needs no escaping of its commas only outside a list).\n * @param inner - the raw text between the brackets\n * @returns the xrefs, in order\n * @category Plugin helpers\n */\nexport function parseXrefList(inner: string): Xref[] {\n const out: Xref[] = [];\n let quoted = false;\n let depth = 0;\n let start = 0;\n const flush = (end: number): void => {\n const xref = parseXref(inner.slice(start, end));\n if (xref !== null) {\n out.push(xref);\n }\n };\n for (let i = 0; i < inner.length; i++) {\n const ch = inner[i];\n if (ch === \"\\\\\") {\n i++;\n } else if (ch === '\"') {\n quoted = !quoted;\n } else if (!quoted && ch === \"{\") {\n depth++;\n } else if (!quoted && ch === \"}\") {\n depth = Math.max(0, depth - 1);\n } else if (!quoted && depth === 0 && ch === \",\") {\n flush(i);\n start = i + 1;\n }\n }\n flush(inner.length);\n return out;\n}\n\n/**\n * Whether the raw value holds an unescaped `{` or `}` outside quotes and outside a bracketed xref\n * list (a brace mid-value that is not a closing qualifier block is literal text the writer should\n * have escaped).\n * @param value - the raw value, qualifiers already split off\n * @returns true when a stray brace is present\n * @category Plugin helpers\n */\nexport function hasStrayBrace(value: string): boolean {\n let quoted = false;\n let listed = false;\n for (let i = 0; i < value.length; i++) {\n const ch = value[i];\n if (ch === \"\\\\\") {\n i++;\n } else if (ch === '\"') {\n quoted = !quoted;\n } else if (!quoted && (ch === \"[\" || ch === \"]\")) {\n // inside an xref list a brace opens that xref's qualifiers (OBO 1.2)\n listed = ch === \"[\";\n } else if (!quoted && !listed && (ch === \"{\" || ch === \"}\")) {\n return true;\n }\n }\n return false;\n}\n\n// ============================================================ the writer side\n\n/** A carriage return, a CRLF pair or a form feed: line ends OBO text cannot carry. */\nconst LINE_ENDS = /\\r\\n|\\r|\\f/g;\n\n/**\n * Whether a text holds a carriage return or a form feed, which the OBO line grammar reads as a line\n * end wherever it stands and no escape can spell; the writers turn them into `\\n`.\n * @param text - the text\n * @returns true when the text loses a character on the way through an OBO file\n * @category Plugin helpers\n */\nexport function hasLineEnd(text: string): boolean {\n return text.includes(\"\\r\") || text.includes(\"\\f\");\n}\n\n/**\n * Escape text for a quoted OBO string (`def: \"...\"`, a synonym, a qualifier value): backslash,\n * quote, newline and tab. A carriage return or form feed becomes a newline (see hasLineEnd()).\n * `\\W` is never written: graph-io reads it as a space, fastobo and the 1.4 BNF as the letter W.\n * @param text - the text\n * @returns the escaped text, without the quotes\n * @category Plugin helpers\n */\nexport function escapeOboQuoted(text: string): string {\n return text.replaceAll(LINE_ENDS, \"\\n\").replaceAll(/[\\\\\"\\n\\t]/g, (ch) => {\n switch (ch) {\n case \"\\n\":\n return String.raw`\\n`;\n case \"\\t\":\n return String.raw`\\t`;\n default:\n return `\\\\${ch}`;\n }\n });\n}\n\n/**\n * Escape text for an unquoted OBO value (`name:`, `comment:`, an xref id, an unknown tag): what\n * escapeOboQuoted() escapes plus `!` (a comment), `{` and `}` (a qualifier block), `[`, `]` and `,`\n * (an xref list) and `\"` (a quoted string). The reader trims an unquoted value, so its leading\n * and trailing spaces cannot be kept.\n * @param text - the text\n * @returns the escaped text\n * @category Plugin helpers\n */\nexport function escapeOboValue(text: string): string {\n return escapeOboQuoted(text).replaceAll(/[!{}[\\],]/g, (ch) => `\\\\${ch}`);\n}\n\n/**\n * Whether a text can stand as one OBO word (an id, a relation, a subset or synonym type name): not\n * empty, no whitespace, no control character (the importer refuses an id holding one), no `!`, `{`\n * or `}`. escapeOboWord() escapes what else would end it or turn\n * it into another token (a backslash, a quote, a leading `[`).\n * @param text - the text\n * @returns true when the text is a word\n * @category Plugin helpers\n */\nexport function isOboWord(text: string): boolean {\n return text.length > 0 && !NOT_IN_WORD.test(text);\n}\n\n/**\n * A character an OBO word cannot hold: whitespace, a control character, `!`, `{` or `}`.\n * @category Plugin helpers\n */\nexport const NOT_IN_WORD = /[\\s!{}\\p{Cc}]/u;\n\n/**\n * Write a word (see isOboWord()): a backslash and a quote escaped, and a leading `[` (which would\n * open an xref list).\n * @param word - a text isOboWord() accepts\n * @returns the text to write\n * @category Plugin helpers\n */\nexport function escapeOboWord(word: string): string {\n const out = word.replaceAll(/[\\\\\"]/g, (ch) => `\\\\${ch}`);\n return out.startsWith(\"[\") ? `\\\\${out}` : out;\n}\n\n/**\n * Whether a text can be a qualifier name: not empty, no surrounding space, none of `=`, `\"`, `,`,\n * `{`, `}`, `[`, `]`, `!`, a backslash or a line end (the reader takes a name as everything up to\n * the first `=`, unescaped only after the split).\n * @param name - the name\n * @returns true when the name is written as it is\n * @category Plugin helpers\n */\nexport function isQualifierName(name: string): boolean {\n return name.length > 0 && name === name.trim() && !/[=\",{}[\\]!\\\\\\n\\r\\t\\f]/.test(name);\n}\n\n/**\n * A qualifier block: `{name=\"value\", ...}`, a list value as one pair per item.\n * @param pairs - the name / value pairs, in order (names isQualifierName() accepts)\n * @returns the block with a leading space, or \"\" when there are no pairs\n * @category Plugin helpers\n */\nexport function qualifierBlock(pairs: readonly (readonly [string, string])[]): string {\n if (pairs.length === 0) {\n return \"\";\n }\n const items = pairs.map(([name, value]) => `${name}=\"${escapeOboQuoted(value)}\"`);\n return ` {${items.join(\", \")}}`;\n}\n","/**\n * The OBO importer (design section 4; research-obo.md): the line-oriented OBO flat file format of\n * the Gene Ontology and the OBO Foundry, versions 1.0, 1.2 and 1.4 read as their union (real files\n * do not say which they follow: the GO writes `format-version: 1.2` and uses 1.4 tags), streamed\n * through the common LineReader.\n *\n * `[Term]` and `[Instance]` frames are nodes; `is_a`, `relationship` and `instance_of` clauses are\n * directed edges from the frame to the target, with the relation in a `relation` dict column (role\n * `kind`) and the trailing qualifier block in a `qualifiers` json column. `[Typedef]` frames are\n * metadata (`meta.extra.obo.typedefs`) unless `typedefs: \"nodes\"`. Every other tag fills the\n * column of its name (src/common/ontology.ts); an unknown tag is kept in `obo.unrecognized`.\n * Frames that share an id are merged (spec 4.1.1): list clauses take the union, a single-valued\n * clause keeps the first. A target no frame declares becomes a placeholder node (the guide's\n * recommended reading; ontologies point into their imports this way) unless `addMissingNodes` is\n * false.\n *\n * ponytail: the frames are held until the end of the file (merging needs every frame of an id,\n * dangling detection the whole id set), so memory is about twice the snapshot's; a two-pass reader\n * would lift that for files beyond a few hundred megabytes.\n */\n\nimport {\n type ColumnHandle,\n GraphFormatError,\n type GraphMetaPatch,\n type GraphSink,\n INVALID_INDEX,\n type NodeId,\n} from \"@graphty/graph-format\";\n\nimport { declareResolved, RENAMED_CODE, ROLE_TAKEN_CODE } from \"../../common/attributes.js\";\nimport {\n BAD_VALUE_CODE,\n DANGLING_REFERENCE_CODE,\n DUPLICATE_ATTRIBUTE_CODE,\n DUPLICATE_NODE_CODE,\n ELEMENT_ISSUE,\n EMPTY_INPUT_CODE,\n ENCODING_FALLBACK_CODE,\n INPUT_ISSUE,\n INVALID_ENCODING_CODE,\n INVALID_UTF8_CODE,\n MISSING_ID_CODE,\n OPTION_IGNORED_CODE,\n UNKNOWN_ELEMENT_CODE,\n UNKNOWN_ENCODING_CODE,\n} from \"../../common/codes.js\";\nimport { DirectionResolver } from \"../../common/direction.js\";\nimport { ID_MERGED_CODE, IdCoercer } from \"../../common/ids.js\";\nimport { LineReader, throwIfAborted } from \"../../common/input.js\";\nimport { OBO_NODE_COLUMNS, oboColumnDecl, PLACEHOLDER_COLUMN, SYNONYM_SCOPES } from \"../../common/ontology.js\";\nimport {\n type ImportFormatDefaults,\n reportSinkOptions,\n reportUnusedOptions,\n resolveImportOptions,\n SINK_OPTION_CODE,\n} from \"../../common/options.js\";\nimport { agree, plural } from \"../../common/plural.js\";\nimport { ImportReportBuilder } from \"../../common/report.js\";\nimport { type CommonImportOptions, type GraphImporter, type ImportInput, type ImportReport } from \"../../types.js\";\nimport {\n endsWithContinuation,\n hasStrayBrace,\n parseXref,\n parseXrefList,\n type Qualifiers,\n splitFormFeeds,\n splitQualifiers,\n splitTagValue,\n stripComment,\n type Token,\n tokenize,\n unclosedBlock,\n unescapeObo,\n type Xref,\n} from \"./syntax.js\";\n\n/**\n * The format-specific options of the OBO importer.\n * @category Built-in formats\n */\nexport interface OboImportOptions extends CommonImportOptions {\n /**\n * \"keep\" reads obsolete terms as nodes with `is_obsolete` set to true; \"drop\" leaves them and\n * their edges out.\n * @defaultValue \"keep\"\n */\n obsolete?: \"keep\" | \"drop\" | undefined;\n /**\n * \"metadata\" keeps the `[Typedef]` frames (relation definitions) in\n * `snapshot.meta.extra.obo.typedefs`; \"nodes\" makes them nodes too, with their `is_a` edges.\n * @defaultValue \"metadata\"\n */\n typedefs?: \"metadata\" | \"nodes\" | undefined;\n}\n\n/**\n * Issue codes of the OBO importer.\n * @category Built-in formats\n */\nexport const OBO_ISSUE = Object.freeze({\n ...INPUT_ISSUE,\n ...ELEMENT_ISSUE,\n /** The input is empty or whitespace. The import stops. */\n EMPTY_INPUT: EMPTY_INPUT_CODE,\n /** The input is not valid UTF-8. The import stops. */\n INVALID_UTF8: INVALID_UTF8_CODE,\n /**\n * Some bytes are not valid in the encoding that was chosen (by a byte order mark or the `encoding` option). The\n * import stops.\n */\n INVALID_ENCODING: INVALID_ENCODING_CODE,\n /** Bytes that are not UTF-8 were read as windows-1252. */\n ENCODING_FALLBACK: ENCODING_FALLBACK_CODE,\n /** A declared encoding the platform cannot decode was ignored. */\n UNKNOWN_ENCODING: UNKNOWN_ENCODING_CODE,\n /** A frame without an `id` clause; the frame is skipped. */\n MISSING_ID: MISSING_ID_CODE,\n /** A clause whose value cannot be read (a boolean other than true / false, a relationship with one or three values); the clause is skipped. */\n BAD_VALUE: BAD_VALUE_CODE,\n /** Two frames have the same id, so they were merged into one node. */\n DUPLICATE_NODE: DUPLICATE_NODE_CODE,\n /** A tag that may appear once per frame appears twice; the first value is kept. */\n DUPLICATE_ATTRIBUTE: DUPLICATE_ATTRIBUTE_CODE,\n /** An unknown tag (kept in `obo.unrecognized`) or frame type (skipped), once per name. */\n UNKNOWN_ELEMENT: UNKNOWN_ELEMENT_CODE,\n /** A target no frame declares: a placeholder node was made, or the edge dropped under addMissingNodes false. */\n DANGLING_REFERENCE: DANGLING_REFERENCE_CODE,\n /** A line without a colon, an unterminated quote, a def without its xref list, a qualifier block that does not parse, an unescaped brace. */\n SYNTAX: \"W_OBO_SYNTAX\",\n /**\n * Nothing in the input looks like OBO: there is no frame header and no header tag. It may be an HTML page, a JSON\n * or GML file, or UTF-16 text without a byte order mark. The import stops.\n */\n NOT_OBO: \"E_OBO_NOT_OBO\",\n /**\n * The header has no `format-version` (OBO 1.2 and 1.4 require one), or names a version other than 1.0, 1.2 or 1.4.\n * The file is read accepting the tags of every version.\n */\n FORMAT_VERSION: \"W_OBO_FORMAT_VERSION\",\n /** The frame's `id` is not its first clause; it is used anyway. */\n ID_NOT_FIRST: \"W_OBO_ID_NOT_FIRST\",\n /** A synonym without a scope in a file that does not say 1.2, or with a scope that is not one of the four. */\n SYNONYM_SCOPE: \"W_OBO_SYNONYM_SCOPE\",\n /** A relation, subset or synonym type that nothing declares. */\n UNDECLARED: \"W_OBO_UNDECLARED\",\n /** One id for a Term and a Typedef (or an Instance); the Term (the first node frame) is the node. */\n ID_KIND_CLASH: \"W_OBO_ID_KIND_CLASH\",\n /** A frame has only one `intersection_of` or `union_of` clause, where OBO needs at least two. */\n CARDINALITY: \"W_OBO_CARDINALITY\",\n /** An obsolete term with is_a / relationship, or replaced_by / consider on a term that is not obsolete. */\n OBSOLETION: \"W_OBO_OBSOLETION\",\n /** An OBO 1.0 / 1.2 tag read as its 1.4 meaning (exact_synonym, xref_analog, use_term, typeref, version). */\n DEPRECATED_TAG: \"W_OBO_DEPRECATED_TAG\",\n /** A backslash line continuation (deprecated in 1.4). */\n DEPRECATED_SYNTAX: \"W_OBO_DEPRECATED_SYNTAX\",\n /**\n * A header clause whose meaning graph-io does not apply (`import`, `id-mapping`, the `treat-xrefs` macros,\n * `owl-axioms`); it is kept in `snapshot.meta.extra.obo.header`.\n */\n HEADER_NOT_APPLIED: \"W_OBO_HEADER_NOT_APPLIED\",\n /** Obsolete terms and their edges left out under obsolete: \"drop\". */\n OBSOLETE_DROPPED: \"W_OBO_OBSOLETE_DROPPED\",\n /**\n * Two different id texts became the same number because `ids` is \"number\" (for example, \"042\" and \"42\"), so their nodes\n * were merged.\n */\n ID_MERGED: ID_MERGED_CODE,\n /** An OBO attribute was renamed `<name>#obo` because another attribute already has its name. */\n COLUMN_RENAMED: RENAMED_CODE,\n /**\n * You read into a graph builder that already has an id, label or position attribute, so this file's one is kept as\n * a plain attribute.\n */\n ROLE_TAKEN: ROLE_TAKEN_CODE,\n /** You set an option this format does not use; it had no effect. The message names the option. */\n OPTION_IGNORED: OPTION_IGNORED_CODE,\n /**\n * You read into your own graph builder, which was created with a different `addMissingNodes`, `duplicateEdges`,\n * `selfLoops` or `weightDtype` than the option you passed; the builder's setting applies.\n */\n SINK_OPTION: SINK_OPTION_CODE,\n});\n\n/** The common options the OBO importer reads. */\nconst USED_OPTIONS: ReadonlySet<keyof CommonImportOptions> = new Set<keyof CommonImportOptions>([\n \"ids\",\n \"addMissingNodes\",\n \"duplicateEdges\",\n \"selfLoops\",\n \"onMixedDirection\",\n \"weightDtype\",\n \"errorLimit\",\n \"signal\",\n \"onProgress\",\n \"encoding\",\n \"restoreMangledIds\",\n]);\n\n/** The property_value relation under which the exporter keeps an id it rewrote (`sanitizeIds: \"mangle\"`). */\nconst ORIGINAL_ID = \"graphty:originalId\";\n\nconst DEFAULTS: ImportFormatDefaults = { ids: \"keep\", defaultDirected: true, weightFrom: null };\n\n/** Frames between two checks of the cancellation signal. */\nconst ABORT_CHECK_INTERVAL = 64;\n\n/** Bytes of the head sniff() reads. */\nconst SNIFF_BYTES = 4096;\n\nconst FRAME_KINDS: ReadonlySet<string> = new Set([\"Term\", \"Typedef\", \"Instance\"]);\n\n/** Header tags kept but not applied (design 4.3, W_OBO_HEADER_NOT_APPLIED). */\nconst NOT_APPLIED_HEADER = /^(import|typeref|id-mapping|default-relationship-id-prefix|owl-axioms|treat-xrefs-as-.*)$/;\n\n/** Deprecated header tags and what they are now. */\nconst DEPRECATED_HEADER: ReadonlyMap<string, string> = new Map([\n [\"typeref\", \"import\"],\n [\"version\", \"data-version\"],\n]);\n\n/**\n * The 1.0 / 1.2 frame tags read as their 1.4 meaning: tag to [1.4 tag, synonym scope].\n * @category Plugin helpers\n */\nexport const DEPRECATED_TAGS: ReadonlyMap<string, readonly [string, string | null]> = new Map([\n [\"exact_synonym\", [\"synonym\", \"EXACT\"]],\n [\"narrow_synonym\", [\"synonym\", \"NARROW\"]],\n [\"broad_synonym\", [\"synonym\", \"BROAD\"]],\n [\"related_synonym\", [\"synonym\", \"RELATED\"]],\n [\"xref_analog\", [\"xref\", null]],\n [\"xref_unk\", [\"xref\", null]],\n [\"xref_unknown\", [\"xref\", null]],\n [\"use_term\", [\"consider\", null]],\n]);\n\n/** Relations every OBO file may use without a Typedef (the 1.2 built-ins). */\nconst BUILTIN_RELATIONS: ReadonlySet<string> = new Set([\n \"is_a\",\n \"instance_of\",\n \"disjoint_from\",\n \"inverse_of\",\n \"union_of\",\n \"intersection_of\",\n]);\n\n/**\n * Single-valued text tags (first value kept).\n * @category Plugin helpers\n */\nexport const TEXT_TAGS: ReadonlySet<string> = new Set([\n \"name\",\n \"namespace\",\n \"comment\",\n \"created_by\",\n \"creation_date\",\n \"domain\",\n \"range\",\n \"inverse_of\",\n]);\n\n/**\n * Single-valued boolean tags.\n * @category Plugin helpers\n */\nexport const BOOL_TAGS: ReadonlySet<string> = new Set(\n Object.keys(OBO_NODE_COLUMNS).filter((name) => OBO_NODE_COLUMNS[name].dtype === \"bool\"),\n);\n\n/**\n * Tags whose value is one id, collected in a list column.\n * @category Plugin helpers\n */\nexport const ID_LIST_TAGS: ReadonlySet<string> = new Set([\n \"alt_id\",\n \"subset\",\n \"replaced_by\",\n \"consider\",\n \"union_of\",\n \"equivalent_to\",\n \"disjoint_from\",\n \"transitive_over\",\n \"disjoint_over\",\n]);\n\n/** Header tags the specification allows once (the first is kept). */\nconst SINGLE_HEADER_TAGS: ReadonlySet<string> = new Set([\n \"format-version\",\n \"data-version\",\n \"version\",\n \"date\",\n \"saved-by\",\n \"auto-generated-by\",\n \"default-namespace\",\n \"ontology\",\n \"default-relationship-id-prefix\",\n]);\n\n/** The format versions the importer knows (it reads their union). */\nconst KNOWN_VERSION = /^(GO_)?1\\.[024]$/;\n\n/** Tags whose value is an id, where a qualifier block cut short by a truncated file is dropped. */\nconst ID_VALUE_TAGS: ReadonlySet<string> = new Set([\n ...ID_LIST_TAGS,\n \"is_a\",\n \"instance_of\",\n \"relationship\",\n \"intersection_of\",\n]);\n\n/** Warnings listed per code before the rest are summed up in one (a file of 50k unknown tags). */\nconst MAX_TALLIES_PER_CODE = 100;\n\n/**\n * Whether a text holds a control character other than tab, line feed, form feed (a line end in\n * the 1.4 grammar, text inside quotes) and carriage return.\n * @param text - the text\n * @returns true when it does\n */\nfunction hasControl(text: string): boolean {\n for (const ch of text) {\n if ((ch < \" \" && ch !== \"\\t\" && ch !== \"\\n\" && ch !== \"\\f\" && ch !== \"\\r\") || ch === \"\\x7f\") {\n return true;\n }\n }\n return false;\n}\n\n/**\n * Whether a tag could name an OBO tag: no whitespace, control characters or the punctuation of\n * other formats (`{`, `\"`, `<`, brackets, parentheses).\n * @param tag - the tag\n * @returns true for a plausible tag\n */\nfunction isTagName(tag: string): boolean {\n return tag.length > 0 && !hasControl(tag) && !/[\\s{}\"<>[\\]()]/.test(tag);\n}\n\n/**\n * A record with no prototype, so a key named after an Object.prototype member (`__proto__`,\n * `constructor`, `toString`) is an own key like any other.\n * @returns the empty record\n */\nfunction ownRecord<T>(): Record<string, T> {\n return Object.create(null) as Record<string, T>;\n}\n\n/**\n * Append a value to the list of a key in a null-prototype record.\n * @param map - the record\n * @param key - the key\n * @param value - the value\n */\nfunction append<T>(map: Record<string, T[]>, key: string, value: T): void {\n if (Object.hasOwn(map, key)) {\n map[key].push(value);\n } else {\n map[key] = [value];\n }\n}\n\n/**\n * Tags that only a Typedef frame may carry (elsewhere they are unrecognized).\n * @category Plugin helpers\n */\nexport const TYPEDEF_TAGS: ReadonlySet<string> = new Set([\n \"domain\",\n \"range\",\n \"inverse_of\",\n \"transitive_over\",\n \"disjoint_over\",\n \"holds_over_chain\",\n \"equivalent_to_chain\",\n \"expand_assertion_to\",\n \"expand_expression_to\",\n \"is_cyclic\",\n \"is_reflexive\",\n \"is_symmetric\",\n \"is_anti_symmetric\",\n \"is_asymmetric\",\n \"is_transitive\",\n \"is_functional\",\n \"is_inverse_functional\",\n \"is_metadata_tag\",\n \"is_class_level\",\n]);\n\ntype FrameKind = \"Term\" | \"Typedef\" | \"Instance\";\n\n/** One clause as read: the tag and the raw value without its comment. */\ninterface Clause {\n readonly tag: string;\n readonly value: string;\n readonly line: number;\n}\n\n/** An edge held until the end of the file. */\ninterface PendingEdge {\n readonly relation: string;\n readonly target: string;\n readonly qualifiers: Qualifiers | null;\n readonly line: number;\n}\n\n/** Everything read for one id, over all of its frames. */\ninterface NodeRecord {\n readonly id: string;\n readonly kind: FrameKind;\n readonly line: number;\n /** Single values and whole-cell values by column. */\n readonly values: Map<string, unknown>;\n /** List and json-list cells by column. */\n readonly lists: Map<string, unknown[]>;\n readonly edges: PendingEdge[];\n /** The clauses already applied (spec 4.1.1: an identical clause counts once). */\n readonly seen: Set<string>;\n /** Typedef frames: every clause by tag, raw, for `meta.extra.obo.typedefs`. */\n readonly raw: Record<string, string[]>;\n}\n\n/** Where a clause is: its line and the id of its frame. */\ninterface Where {\n readonly line: number;\n readonly element: string;\n}\n\n/** A warning counted while reading and recorded once at the end. */\ninterface Tally {\n readonly category: \"parse-error\" | \"validation-error\" | \"coercion\" | \"unsupported\" | \"merged\";\n readonly code: string;\n readonly element: string;\n readonly what: string;\n readonly line: number;\n count: number;\n}\n\n/** The OBO-specific options, resolved. */\ninterface ResolvedOboOptions {\n readonly obsolete: \"keep\" | \"drop\";\n readonly typedefs: \"metadata\" | \"nodes\";\n}\n\n/**\n * Resolve the OBO-specific options.\n * @param options - the caller's options\n * @returns the resolved options; E_UNSUPPORTED for a value outside its set\n */\nfunction resolveOboOptions(options: OboImportOptions | undefined): ResolvedOboOptions {\n const obsolete = options?.obsolete ?? \"keep\";\n const typedefs = options?.typedefs ?? \"metadata\";\n if (obsolete !== \"keep\" && obsolete !== \"drop\") {\n throw unsupported(\"obsolete\", obsolete, [\"keep\", \"drop\"]);\n }\n if (typedefs !== \"metadata\" && typedefs !== \"nodes\") {\n throw unsupported(\"typedefs\", typedefs, [\"metadata\", \"nodes\"]);\n }\n return { obsolete, typedefs };\n}\n\n/**\n * The E_UNSUPPORTED error of an option outside its set.\n * @param option - the option name\n * @param found - the value\n * @param supported - the allowed values\n * @returns the error\n */\nfunction unsupported(option: string, found: unknown, supported: readonly string[]): Error {\n return new GraphFormatError(\n \"E_UNSUPPORTED\",\n `option ${option}: ${JSON.stringify(found)} is not one of ${supported.join(\", \")}`,\n {\n option,\n found,\n supported,\n },\n );\n}\n\n/** One import's state. */\nclass OboReader {\n private readonly report: ImportReportBuilder;\n\n private readonly signal: AbortSignal | null;\n\n /** Header clauses by tag, raw, in order. */\n private readonly header: Record<string, string[]> = ownRecord<string[]>();\n\n /** Whether `[Typedef]` frames are nodes (typedefs \"nodes\"). */\n private readonly typedefsAsNodes: boolean;\n\n /** Whether any frame header was read. */\n private frameSeen = false;\n\n /** Header clauses whose tag could be an OBO tag. */\n private tagClauses = 0;\n\n /** The first line that is not a frame header, a comment or a tag-value line with a plausible tag. */\n private firstBadLine: number | null = null;\n\n private version: string | null = null;\n\n private defaultNamespace: string | null = null;\n\n private readonly subsets = new Set<string>();\n\n /** Declared synonym types and their default scope (null: none). */\n private readonly synonymTypes = new Map<string, string | null>();\n\n /** Node frames (Term, Instance) by id, in first-appearance order. */\n readonly nodes = new Map<string, NodeRecord>();\n\n /** Typedef frames by id. */\n readonly typedefs = new Map<string, NodeRecord>();\n\n private readonly tallies = new Map<string, Tally>();\n\n /** The frame being read: its kind (null for an unknown frame type), name and clauses. */\n private frame: { kind: FrameKind | null; name: string; line: number; clauses: Clause[] } | null = null;\n\n /** The frames of an unknown type, raw, for `meta.extra.obo.unknownFrames`. */\n readonly unknownFrames: { type: string; clauses: Record<string, string[]> }[] = [];\n\n private framesSinceCheck = 0;\n\n /** Whether any significant line was read. */\n significant = false;\n\n /**\n * Create a reader.\n * @param report - the report\n * @param signal - the cancellation signal\n * @param typedefsAsNodes - whether `[Typedef]` frames are nodes\n */\n constructor(report: ImportReportBuilder, signal: AbortSignal | null, typedefsAsNodes: boolean) {\n this.report = report;\n this.signal = signal;\n this.typedefsAsNodes = typedefsAsNodes;\n }\n\n /**\n * Read one logical line.\n * @param text - the line, continuation joined\n * @param line - its 1-based number\n */\n line(text: string, line: number): void {\n const t = text.trim();\n if (t.length === 0) {\n return;\n }\n this.significant = true;\n if (t.startsWith(\"!\")) {\n return;\n }\n if (t.startsWith(\"[\") && this.frameHeader(t, line)) {\n return;\n }\n // the comment goes first, so a colon inside it never makes `foo ! a:b` a tag-value line\n const tv = splitTagValue(stripComment(t));\n if (tv === null || tv.tag.length === 0) {\n this.firstBadLine ??= line;\n const what = tv === null ? \"a line without a colon was skipped\" : \"a line without a tag was skipped\";\n this.tally(\"parse-error\", OBO_ISSUE.SYNTAX, what, \"line\", line);\n return;\n }\n const clause: Clause = { tag: tv.tag, value: stripComment(tv.rest), line };\n if (this.frame === null) {\n if (isTagName(tv.tag)) {\n this.tagClauses++;\n } else {\n this.firstBadLine ??= line;\n }\n this.headerClause(clause);\n } else {\n this.frame.clauses.push(clause);\n }\n }\n\n /**\n * Start a frame at a line opening with `[`: a well-formed header, or one damaged so that only a\n * frame header can be meant (a known frame name, or no colon: `[Term`, `[Term] extra`), with a\n * warning, so the clauses after it never merge into the frame before.\n * @param t - the trimmed line\n * @param line - its number\n * @returns false when the line is not a frame header\n */\n private frameHeader(t: string, line: number): boolean {\n const close = t.indexOf(\"]\");\n const name = (close < 0 ? t.slice(1) : t.slice(1, close)).trim();\n const after = close < 0 ? \"\" : t.slice(close + 1).trim();\n const clean = close >= 0 && (after.length === 0 || after.startsWith(\"!\"));\n if (!clean && !FRAME_KINDS.has(name) && t.includes(\":\")) {\n return false;\n }\n if (!clean) {\n const what =\n close < 0\n ? \"a frame header without its closing ] starts the frame\"\n : \"text after a frame header was ignored\";\n this.tally(\"parse-error\", OBO_ISSUE.SYNTAX, what, `[${name}]`, line);\n }\n // a known frame name, or a clean header with a name: anything else (`[`, `[{\"id\": 1}]`, a JSON\n // array) is read as a damaged header but is no proof the input is OBO\n const proof = FRAME_KINDS.has(name) || (clean && /^[A-Za-z]/.test(name) && isTagName(name));\n if (!proof) {\n this.firstBadLine ??= line;\n }\n this.startFrame(name, line, proof);\n return true;\n }\n\n /**\n * Start a frame, finishing the one before.\n * @param name - the frame type\n * @param line - the header's line\n * @param proof - whether the header shows the input is OBO\n */\n private startFrame(name: string, line: number, proof: boolean): void {\n this.finishFrame();\n this.frameSeen ||= proof;\n const kind = FRAME_KINDS.has(name) ? (name as FrameKind) : null;\n if (kind === null) {\n this.tally(\n \"validation-error\",\n OBO_ISSUE.UNKNOWN_ELEMENT,\n \"frames of an unknown type are not nodes; kept in meta.extra.obo.unknownFrames\",\n `[${name}]`,\n line,\n );\n }\n this.frame = { kind, name, line, clauses: [] };\n }\n\n /**\n * Record one header clause.\n * @param clause - the clause\n */\n private headerClause(clause: Clause): void {\n append(this.header, clause.tag, clause.value);\n const { tag } = clause;\n if (SINGLE_HEADER_TAGS.has(tag) && this.header[tag].length > 1) {\n this.tally(\n \"validation-error\",\n OBO_ISSUE.DUPLICATE_ATTRIBUTE,\n \"a single-valued header tag given twice; the first is kept\",\n tag,\n clause.line,\n );\n }\n const tokens = tokenize(splitQualifiers(clause.value).value);\n const first = tokens.length > 0 && tokens[0].kind === \"word\" ? tokens[0].text : null;\n if (tag === \"format-version\") {\n this.version ??= unescapeObo(clause.value).trim();\n } else if (tag === \"default-namespace\") {\n this.defaultNamespace ??= first;\n } else if ((tag === \"subsetdef\" || tag === \"synonymtypedef\") && first === null) {\n this.tally(\n \"parse-error\",\n OBO_ISSUE.SYNTAX,\n \"a declaration whose name is not a word declares nothing\",\n tag,\n clause.line,\n );\n } else if (tag === \"subsetdef\" && first !== null) {\n this.subsets.add(first);\n } else if (tag === \"synonymtypedef\" && first !== null) {\n const scope = tokens.slice(1).find((t) => t.kind === \"word\" && SYNONYM_SCOPES.has(t.text));\n this.synonymTypes.set(first, scope?.text ?? null);\n }\n const now = DEPRECATED_HEADER.get(tag);\n if (now !== undefined) {\n this.tally(\"coercion\", OBO_ISSUE.DEPRECATED_TAG, `the 1.0 header tag is read as ${now}`, tag, clause.line);\n }\n if (NOT_APPLIED_HEADER.test(tag)) {\n this.tally(\n \"unsupported\",\n OBO_ISSUE.HEADER_NOT_APPLIED,\n \"kept in meta.extra.obo.header, not applied\",\n tag,\n clause.line,\n );\n }\n }\n\n /** Finish the frame being read: find its id and merge its clauses into the record of that id. */\n finishFrame(): void {\n const { frame } = this;\n this.frame = null;\n if (frame === null) {\n return;\n }\n if (frame.kind === null) {\n // the guides: an unrecognized frame must survive, so its clauses are kept, raw\n const clauses = ownRecord<string[]>();\n for (const clause of frame.clauses) {\n append(clauses, clause.tag, clause.value);\n }\n this.unknownFrames.push({ type: frame.name, clauses });\n return;\n }\n if (++this.framesSinceCheck >= ABORT_CHECK_INTERVAL) {\n this.framesSinceCheck = 0;\n throwIfAborted(this.signal);\n }\n const idAt = frame.clauses.findIndex((c) => c.tag === \"id\");\n const idParts = idAt < 0 ? null : splitQualifiers(frame.clauses[idAt].value);\n const rawId = idParts === null ? \"\" : idParts.value.trim();\n const id = unescapeObo(rawId).trim();\n // a Typedef is metadata unless typedefs \"nodes\": it would never have been a node\n const wouldBeNode = frame.kind !== \"Typedef\" || this.typedefsAsNodes;\n if (id.length === 0) {\n this.report.error(\n \"missing-value\",\n OBO_ISSUE.MISSING_ID,\n `a [${frame.kind}] frame has no id; it is skipped`,\n {\n line: frame.line,\n },\n );\n if (wouldBeNode) {\n this.report.counts.skippedNodes++;\n }\n return;\n }\n if (tokenize(rawId).length > 1 || hasControl(id)) {\n // a reference cannot name such an id (is_a needs one word), so the frame is refused\n // rather than made a node no edge can reach\n this.report.error(\n \"validation-error\",\n OBO_ISSUE.BAD_VALUE,\n `a [${frame.kind}] frame's id ${JSON.stringify(id)} holds unescaped whitespace or a control character; the frame is skipped`,\n { line: frame.clauses[idAt].line, element: id },\n );\n if (wouldBeNode) {\n this.report.counts.skippedNodes++;\n }\n return;\n }\n if (idAt > 0) {\n this.tally(\n \"validation-error\",\n OBO_ISSUE.ID_NOT_FIRST,\n \"the id clause is not the frame's first; it is used\",\n \"id\",\n frame.clauses[idAt].line,\n );\n }\n const target = this.recordFor(frame.kind, id, frame.line);\n this.extraQualifiers(target, \"id\", id, idParts?.qualifiers ?? null);\n for (let i = 0; i < frame.clauses.length; i++) {\n const clause = frame.clauses[i];\n if (clause.tag === \"id\") {\n if (i !== idAt) {\n this.tally(\n \"validation-error\",\n OBO_ISSUE.DUPLICATE_ATTRIBUTE,\n \"a frame names a second id; the first is kept\",\n \"id\",\n clause.line,\n );\n }\n continue;\n }\n this.applyClause(target, clause);\n }\n if (target.kind === \"Typedef\" && !Object.hasOwn(target.raw, \"id\")) {\n target.raw.id = [id];\n }\n }\n\n /**\n * The record a frame merges into: the existing one of its id, or a new one.\n * @param kind - the frame type\n * @param id - the id\n * @param line - the frame's line\n * @returns the record\n */\n private recordFor(kind: FrameKind, id: string, line: number): NodeRecord {\n const map = kind === \"Typedef\" ? this.typedefs : this.nodes;\n const existing = map.get(id);\n if (existing !== undefined) {\n if (existing.kind !== kind) {\n this.tally(\n \"validation-error\",\n OBO_ISSUE.ID_KIND_CLASH,\n `an id names both a ${existing.kind} and an ${kind}; the ${existing.kind} is the node`,\n id,\n line,\n );\n } else {\n this.tally(\n \"merged\",\n OBO_ISSUE.DUPLICATE_NODE,\n `[${kind}] frames with this id are merged (spec 4.1.1)`,\n id,\n line,\n );\n }\n return existing;\n }\n const created: NodeRecord = {\n id,\n kind,\n line,\n values: new Map(),\n lists: new Map(),\n edges: [],\n seen: new Set(),\n raw: ownRecord<string[]>(),\n };\n map.set(id, created);\n return created;\n }\n\n /**\n * A clause's tag (a 1.0 tag read as its current one), the synonym scope that tag implies, its\n * qualifier block and its value, with the syntax warnings about stray braces recorded.\n * @param clause - the clause\n * @returns the parts\n */\n private clauseParts(clause: Clause): {\n tag: string;\n scope: string | null;\n qualifiers: ReturnType<typeof splitQualifiers>[\"qualifiers\"];\n value: string;\n } {\n let { tag } = clause;\n let scope: string | null = null;\n const deprecated = DEPRECATED_TAGS.get(tag);\n if (deprecated !== undefined) {\n this.tally(\n \"coercion\",\n OBO_ISSUE.DEPRECATED_TAG,\n `the 1.0 tag is read as ${deprecated[0]}`,\n tag,\n clause.line,\n );\n [tag, scope] = deprecated;\n }\n let split = splitQualifiers(clause.value);\n const open = ID_VALUE_TAGS.has(tag) ? unclosedBlock(split.value) : -1;\n if (open >= 0) {\n this.tally(\n \"parse-error\",\n OBO_ISSUE.SYNTAX,\n \"a qualifier block without its closing brace was dropped\",\n tag,\n clause.line,\n );\n split = splitQualifiers(split.value.slice(0, open).trimEnd());\n }\n const { qualifiers } = split;\n if (split.badBlock !== null) {\n this.tally(\n \"parse-error\",\n OBO_ISSUE.SYNTAX,\n \"a closing brace that is not a qualifier block was kept as text\",\n tag,\n clause.line,\n );\n } else if (hasStrayBrace(split.value)) {\n this.tally(\n \"parse-error\",\n OBO_ISSUE.SYNTAX,\n \"an unescaped brace inside a value was kept as text\",\n tag,\n clause.line,\n );\n }\n return { tag, scope, qualifiers, value: split.value };\n }\n\n /**\n * A def, expand_assertion_to or expand_expression_to clause: quoted text and its xref list.\n * @param record - the record\n * @param tag - the tag\n * @param value - the clause value\n * @param tokens - its tokens\n * @param qualifiers - its qualifier block\n * @param line - its line\n */\n private definition(\n record: NodeRecord,\n tag: string,\n value: string,\n tokens: ReturnType<typeof tokenize>,\n qualifiers: ReturnType<typeof splitQualifiers>[\"qualifiers\"],\n line: number,\n ): void {\n if (tag === \"def\" && record.values.has(\"def\")) {\n // the second def of an id: reported, and none of its xrefs leak into the first's\n this.single(record, \"def\", null, line);\n return;\n }\n const text = this.quotedWithXrefs(record, tag, value, tokens, line);\n if (tag === \"def\") {\n this.single(record, \"def\", text.text, line, () => {\n record.values.set(\"def.xrefs\", text.xrefs);\n });\n this.extraQualifiers(record, tag, text.text, qualifiers);\n } else {\n this.push(record, tag, withQualifiers({ template: text.text, xrefs: text.xrefs }, qualifiers));\n }\n }\n\n /**\n * Apply one clause to a record.\n * @param record - the record\n * @param clause - the clause\n */\n private applyClause(record: NodeRecord, clause: Clause): void {\n const key = `${clause.tag}\\u0000${clause.value}`;\n if (record.seen.has(key)) {\n return;\n }\n record.seen.add(key);\n if (record.kind === \"Typedef\") {\n append(record.raw, clause.tag, clause.value);\n }\n const { tag, scope, qualifiers, value } = this.clauseParts(clause);\n // a control character kept in the value is the shared W_CONTROL_CHARACTER of the text check\n const where = { line: clause.line, element: record.id };\n if (TYPEDEF_TAGS.has(tag) && record.kind !== \"Typedef\") {\n this.unrecognized(record, clause);\n return;\n }\n if (TEXT_TAGS.has(tag)) {\n this.text(record, tag, value, qualifiers, clause.line);\n return;\n }\n if (BOOL_TAGS.has(tag)) {\n const text = unescapeObo(value).trim();\n if (text !== \"true\" && text !== \"false\") {\n this.report.error(\n \"validation-error\",\n OBO_ISSUE.BAD_VALUE,\n `${tag}: ${JSON.stringify(text)} is not true or false; the clause is skipped`,\n where,\n );\n return;\n }\n this.single(record, tag, text === \"true\", clause.line);\n this.extraQualifiers(record, tag, text, qualifiers);\n return;\n }\n const tokens = tokenize(value);\n if (ID_LIST_TAGS.has(tag)) {\n const id = this.oneWord(tokens, tag, where);\n if (id !== null) {\n this.push(record, tag, id);\n this.extraQualifiers(record, tag, id, qualifiers);\n if (tag === \"subset\" && !this.subsets.has(id)) {\n this.tally(\n \"validation-error\",\n OBO_ISSUE.UNDECLARED,\n \"a subset no subsetdef declares\",\n id,\n clause.line,\n );\n }\n }\n return;\n }\n switch (tag) {\n case \"is_a\":\n case \"instance_of\": {\n if (tag === \"instance_of\" && record.kind !== \"Instance\") {\n this.unrecognized(record, clause);\n return;\n }\n const target = this.oneWord(tokens, tag, where);\n if (target !== null) {\n record.edges.push({ relation: tag, target, qualifiers, line: clause.line });\n }\n return;\n }\n case \"relationship\": {\n if (tokens.length !== 2 || tokens.some((t) => t.kind !== \"word\")) {\n this.report.error(\n \"validation-error\",\n OBO_ISSUE.BAD_VALUE,\n `relationship needs a relation and a target, found ${JSON.stringify(unescapeObo(value))}; the clause is skipped`,\n where,\n );\n return;\n }\n record.edges.push({ relation: tokens[0].text, target: tokens[1].text, qualifiers, line: clause.line });\n return;\n }\n case \"intersection_of\": {\n if (tokens.length < 1 || tokens.length > 2 || tokens.some((t) => t.kind !== \"word\")) {\n this.report.error(\n \"validation-error\",\n OBO_ISSUE.BAD_VALUE,\n `intersection_of needs a class, or a relation and a class, found ${JSON.stringify(unescapeObo(value))}; the clause is skipped`,\n where,\n );\n return;\n }\n const item: Record<string, unknown> =\n tokens.length === 1\n ? { relation: null, target: tokens[0].text }\n : { relation: tokens[0].text, target: tokens[1].text };\n this.push(record, tag, withQualifiers(item, qualifiers));\n return;\n }\n case \"holds_over_chain\":\n case \"equivalent_to_chain\": {\n if (tokens.length !== 2 || tokens.some((t) => t.kind !== \"word\")) {\n this.report.error(\n \"validation-error\",\n OBO_ISSUE.BAD_VALUE,\n `${tag} needs two relations; the clause is skipped`,\n where,\n );\n return;\n }\n this.push(record, tag, [tokens[0].text, tokens[1].text]);\n this.extraQualifiers(record, tag, `${tokens[0].text} ${tokens[1].text}`, qualifiers);\n return;\n }\n case \"def\":\n case \"expand_assertion_to\":\n case \"expand_expression_to\":\n this.definition(record, tag, value, tokens, qualifiers, clause.line);\n return;\n case \"synonym\":\n this.synonym(record, tokens, scope, qualifiers, clause.line);\n return;\n case \"xref\": {\n const xref = parseXref(value);\n if (xref === null) {\n this.report.error(\n \"validation-error\",\n OBO_ISSUE.BAD_VALUE,\n \"xref has no id; the clause is skipped\",\n where,\n );\n return;\n }\n this.push(record, \"xref\", xref.id);\n this.describe(record, [xref], tag, clause.line);\n this.extraQualifiers(record, tag, xref.id, qualifiers ?? xref.qualifiers);\n return;\n }\n case \"property_value\":\n this.propertyValue(record, tokens, qualifiers, where);\n return;\n default:\n this.unrecognized(record, clause);\n }\n }\n\n /**\n * A single-valued text clause (name, comment, ...), warning about a quote that never closes\n * (stripComment() then keeps a `!` comment after it as text).\n * @param record - the record\n * @param tag - the tag\n * @param value - the raw value\n * @param qualifiers - its qualifier block\n * @param line - its line\n */\n private text(record: NodeRecord, tag: string, value: string, qualifiers: Qualifiers | null, line: number): void {\n if (tokenize(value).some((t) => t.kind === \"quoted\" && t.unterminated)) {\n this.tally(\n \"parse-error\",\n OBO_ISSUE.SYNTAX,\n \"an unterminated quote; the text after it, a comment included, is kept\",\n tag,\n line,\n );\n }\n const text = unescapeObo(value).trim();\n this.single(record, tag, text, line);\n this.extraQualifiers(record, tag, text, qualifiers);\n }\n\n /**\n * Read a value that must be one word.\n * @param tokens - the value's tokens\n * @param tag - the tag, for the message\n * @param where - the location\n * @returns the word, or null after reporting E_BAD_VALUE\n */\n private oneWord(tokens: readonly Token[], tag: string, where: Where): string | null {\n if (tokens.length === 1 && tokens[0].kind === \"word\") {\n return tokens[0].text;\n }\n const found = tokens.map((t) => t.text).join(\" \");\n this.report.error(\n \"validation-error\",\n OBO_ISSUE.BAD_VALUE,\n `${tag} needs one id, found ${JSON.stringify(found)}; the clause is skipped`,\n where,\n );\n return null;\n }\n\n /**\n * Read `\"text\" [xrefs]` (def, expand_*), reporting the forms the grammar does not allow.\n * @param record - the record (xref descriptions go to its `xref.descriptions`)\n * @param tag - the tag\n * @param value - the raw value\n * @param tokens - its tokens\n * @param line - the line\n * @returns the text and the xref ids\n */\n private quotedWithXrefs(\n record: NodeRecord,\n tag: string,\n value: string,\n tokens: readonly Token[],\n line: number,\n ): { text: string; xrefs: string[] } {\n if (tokens.length === 0 || tokens[0].kind !== \"quoted\") {\n this.tally(\"parse-error\", OBO_ISSUE.SYNTAX, \"the text is not quoted; the whole value is kept\", tag, line);\n return { text: unescapeObo(value).trim(), xrefs: [] };\n }\n if (tokens[0].unterminated) {\n this.tally(\n \"parse-error\",\n OBO_ISSUE.SYNTAX,\n \"an unterminated quote; the text runs to the end of the line\",\n tag,\n line,\n );\n return { text: tokens[0].text, xrefs: [] };\n }\n const list = tokens[1];\n if (list?.kind !== \"list\") {\n this.tally(\"parse-error\", OBO_ISSUE.SYNTAX, \"the xref list is missing\", tag, line);\n return { text: tokens[0].text, xrefs: [] };\n }\n if (list.unterminated) {\n this.tally(\"parse-error\", OBO_ISSUE.SYNTAX, \"an xref list without its closing ]; kept as read\", tag, line);\n }\n if (tokens.length > 2) {\n this.tally(\"parse-error\", OBO_ISSUE.SYNTAX, \"text after the xref list was ignored\", tag, line);\n }\n const xrefs = parseXrefList(list.text);\n this.describe(record, xrefs, tag, line);\n this.xrefQualifiers(record, tag, xrefs);\n return { text: tokens[0].text, xrefs: xrefs.map((x) => x.id) };\n }\n\n /**\n * Read a synonym: `\"text\" SCOPE? TYPE? [xrefs]` (the scope optional in 1.2).\n * @param record - the record\n * @param tokens - the value's tokens\n * @param fixedScope - the scope of a 1.0 tag (exact_synonym), or null\n * @param qualifiers - the clause's qualifiers\n * @param line - the line\n */\n private synonym(\n record: NodeRecord,\n tokens: readonly Token[],\n fixedScope: string | null,\n qualifiers: Qualifiers | null,\n line: number,\n ): void {\n if (tokens.length === 0 || tokens[0].kind !== \"quoted\") {\n this.report.error(\n \"validation-error\",\n OBO_ISSUE.BAD_VALUE,\n \"a synonym needs its quoted text; the clause is skipped\",\n {\n line,\n element: record.id,\n },\n );\n return;\n }\n if (tokens[0].unterminated) {\n this.tally(\n \"parse-error\",\n OBO_ISSUE.SYNTAX,\n \"an unterminated quote; the text runs to the end of the line\",\n \"synonym\",\n line,\n );\n }\n const words = tokens\n .slice(1)\n .filter((t) => t.kind === \"word\")\n .map((t) => t.text);\n const list = tokens.slice(1).find((t) => t.kind === \"list\");\n let scope: string | null = fixedScope;\n let type: string | null = null;\n if (fixedScope === null) {\n if (words.length > 0 && SYNONYM_SCOPES.has(words[0])) {\n [scope] = words;\n type = words[1] ?? null;\n } else if (words.length > 0 && this.synonymTypes.has(words[0])) {\n [type] = words;\n scope = \"RELATED\";\n } else if (words.length > 0) {\n [type] = words;\n this.tally(\n \"validation-error\",\n OBO_ISSUE.SYNONYM_SCOPE,\n `a scope that is not EXACT, BROAD, NARROW or RELATED was kept as the type, scope null`,\n words[0],\n line,\n );\n } else {\n scope = \"RELATED\";\n }\n if (scope === \"RELATED\" && (words.length === 0 || words[0] === type) && !this.allowsMissingScope()) {\n this.tally(\n \"validation-error\",\n OBO_ISSUE.SYNONYM_SCOPE,\n \"a synonym without a scope (1.2 only) is read as RELATED\",\n \"synonym\",\n line,\n );\n }\n }\n if (type !== null) {\n const declared = this.synonymTypes.get(type);\n if (declared === undefined) {\n if (scope !== null) {\n this.tally(\n \"validation-error\",\n OBO_ISSUE.UNDECLARED,\n \"a synonym type no synonymtypedef declares\",\n type,\n line,\n );\n }\n } else if (declared !== null) {\n // the 1.2 guide: a type's default scope is used regardless of the synonym's own\n scope = declared;\n }\n }\n if (words.length > 2 || list === undefined) {\n this.tally(\n \"parse-error\",\n OBO_ISSUE.SYNTAX,\n list === undefined ? \"a synonym without its xref list\" : \"extra words after the synonym type\",\n \"synonym\",\n line,\n );\n }\n const listAt = list === undefined ? -1 : tokens.indexOf(list);\n const stray = tokens.some(\n (t, k) =>\n k > 0 && (t.kind === \"quoted\" || (t.kind === \"list\" && k !== listAt) || (listAt >= 0 && k > listAt)),\n );\n if (stray) {\n this.tally(\n \"parse-error\",\n OBO_ISSUE.SYNTAX,\n \"a second quoted string, a second xref list or text after the list was ignored\",\n \"synonym\",\n line,\n );\n }\n if (list?.unterminated === true) {\n this.tally(\n \"parse-error\",\n OBO_ISSUE.SYNTAX,\n \"an xref list without its closing ]; kept as read\",\n \"synonym\",\n line,\n );\n }\n const xrefs = list === undefined ? [] : parseXrefList(list.text);\n this.describe(record, xrefs, \"synonym\", line);\n this.xrefQualifiers(record, \"synonym\", xrefs);\n this.push(\n record,\n \"synonym\",\n withQualifiers({ text: tokens[0].text, scope, type, xrefs: xrefs.map((x) => x.id) }, qualifiers),\n );\n }\n\n /**\n * Whether the file's version lets a synonym omit its scope (1.0 and 1.2).\n * @returns true for a 1.2 or 1.0 file\n */\n private allowsMissingScope(): boolean {\n return this.version !== null && /^(1\\.[0-2]|GO_1\\.[0-2])\\b/.test(this.version);\n }\n\n /**\n * Read a property_value: `relation \"literal\" datatype` or `relation id`.\n * @param record - the record\n * @param tokens - the value's tokens\n * @param qualifiers - the clause's qualifiers\n * @param where - the location\n */\n private propertyValue(\n record: NodeRecord,\n tokens: readonly Token[],\n qualifiers: Qualifiers | null,\n where: Where,\n ): void {\n if (tokens.length < 2 || tokens.length > 3 || tokens[0].kind !== \"word\" || tokens[1].kind === \"list\") {\n this.report.error(\n \"validation-error\",\n OBO_ISSUE.BAD_VALUE,\n \"property_value needs a relation and a value; the clause is skipped\",\n where,\n );\n return;\n }\n if (tokens.some((t) => t.unterminated)) {\n this.tally(\n \"parse-error\",\n OBO_ISSUE.SYNTAX,\n \"an unterminated quote; the text runs to the end of the line\",\n \"property_value\",\n where.line,\n );\n }\n let datatype = tokens.length === 3 ? tokens[2].text : null;\n if (tokens.length === 3 && tokens[2].kind !== \"word\") {\n this.tally(\n \"parse-error\",\n OBO_ISSUE.SYNTAX,\n \"a datatype that is not a word was ignored\",\n \"property_value\",\n where.line,\n );\n datatype = null;\n }\n this.push(\n record,\n \"property_value\",\n withQualifiers({ relation: tokens[0].text, value: tokens[1].text, datatype }, qualifiers),\n );\n }\n\n /**\n * Set a single-valued column, keeping the first value of an id.\n * @param record - the record\n * @param column - the column\n * @param value - the value\n * @param line - the line\n * @param also - more to set together with the value\n */\n private single(record: NodeRecord, column: string, value: unknown, line: number, also?: () => void): void {\n if (record.values.has(column)) {\n this.tally(\n \"validation-error\",\n OBO_ISSUE.DUPLICATE_ATTRIBUTE,\n \"a single-valued tag given twice for one id; the first is kept\",\n column,\n line,\n );\n return;\n }\n record.values.set(column, value);\n also?.();\n }\n\n /**\n * Append to a list column, without repeats (merged frames take the union).\n * @param record - the record\n * @param column - the column\n * @param value - the item\n */\n private push(record: NodeRecord, column: string, value: unknown): void {\n let list = record.lists.get(column);\n if (list === undefined) {\n list = [];\n record.lists.set(column, list);\n }\n // objects are never repeated: identical clauses were already skipped\n if (typeof value === \"object\" || !list.includes(value)) {\n list.push(value);\n }\n }\n\n /**\n * Record xref descriptions in `xref.descriptions` (the first description of an id is kept),\n * warning about a description whose quote never closes.\n * @param target - the record\n * @param xrefs - the xrefs\n * @param tag - the clause's tag\n * @param line - the clause's line\n */\n private describe(target: NodeRecord, xrefs: readonly Xref[], tag: string, line: number): void {\n for (const xref of xrefs) {\n if (xref.unterminated) {\n this.tally(\n \"parse-error\",\n OBO_ISSUE.SYNTAX,\n \"an xref description whose quote never closes runs to the end\",\n tag,\n line,\n );\n }\n if (xref.description !== null) {\n let map = target.values.get(\"xref.descriptions\") as Record<string, string> | undefined;\n if (map === undefined) {\n map = ownRecord<string>();\n target.values.set(\"xref.descriptions\", map);\n }\n if (!Object.hasOwn(map, xref.id)) {\n map[xref.id] = xref.description;\n }\n }\n }\n }\n\n /**\n * Keep the per-xref qualifiers of an xref list (OBO 1.2: `[A:1 {source=\"x\"}]`) in\n * `obo.qualifiers` under `<tag>.xrefs`.\n * @param record - the record\n * @param tag - the clause's tag\n * @param xrefs - the list's xrefs\n */\n private xrefQualifiers(record: NodeRecord, tag: string, xrefs: readonly Xref[]): void {\n for (const xref of xrefs) {\n this.extraQualifiers(record, `${tag}.xrefs`, xref.id, xref.qualifiers);\n }\n }\n\n /**\n * Keep the qualifiers of a clause whose column has no place for them in `obo.qualifiers`.\n * @param record - the record\n * @param tag - the tag\n * @param value - the clause's value as stored\n * @param qualifiers - the qualifiers, or null\n */\n private extraQualifiers(record: NodeRecord, tag: string, value: string, qualifiers: Qualifiers | null): void {\n if (qualifiers === null) {\n return;\n }\n const map = (record.values.get(\"obo.qualifiers\") as Record<string, unknown[]> | undefined) ?? {};\n (map[tag] ??= []).push({ value, qualifiers });\n record.values.set(\"obo.qualifiers\", map);\n }\n\n /**\n * Keep an unknown clause in `obo.unrecognized`.\n * @param record - the record\n * @param clause - the clause\n */\n private unrecognized(record: NodeRecord, clause: Clause): void {\n let map = record.values.get(\"obo.unrecognized\") as Record<string, string[]> | undefined;\n if (map === undefined) {\n map = ownRecord<string[]>();\n record.values.set(\"obo.unrecognized\", map);\n }\n append(map, clause.tag, unescapeObo(clause.value));\n this.tally(\n \"validation-error\",\n OBO_ISSUE.UNKNOWN_ELEMENT,\n \"an unknown tag was kept in obo.unrecognized\",\n clause.tag,\n clause.line,\n );\n }\n\n /**\n * Count a warning, recorded once per code and element at the end.\n * @param category - the category\n * @param code - the code\n * @param what - what happened\n * @param element - the tag, id or name it is about\n * @param line - the first line\n */\n tally(category: Tally[\"category\"], code: string, what: string, element: string, line: number): void {\n const key = `${code}\\u0000${element}\\u0000${what}`;\n const found = this.tallies.get(key);\n if (found === undefined) {\n this.tallies.set(key, { category, code, element, what, line, count: 1 });\n } else {\n found.count++;\n }\n }\n\n /**\n * Record the counted warnings, in the order they were first seen; past MAX_TALLIES_PER_CODE\n * of one code, the rest are summed up in one warning.\n */\n flushTallies(): void {\n const listed = new Map<string, number>();\n const over = new Map<string, Tally[]>();\n for (const t of this.tallies.values()) {\n const n = (listed.get(t.code) ?? 0) + 1;\n listed.set(t.code, n);\n if (n > MAX_TALLIES_PER_CODE) {\n const rest = over.get(t.code) ?? [];\n rest.push(t);\n over.set(t.code, rest);\n continue;\n }\n this.report.warning(\n t.category,\n t.code,\n `${t.element}: ${t.what} (${t.count} time${plural(t.count)}, first at line ${t.line})`,\n {\n line: t.line,\n element: t.element,\n },\n );\n }\n for (const [code, rest] of over) {\n this.report.warning(\n rest[0].category,\n code,\n `${rest.length} more element${plural(rest.length)} with this warning, not listed (first: ${rest[0].element}: ${rest[0].what}, line ${rest[0].line})`,\n { line: rest[0].line },\n );\n }\n this.tallies.clear();\n }\n\n /**\n * The first line that makes the input not OBO: null unless no frame header and no plausible\n * header tag was read while some line was neither (an HTML page, a JSON, GML, DOT or CSV file,\n * UTF-16 read without its BOM). A file of only comments is OBO, if an empty one.\n * @returns the line, or null\n */\n notObo(): number | null {\n return this.frameSeen || this.tagClauses > 0 ? null : this.firstBadLine;\n }\n\n /**\n * Warn about the header once the file is read: a missing or unknown format-version (the\n * synonym-scope rule depends on it), a date that is not a real calendar date.\n */\n checkHeader(): void {\n if (this.version === null) {\n const empty = this.frameSeen ? \"\" : \" and the file has no frames: nothing was read\";\n this.tally(\n \"validation-error\",\n OBO_ISSUE.FORMAT_VERSION,\n `the header has no format-version (required by 1.2 and 1.4)${empty}; read as the 1.0 / 1.2 / 1.4 union`,\n \"format-version\",\n 1,\n );\n } else if (!KNOWN_VERSION.test(this.version)) {\n this.tally(\n \"validation-error\",\n OBO_ISSUE.FORMAT_VERSION,\n `format-version ${JSON.stringify(this.version)} is not 1.0, 1.2 or 1.4; read as 1.4`,\n \"format-version\",\n 1,\n );\n }\n const date = this.header.date?.[0];\n if (\n date !== undefined &&\n /^\\d{2}:\\d{2}:\\d{4}\\s+\\d{2}:\\d{2}$/.test(date.trim()) &&\n oboDate(date.trim()) === null\n ) {\n this.tally(\n \"validation-error\",\n OBO_ISSUE.SYNTAX,\n \"the header date is not a real calendar date; created is null\",\n \"date\",\n 1,\n );\n }\n }\n\n /**\n * The header as GraphMeta fields (design 4.2): name from `ontology`, the version, `created` from\n * the `dd:MM:yyyy HH:mm` date, `creator` from `saved-by`.\n * @returns the metadata patch, without `extra`\n */\n meta(): GraphMetaPatch {\n const first = (tag: string): string | null => {\n const values = this.header[tag];\n return values === undefined ? null : unescapeObo(values[0]).trim();\n };\n return {\n name: first(\"ontology\"),\n sourceFormat: \"obo\",\n sourceVersion: this.version,\n created: oboDate(first(\"date\")),\n creator: first(\"saved-by\"),\n };\n }\n\n /**\n * The raw header clauses.\n * @returns the header by tag\n */\n headerRecord(): Record<string, string[]> {\n return this.header;\n }\n\n /**\n * The namespace a frame without one gets.\n * @returns the default namespace, or null\n */\n namespaceDefault(): string | null {\n return this.defaultNamespace;\n }\n}\n\n/**\n * Add the qualifiers to a json item when there are any.\n * @param item - the item\n * @param qualifiers - the qualifiers, or null\n * @returns the item\n */\nfunction withQualifiers(item: Record<string, unknown>, qualifiers: Qualifiers | null): Record<string, unknown> {\n return qualifiers === null ? item : { ...item, qualifiers };\n}\n\n/**\n * The OBO header date `dd:MM:yyyy HH:mm` as ISO 8601 (`yyyy-MM-ddTHH:mm`).\n * @param text - the header value, or null\n * @returns the ISO text, or null when the date is not of that form\n */\nfunction oboDate(text: string | null): string | null {\n const m = text === null ? null : /^(\\d{2}):(\\d{2}):(\\d{4})\\s+(\\d{2}):(\\d{2})$/.exec(text);\n if (m === null) {\n return null;\n }\n const [, dd, mm, yyyy, hh, min] = m;\n // a real calendar date: 31:02 and 31:04 do not survive the round trip through Date\n const day = new Date(Date.UTC(Number(yyyy), Number(mm) - 1, Number(dd)));\n if (Number(mm) < 1 || Number(mm) > 12 || day.getUTCDate() !== Number(dd) || Number(hh) > 23 || Number(min) > 59) {\n return null;\n }\n return `${yyyy}-${mm}-${dd}T${hh}:${min}`;\n}\n\n/** What writeGraph() pushes, decided before anything reaches the sink. */\ninterface GraphPlan {\n /** The node records, in first-appearance order. */\n readonly nodes: readonly NodeRecord[];\n /** The undeclared targets that become placeholder nodes. */\n readonly placeholders: readonly string[];\n /** The edges to push. */\n readonly edges: readonly { readonly source: string; readonly edge: PendingEdge }[];\n}\n\n/**\n * Decide what is written (design 4.2): the node records (Typedefs too under typedefs \"nodes\", the\n * obsolete ones left out under obsolete \"drop\"), the placeholders of undeclared targets and the\n * edges; record the warnings that need the whole file (obsoletion rules, undeclared relations,\n * dangling targets, dropped obsolete terms).\n * @param reader - the finished reader\n * @param report - the report\n * @param addMissingNodes - whether an undeclared target becomes a placeholder node\n * @param obo - the OBO options\n * @returns the plan\n */\nfunction planGraph(\n reader: OboReader,\n report: ImportReportBuilder,\n addMissingNodes: boolean,\n obo: ResolvedOboOptions,\n): GraphPlan {\n const records: NodeRecord[] = [...reader.nodes.values()];\n for (const [id, typedef] of reader.typedefs) {\n const node = reader.nodes.get(id);\n if (node !== undefined) {\n reader.tally(\n \"validation-error\",\n OBO_ISSUE.ID_KIND_CLASH,\n `an id names both a ${node.kind} and a Typedef; the ${node.kind} is the node`,\n id,\n typedef.line,\n );\n } else if (obo.typedefs === \"nodes\") {\n records.push(typedef);\n }\n }\n // a class expression needs two or more operands, counted after merging (spec 4.1.1)\n for (const record of [...reader.nodes.values(), ...reader.typedefs.values()]) {\n for (const tag of [\"intersection_of\", \"union_of\"]) {\n if (record.lists.get(tag)?.length === 1) {\n reader.tally(\n \"validation-error\",\n OBO_ISSUE.CARDINALITY,\n \"a single clause (a class expression needs two or more)\",\n tag,\n record.line,\n );\n }\n }\n }\n const dropped = new Set<string>();\n const kept = new Set<string>();\n for (const record of records) {\n const obsolete = record.values.get(\"is_obsolete\") === true;\n (obo.obsolete === \"drop\" && obsolete ? dropped : kept).add(record.id);\n // obsoletion rules (the 1.2 guide; fastobo-validator --obsoletion)\n if (obsolete && record.edges.length > 0) {\n reader.tally(\n \"validation-error\",\n OBO_ISSUE.OBSOLETION,\n \"an obsolete term has is_a or relationship clauses; they are kept\",\n \"is_obsolete\",\n record.edges[0].line,\n );\n }\n if (!obsolete && (record.lists.has(\"replaced_by\") || record.lists.has(\"consider\"))) {\n reader.tally(\n \"validation-error\",\n OBO_ISSUE.OBSOLETION,\n \"replaced_by or consider on a term that is not obsolete; kept\",\n \"replaced_by\",\n record.line,\n );\n }\n }\n const declared = new Set<string>(reader.typedefs.keys());\n for (const typedef of reader.typedefs.values()) {\n for (const xref of (typedef.lists.get(\"xref\") ?? []) as string[]) {\n declared.add(xref);\n }\n }\n const dangling: string[] = [];\n const danglingSet = new Set<string>();\n let danglingEdges = 0;\n let droppedEdges = 0;\n const edges: { source: string; edge: PendingEdge }[] = [];\n for (const record of records) {\n for (const edge of record.edges) {\n if (dropped.has(record.id) || dropped.has(edge.target)) {\n droppedEdges++;\n continue;\n }\n if (!BUILTIN_RELATIONS.has(edge.relation) && !declared.has(edge.relation)) {\n reader.tally(\n \"validation-error\",\n OBO_ISSUE.UNDECLARED,\n \"a relation no Typedef declares\",\n edge.relation,\n edge.line,\n );\n }\n if (!kept.has(edge.target)) {\n if (!danglingSet.has(edge.target)) {\n danglingSet.add(edge.target);\n dangling.push(edge.target);\n }\n if (!addMissingNodes) {\n danglingEdges++;\n report.counts.skippedEdges++;\n continue;\n }\n }\n edges.push({ source: record.id, edge });\n }\n }\n reader.flushTallies();\n reportDangling(records, dangling, addMissingNodes, danglingEdges, report, new Set(reader.typedefs.keys()));\n if (dropped.size > 0) {\n report.warning(\n \"merged\",\n OBO_ISSUE.OBSOLETE_DROPPED,\n `${dropped.size} obsolete term${plural(dropped.size)} and ${droppedEdges} edge${plural(droppedEdges)} to or from them were left out (obsolete: \"drop\")`,\n { element: [...dropped][0] },\n );\n }\n return {\n nodes: records.filter((record) => kept.has(record.id)),\n placeholders: addMissingNodes ? dangling : [],\n edges,\n };\n}\n\n/**\n * Record the one W_DANGLING_REFERENCE of an import: the count, the first targets, and for a target\n * that is another term's alt_id, the term it is an alt_id of.\n * @param records - every node record\n * @param dangling - the undeclared targets, in first-reference order\n * @param addMissingNodes - whether they became placeholder nodes\n * @param droppedEdges - the edges dropped under addMissingNodes false\n * @param report - the report\n * @param typedefs - the ids of the Typedef frames (kept as metadata, so not nodes)\n */\nfunction reportDangling(\n records: readonly NodeRecord[],\n dangling: readonly string[],\n addMissingNodes: boolean,\n droppedEdges: number,\n report: ImportReportBuilder,\n typedefs: ReadonlySet<string>,\n): void {\n if (dangling.length === 0) {\n return;\n }\n const altOf = new Map<string, string>();\n for (const record of records) {\n for (const alt of (record.lists.get(\"alt_id\") ?? []) as string[]) {\n altOf.set(alt, record.id);\n }\n }\n const shown = dangling.slice(0, 5).map((id) => {\n const primary = altOf.get(id);\n if (typedefs.has(id)) {\n return `${id} (a Typedef, kept as metadata, not a node)`;\n }\n return primary === undefined ? id : `${id} (an alt_id of ${primary})`;\n });\n const more = dangling.length > 5 ? `, ... (${dangling.length - 5} more)` : \"\";\n const action = addMissingNodes\n ? \"each became a placeholder node (graphty.placeholder)\"\n : `${droppedEdges} edge${plural(droppedEdges)} to them ${agree(droppedEdges, \"was\", \"were\")} dropped (addMissingNodes false)`;\n report.warning(\n \"validation-error\",\n OBO_ISSUE.DANGLING_REFERENCE,\n `${dangling.length} target${plural(dangling.length)} no frame declares: ${shown.join(\", \")}${more}; ${action}`,\n { element: dangling[0] },\n );\n}\n\n/** Pushes ids into a sink: the id coercion rule and the cancellation check. */\nclass Pusher {\n readonly sink: GraphSink;\n\n readonly report: ImportReportBuilder;\n\n private readonly coercer: IdCoercer;\n\n private readonly signal: AbortSignal | null;\n\n /** The original ids restored under restoreMangledIds, by the id the file wrote. */\n readonly restored = new Map<string, string>();\n\n private since = 0;\n\n /**\n * Create a pusher.\n * @param sink - the sink\n * @param report - the report\n * @param options - the resolved common options\n */\n constructor(sink: GraphSink, report: ImportReportBuilder, options: ReturnType<typeof resolveImportOptions>) {\n this.sink = sink;\n this.report = report;\n this.coercer = new IdCoercer(options.ids);\n this.signal = options.signal;\n }\n\n /**\n * An id text under the `ids` rule, reporting a merge.\n * @param text - the id as written\n * @returns the node id\n */\n id(text: string): NodeId {\n const id = this.coercer.text(this.restored.get(text) ?? text);\n const merge = this.coercer.lastMerge;\n if (merge !== null) {\n this.report.warning(\n \"coercion\",\n OBO_ISSUE.ID_MERGED,\n `id text ${JSON.stringify(merge.text)} merged with ${JSON.stringify(merge.previousText)} as ${merge.id}`,\n { element: text },\n );\n }\n return id;\n }\n\n /**\n * Add a node, counting it, or record why it was refused.\n * @param text - the id as written\n * @param line - the line, when known\n * @returns the node index, or -1 when refused\n */\n node(text: string, line?: number): number {\n this.tick();\n try {\n const id = this.id(text);\n const known = this.sink.indexOf(id) !== INVALID_INDEX;\n const index = this.sink.addNode(id);\n if (!known) {\n this.report.counts.nodes++;\n }\n return index;\n } catch (err) {\n this.report.recordError(err, { line, element: text });\n this.report.counts.skippedNodes++;\n return -1;\n }\n }\n\n /** Check the cancellation signal every ABORT_CHECK_INTERVAL pushes. */\n tick(): void {\n if (++this.since >= ABORT_CHECK_INTERVAL) {\n this.since = 0;\n throwIfAborted(this.signal);\n }\n }\n}\n\n/**\n * Write the records into the sink (design 4.2): the nodes with the vocabulary columns they use,\n * the placeholders of undeclared targets, then the edges.\n * @param reader - the finished reader\n * @param sink - the sink\n * @param report - the report\n * @param options - the resolved options\n * @param obo - the OBO options\n */\nfunction writeGraph(\n reader: OboReader,\n sink: GraphSink,\n report: ImportReportBuilder,\n options: ReturnType<typeof resolveImportOptions>,\n obo: ResolvedOboOptions,\n): void {\n const plan = planGraph(reader, report, options.addMissingNodes, obo);\n const push = new Pusher(sink, report, options);\n if (options.restoreMangledIds) {\n restoreIds(plan.nodes, push.restored);\n }\n const namespace = reader.namespaceDefault();\n // columns, declared only when used, in the vocabulary's order\n const used = new Set<string>([\"type\"]);\n for (const record of plan.nodes) {\n for (const name of [...record.values.keys(), ...record.lists.keys()]) {\n used.add(name);\n }\n }\n if (namespace !== null) {\n used.add(\"namespace\");\n }\n const columns = new Map<string, ColumnHandle>();\n for (const name of plan.nodes.length > 0 ? Object.keys(OBO_NODE_COLUMNS) : []) {\n if (used.has(name)) {\n columns.set(name, declareResolved(sink, \"node\", oboColumnDecl(\"node\", name), report).handle);\n }\n }\n sink.reserve(plan.nodes.length + plan.placeholders.length, plan.edges.length);\n for (const record of plan.nodes) {\n const index = push.node(record.id, record.line);\n if (index < 0) {\n continue;\n }\n const cells: [string, unknown][] = [[\"type\", record.kind], ...record.values, ...record.lists];\n if (namespace !== null && !record.values.has(\"namespace\")) {\n cells.push([\"namespace\", namespace]);\n }\n for (const [name, value] of cells) {\n const handle = columns.get(name);\n if (handle !== undefined) {\n sink.setNodeValue(handle, index, value);\n }\n }\n }\n if (plan.placeholders.length > 0) {\n const placeholder = declareResolved(sink, \"node\", oboColumnDecl(\"node\", PLACEHOLDER_COLUMN), report).handle;\n for (const text of plan.placeholders) {\n const index = push.node(text);\n if (index >= 0) {\n sink.setNodeValue(placeholder, index, true);\n }\n }\n }\n writeEdges(plan, push, options);\n}\n\n/**\n * Take back the ids the exporter rewrote under `sanitizeIds: \"mangle\"`: a frame's\n * `property_value: graphty:originalId \"...\"` names its original id, which replaces the written one\n * wherever the file names it (the property value itself is dropped). An original that another\n * frame already uses as its id is not restored.\n * @param records - the node records\n * @param restored - receives written id to original id\n */\nfunction restoreIds(records: readonly NodeRecord[], restored: Map<string, string>): void {\n const taken = new Set(records.map((r) => r.id));\n for (const record of records) {\n const values = record.lists.get(\"property_value\") as { relation: string; value: string }[] | undefined;\n const at = values?.findIndex((v) => v.relation === ORIGINAL_ID) ?? -1;\n if (values === undefined || at < 0) {\n continue;\n }\n const original = originalText(values[at].value);\n if (taken.has(original)) {\n continue;\n }\n taken.add(original);\n restored.set(record.id, original);\n values.splice(at, 1);\n if (values.length === 0) {\n record.lists.delete(\"property_value\");\n }\n }\n}\n\n/**\n * The original id of a `graphty:originalId` property value: the exporter writes it as JSON text (so\n * every character survives); a value that is not a JSON string is the id as it stands.\n * @param value - the property value\n * @returns the original id\n */\nfunction originalText(value: string): string {\n try {\n const parsed: unknown = JSON.parse(value);\n return typeof parsed === \"string\" ? parsed : value;\n } catch {\n return value;\n }\n}\n\n/**\n * Push the planned edges through the direction resolver, with their relation and qualifiers.\n * @param plan - the plan\n * @param push - the pusher\n * @param options - the resolved options\n */\nfunction writeEdges(plan: GraphPlan, push: Pusher, options: ReturnType<typeof resolveImportOptions>): void {\n const { sink, report } = push;\n const direction = new DirectionResolver(sink, report, options.onMixedDirection);\n direction.setHeader(true);\n if (plan.edges.length === 0) {\n return;\n }\n const relation = declareResolved(sink, \"edge\", oboColumnDecl(\"edge\", \"relation\"), report).handle;\n const qualifiers = plan.edges.some((e) => e.edge.qualifiers !== null)\n ? declareResolved(sink, \"edge\", oboColumnDecl(\"edge\", \"qualifiers\"), report).handle\n : null;\n for (const { source, edge } of plan.edges) {\n push.tick();\n const before = sink.edgeCount;\n try {\n const e = direction.addEdge(push.id(source), push.id(edge.target), \"directed\", undefined, {\n line: edge.line,\n element: source,\n });\n report.counts.edges += sink.edgeCount - before;\n if (e < 0) {\n continue;\n }\n sink.setEdgeValue(relation, e, edge.relation);\n if (qualifiers !== null && edge.qualifiers !== null) {\n sink.setEdgeValue(qualifiers, e, edge.qualifiers);\n }\n } catch (err) {\n report.recordError(err, { line: edge.line, element: source });\n report.counts.skippedEdges++;\n }\n }\n}\n\n/**\n * Feed the physical lines to the reader as logical lines: backslash continuations joined (the parts\n * collected and joined once, so a value continued over many lines costs its length), form feeds\n * outside quotes split. A backslash inside a `!` comment never continues a line, and a continuation\n * never swallows a frame header or a blank line.\n * @param lines - the line reader\n * @param reader - the OBO reader\n */\nasync function readLines(lines: LineReader, reader: OboReader): Promise<void> {\n const parts: string[] = [];\n let partLine = 0;\n const feed = (text: string, line: number): void => {\n for (const piece of splitFormFeeds(text)) {\n reader.line(piece, line);\n }\n };\n for await (const physical of lines) {\n const { line } = lines;\n if (parts.length > 0) {\n const head = physical.trimStart();\n if (head.length === 0 || head.startsWith(\"[\")) {\n reader.tally(\n \"parse-error\",\n OBO_ISSUE.SYNTAX,\n \"a line continuation before a frame header or a blank line was ignored\",\n \"\\\\\",\n partLine,\n );\n feed(parts.join(\"\"), partLine);\n parts.length = 0;\n } else {\n reader.tally(\n \"coercion\",\n OBO_ISSUE.DEPRECATED_SYNTAX,\n \"a backslash line continuation was joined (deprecated in 1.4)\",\n \"\\\\\",\n partLine,\n );\n }\n }\n if (endsWithContinuation(physical) && stripComment(physical) === physical) {\n parts.push(physical.slice(0, -1));\n partLine = line;\n continue;\n }\n if (parts.length > 0) {\n parts.push(physical);\n feed(parts.join(\"\"), line);\n parts.length = 0;\n } else {\n feed(physical, line);\n }\n }\n if (parts.length > 0) {\n reader.tally(\n \"coercion\",\n OBO_ISSUE.DEPRECATED_SYNTAX,\n \"a backslash line continuation was joined (deprecated in 1.4)\",\n \"\\\\\",\n partLine,\n );\n feed(parts.join(\"\"), partLine);\n }\n}\n\n/**\n * Confidence that a head is OBO (design 1.5): after a BOM, blank lines and `!` comment lines, 0.9\n * when the first significant line is `format-version:` or a `[Term]` / `[Typedef]` / `[Instance]`\n * header, or such a header follows `tag: value` lines; 0.4 for a head of only `tag: value` lines.\n * @param head - the first bytes\n * @returns the confidence\n */\nfunction sniffObo(head: Uint8Array): number {\n let text = new TextDecoder(\"utf-8\").decode(head.subarray(0, SNIFF_BYTES));\n if (text.charCodeAt(0) === 0xfeff) {\n text = text.slice(1);\n }\n const lines = text.split(/\\r\\n|\\r|\\n|\\f/);\n // the last line may be cut mid-way\n if (lines.length > 1 && head.byteLength >= SNIFF_BYTES) {\n lines.pop();\n }\n let tagLines = 0;\n for (const raw of lines) {\n const line = raw.trim();\n if (line.length === 0 || line.startsWith(\"!\")) {\n continue;\n }\n if (/^\\[(Term|Typedef|Instance)\\]\\s*(!.*)?$/.test(line)) {\n return 0.9;\n }\n if (tagLines === 0 && /^format-version\\s*:/.test(line)) {\n return 0.9;\n }\n if (/^[A-Za-z][A-Za-z0-9_-]*\\s*:(\\s|$)/.test(line)) {\n tagLines++;\n continue;\n }\n return 0;\n }\n return tagLines > 0 ? 0.4 : 0;\n}\n\n/**\n * The OBO importer plugin.\n * @category Built-in formats\n */\nexport const oboImporter: GraphImporter<OboImportOptions> = Object.freeze({\n format: \"obo\",\n options: Object.freeze([\"obsolete\", \"typedefs\"]),\n extensions: Object.freeze([\".obo\"]),\n mimeTypes: Object.freeze([\"text/obo\", \"application/obo\"]),\n\n /**\n * Confidence that the head is an OBO file.\n * @param head - the first bytes\n * @returns the confidence\n */\n sniff(head: Uint8Array): number {\n return sniffObo(head);\n },\n\n /**\n * Read an OBO file into the sink.\n * @param input - the text, bytes or stream\n * @param sink - the sink\n * @param options - format-specific and common options\n * @returns the import report; ImportError on a fatal error or beyond the error limit\n */\n async import(\n input: ImportInput,\n sink: GraphSink,\n options?: OboImportOptions & CommonImportOptions,\n ): Promise<ImportReport> {\n const resolved = resolveImportOptions(options, DEFAULTS);\n const obo = resolveOboOptions(options);\n const report = new ImportReportBuilder(\"obo\", resolved.errorLimit);\n reportSinkOptions(sink, options, report, true);\n reportUnusedOptions(options, report, USED_OPTIONS);\n const reader = new OboReader(report, resolved.signal, obo.typedefs === \"nodes\");\n await readLines(new LineReader(input, report, resolved), reader);\n reader.finishFrame();\n if (!reader.significant) {\n report.fail(OBO_ISSUE.EMPTY_INPUT, \"the input is empty\");\n }\n const notObo = reader.notObo();\n if (notObo !== null) {\n report.fail(\n OBO_ISSUE.NOT_OBO,\n `the input is not OBO: it has no frame header and no header tag, and line ${notObo} is not a tag-value line`,\n { line: notObo },\n );\n }\n throwIfAborted(resolved.signal);\n reader.checkHeader();\n writeGraph(reader, sink, report, resolved, obo);\n const typedefs = ownRecord<Record<string, string[]>>();\n for (const [id, record] of reader.typedefs) {\n typedefs[id] = record.raw;\n }\n const extra: Record<string, unknown> = { header: reader.headerRecord(), typedefs };\n if (reader.unknownFrames.length > 0) {\n extra.unknownFrames = reader.unknownFrames;\n }\n sink.setMeta({ ...reader.meta(), extra: { obo: extra } });\n throwIfAborted(resolved.signal);\n return report.finish();\n },\n});\n","/**\n * The OBO exporter: writes a snapshot as an OBO 1.4 flat file, the text format of the Gene\n * Ontology and the OBO Foundry ontologies.\n *\n * Every node is a frame (`[Term]`, or `[Instance]` / `[Typedef]` from the `type` column) in node\n * order; every edge is a clause on its source's frame: `is_a: T` for the relation `is_a`,\n * `instance_of: T` on an Instance, `relationship: R T` for anything else, an edge without a\n * relation as `is_a` (the `relation` option). The columns of the OBO vocabulary\n * (src/common/ontology.ts: `name`, `namespace`, `def`, `synonym`, `xref`, ...) are written back\n * as their tags; any other node column becomes `property_value: <column> \"<value>\" xsd:<type>`\n * lines (with a `[Typedef]` declaring the column as a metadata relation), any other edge column a\n * qualifier of the edge's clause. A placeholder node (`graphty.placeholder`, a target no frame\n * declared) gets no frame, so the re-import makes it again. The header, the Typedefs and the\n * unknown frames an OBO import kept in `meta.extra.obo` are written back.\n *\n * check() predicts every difference the OBO importer produces on re-import: a vocabulary column\n * whose values the file cannot carry exactly is written as `property_value` lines instead and\n * reported, never written half right.\n */\n\nimport { type Column, GraphFormatError, type GraphSnapshot, type NodeId } from \"@graphty/graph-format\";\n\nimport {\n COLUMN_AS_PROPERTY_VALUE_CODE,\n GRAPH_COLUMN_AS_METADATA_CODE,\n NODE_ORDER_CODE,\n RELATION_ASSUMED_CODE,\n ROLE_ASSUMED_CODE,\n TYPEDEF_NODES_CODE,\n} from \"../../common/codes.js\";\nimport { type PairFolding, pairFolding } from \"../../common/direction.js\";\nimport { capabilities, LOSS } from \"../../common/export.js\";\nimport { formatNumber } from \"../../common/format.js\";\nimport { OBO_NODE_COLUMNS, PLACEHOLDER_COLUMN, SYNONYM_SCOPES } from \"../../common/ontology.js\";\nimport {\n capabilityNotes,\n cellOf,\n emptyColumnNotes,\n fitsVocabulary,\n FRAME_KINDS,\n type FrameKind,\n framelessNodes,\n isQualifierRecord,\n movedNodes,\n type NoteFn,\n notePropertyColumn,\n slotColumn,\n textOf,\n UNWRITTEN_ROLES,\n} from \"../../common/ontology-export.js\";\nimport { type ResolvedExportOptions, resolveExportOptions } from \"../../common/options.js\";\nimport { agree, plural } from \"../../common/plural.js\";\nimport { type ExplicitWeights, explicitWeights } from \"../../common/weights.js\";\nimport { encodeChunks, joinText } from \"../../common/writer.js\";\nimport { type CommonExportOptions, type ExportCapabilities, type GraphExporter, type LossNote } from \"../../types.js\";\nimport { BOOL_TAGS, DEPRECATED_TAGS, ID_LIST_TAGS, TEXT_TAGS, TYPEDEF_TAGS } from \"./importer.js\";\nimport {\n escapeOboQuoted,\n escapeOboValue,\n escapeOboWord,\n hasLineEnd,\n isOboWord,\n isQualifierName,\n NOT_IN_WORD,\n qualifierBlock,\n tokenize,\n} from \"./syntax.js\";\n\n/**\n * The format-specific options of the OBO exporter.\n * @category Built-in formats\n */\nexport interface OboExportOptions extends CommonExportOptions {\n /**\n * The relation written for an edge that has none of its own (no `relation` value): an OBO id\n * such as `is_a` or `part_of`. Reasoners and ROBOT read `is_a` as subclassing.\n * @defaultValue \"is_a\"\n */\n relation?: string | undefined;\n /**\n * The `ontology` id written in the header, such as `go` or `uberon`. It may hold letters,\n * digits and `_ . - /`; any other character makes checkExport() and the save throw\n * E_UNSUPPORTED. The default is the id an OBO import read, else the graph name with every other\n * character replaced by `_`, else no `ontology` line.\n * @defaultValue as read, else the graph name\n */\n ontology?: string | undefined;\n}\n\n/**\n * The loss notes the OBO exporter's check() returns, by name. A key is the code without its\n * severity and format prefixes.\n * @category Built-in formats\n */\nexport const OBO_LOSS = Object.freeze({\n /** A node column outside the OBO vocabulary (or one whose values a tag cannot carry exactly) reads back inside the `property_value` column. */\n COLUMN_AS_PROPERTY_VALUE: COLUMN_AS_PROPERTY_VALUE_CODE,\n /** An edge column (or the explicit weights) reads back inside the `qualifiers` column. */\n EDGE_COLUMN_AS_QUALIFIER: \"W_OBO_EDGE_COLUMN_AS_QUALIFIER\",\n /** Every edge is written from its source to its target, so an undirected graph reads back as directed. */\n UNDIRECTED_AS_DIRECTED: \"W_OBO_UNDIRECTED_AS_DIRECTED\",\n /** Two identical clauses on one frame (parallel edges with one relation and the same qualifiers, a repeated list item) read back as one. */\n DUPLICATE_CLAUSE: \"W_OBO_DUPLICATE_CLAUSE\",\n /** An edge without a relation is written with the `relation` option (default `is_a`). */\n RELATION_ASSUMED: RELATION_ASSUMED_CODE,\n /** A relation that is not an OBO id (empty, or holding a space, `!`, `{` or `}`) is written with `_` in place of those characters. */\n RELATION_RENAMED: \"W_OBO_RELATION_RENAMED\",\n /** The graph name is not an ontology id; the header `ontology` is written with `_` in place of the other characters. */\n ONTOLOGY_NAME: \"W_OBO_ONTOLOGY_NAME\",\n /** `[Typedef]` frames read back as nodes only under the importer's `typedefs: \"nodes\"`; by default they are metadata. */\n TYPEDEF_NODES: TYPEDEF_NODES_CODE,\n /** Edges are written in the frame of their source node, so they read back grouped by source, in node order. */\n EDGE_ORDER: \"W_OBO_EDGE_ORDER\",\n /**\n * A graph attribute is written as a header `property_value` and reads back in `snapshot.meta.extra.obo.header`,\n * not as a graph attribute.\n */\n GRAPH_COLUMN_AS_METADATA: GRAPH_COLUMN_AS_METADATA_CODE,\n /** A carriage return or form feed in a text cannot be written; it is written as a line feed. */\n LINE_END: \"W_OBO_LINE_END\",\n /** The nodes read back in a different order. */\n NODE_ORDER: NODE_ORDER_CODE,\n /** A mutual pair is written as two clauses without its mark. */\n MUTUAL_EXPANDED: LOSS.MUTUAL_EXPANDED,\n /**\n * The undirected edges of a mixed graph are written the way `onMixedDirection` chose (\"directed\" or \"undirected\").\n */\n MIXED_DIRECTION: LOSS.MIXED_DIRECTION,\n /**\n * The graph has both directed and undirected edges and `onMixedDirection` is \"error\". An import stops; a save to a\n * format that holds one direction per file fails with E_DIRECTED. Pass \"directed\" or \"undirected\" to read or write\n * it anyway.\n */\n MIXED_DIRECTION_ERROR: LOSS.MIXED_DIRECTION_ERROR,\n /** OBO has no edge ids. */\n EDGE_IDS_DROPPED: LOSS.EDGE_IDS_DROPPED,\n /** OBO has no positions. */\n POSITIONS_DROPPED: LOSS.POSITIONS,\n /** OBO has no containment. */\n HIERARCHY_DROPPED: LOSS.HIERARCHY,\n /** OBO has no time. */\n TEMPORAL_DROPPED: LOSS.TEMPORAL,\n /** OBO has no visual columns. */\n VIZ_DROPPED: LOSS.VIZ,\n /** An attribute with a role the format has no place for is written as a plain attribute; the role is lost. */\n ROLE_DROPPED: LOSS.ROLE,\n /**\n * An attribute without a role is written where the format keeps a role (for example, a `name` column as the label), and\n * reads back with that role.\n */\n ROLE_ASSUMED: ROLE_ASSUMED_CODE,\n /**\n * An attribute with a role (for example, the label) is written where the format keeps that role, and reads back under the\n * name the format's importer gives it.\n */\n COLUMN_NAME_CHANGED: LOSS.COLUMN_NAME_CHANGED,\n /**\n * An OBO attribute stored as text where graph-io uses a dictionary (or the other way round); it reads back with\n * graph-io's usual type. The values are the same.\n */\n DTYPE_UNSUPPORTED: LOSS.DTYPE,\n /** A column without a value on any written element reads back absent. */\n EMPTY_COLUMN_DROPPED: LOSS.EMPTY_COLUMN,\n /** A declared default: OBO has none. */\n DEFAULT_DROPPED: LOSS.DEFAULT,\n /** Declared options: OBO has no enumerations. */\n OPTIONS_DROPPED: LOSS.OPTIONS,\n /** An extension table OBO cannot carry. */\n EXTENSION_TABLE_DROPPED: LOSS.EXTENSION_TABLE,\n /**\n * Node ids the format cannot write, under `sanitizeIds: \"error\"`; the save fails with E_INVALID_ID. Pass\n * `sanitizeIds: \"mangle\"` to rewrite them.\n */\n ID_CHARSET: LOSS.ID_CHARSET,\n /** Node ids OBO cannot write as they are, under sanitizeIds \"mangle\": rewritten, the original kept. */\n ID_MANGLED: LOSS.ID_MANGLED,\n /** Numeric ids are written as text and read back as strings. */\n ID_TEXT_TYPE: LOSS.ID_TEXT_TYPE,\n /**\n * Two node ids would be written as the same text (the number 5 and the text \"5\"); the save fails with\n * E_INVALID_ID.\n */\n ID_TEXT_COLLISION: LOSS.ID_TEXT_COLLISION,\n});\n\n/**\n * What the OBO flat file keeps: a directed multigraph with self-loops and any id (the exporter's\n * own rule refuses whitespace, control characters, `!`, `{` and `}`). No column of the snapshot's own reads back as\n * a column: the file keeps the OBO vocabulary (`name`, `def`, `synonym`, ... with their own\n * types) and writes every other node column as property values and every edge column as\n * qualifiers, which check() reports column by column.\n * @category Built-in formats\n */\nexport const OBO_CAPABILITIES: ExportCapabilities = capabilities({\n mixedDirection: false,\n multiEdges: true,\n selfLoops: true,\n edgeIds: \"none\",\n idCharset: \"any\",\n dtypes: [],\n components: false,\n lists: false,\n json: false,\n defaults: false,\n options: false,\n hierarchy: false,\n temporal: \"none\",\n graphAttributes: false,\n positions: false,\n viz: false,\n});\n\n/** The roles OBO has a slot for, and the column names its importer gives them. */\n\n/** The node column that keeps a rewritten id's original (restored by restoreMangledIds). */\nconst ORIGINAL_ID = \"graphty:originalId\";\n\n/** The edge columns of the vocabulary. */\nconst RELATION_COLUMN = \"relation\";\nconst QUALIFIERS_COLUMN = \"qualifiers\";\n\n/** The qualifier name the explicit weights are written under. */\nconst WEIGHT_QUALIFIER = \"weight\";\n\n/** The relations a file may use without declaring them (the importer's built-ins). */\nconst BUILTIN_RELATIONS: ReadonlySet<string> = new Set([\n \"is_a\",\n \"instance_of\",\n \"disjoint_from\",\n \"inverse_of\",\n \"union_of\",\n \"intersection_of\",\n]);\n\n/** Marks where the edge clauses go in TAG_ORDER. */\nconst EDGES = \"\\u0000edges\";\n\n/** Marks where the unknown tags go in TAG_ORDER. */\nconst UNRECOGNIZED = \"obo.unrecognized\";\n\n/** The order of the tags in a frame (the OBO 1.4 guide's, Term, Instance and Typedef tags merged). */\nconst TAG_ORDER: readonly string[] = [\n \"is_anonymous\",\n \"name\",\n \"namespace\",\n \"alt_id\",\n \"def\",\n \"comment\",\n \"subset\",\n \"synonym\",\n \"xref\",\n \"builtin\",\n \"property_value\",\n \"domain\",\n \"range\",\n \"holds_over_chain\",\n \"is_anti_symmetric\",\n \"is_cyclic\",\n \"is_reflexive\",\n \"is_symmetric\",\n \"is_asymmetric\",\n \"is_transitive\",\n \"is_functional\",\n \"is_inverse_functional\",\n EDGES,\n \"intersection_of\",\n \"union_of\",\n \"equivalent_to\",\n \"disjoint_from\",\n \"inverse_of\",\n \"transitive_over\",\n \"equivalent_to_chain\",\n \"disjoint_over\",\n \"created_by\",\n \"creation_date\",\n \"is_obsolete\",\n \"replaced_by\",\n \"consider\",\n \"expand_assertion_to\",\n \"expand_expression_to\",\n \"is_metadata_tag\",\n \"is_class_level\",\n UNRECOGNIZED,\n];\n\n/** The header tags in the 1.4 guide's order; every other kept header tag follows them. */\nconst HEADER_ORDER: readonly string[] = [\n \"format-version\",\n \"data-version\",\n \"version\",\n \"date\",\n \"saved-by\",\n \"auto-generated-by\",\n \"import\",\n \"subsetdef\",\n \"synonymtypedef\",\n \"idspace\",\n \"default-relationship-id-prefix\",\n \"id-mapping\",\n \"default-namespace\",\n \"namespace-id-rule\",\n \"remark\",\n \"ontology\",\n];\n\n/** Tags the importer applies (so an unknown tag of that name would not read back as unknown). */\nconst APPLIED_TAGS: ReadonlySet<string> = new Set([\n \"id\",\n \"is_a\",\n \"instance_of\",\n \"relationship\",\n \"intersection_of\",\n \"holds_over_chain\",\n \"equivalent_to_chain\",\n \"def\",\n \"expand_assertion_to\",\n \"expand_expression_to\",\n \"synonym\",\n \"xref\",\n \"property_value\",\n ...TEXT_TAGS,\n ...BOOL_TAGS,\n ...ID_LIST_TAGS,\n ...DEPRECATED_TAGS.keys(),\n]);\n\n/** The vocabulary node columns the flat file writes as tags (`type`, `name` and `propertyType` aside). */\nconst TAG_COLUMNS: ReadonlySet<string> = new Set(\n Object.keys(OBO_NODE_COLUMNS).filter((name) => name !== \"type\" && name !== \"name\" && name !== \"propertyType\"),\n);\n\n/** The xsd datatype of a dtype in a `property_value` line. */\nconst XSD: Readonly<Record<string, string>> = Object.freeze({\n string: \"xsd:string\",\n dict: \"xsd:string\",\n bool: \"xsd:boolean\",\n i32: \"xsd:integer\",\n u32: \"xsd:integer\",\n u8: \"xsd:integer\",\n f32: \"xsd:double\",\n f64: \"xsd:double\",\n});\n\n/** A node column written as `property_value` lines. */\ninterface PropertyColumn {\n readonly column: Column;\n /** The relation the lines name (the column name, or its id form). */\n readonly relation: string;\n}\n\n/** An edge column written as qualifiers. */\ninterface QualifierColumn {\n readonly column: Column;\n /** The qualifier name (the column name, or its written form). */\n readonly name: string;\n}\n\n/** Everything write() needs, computed once by plan(). */\ninterface Plan {\n readonly notes: LossNote[];\n readonly fatal: GraphFormatError | null;\n readonly options: { readonly relation: string; readonly ontology: string | null };\n /** The id written for each node. */\n readonly ids: readonly string[];\n /** The rewritten nodes' original ids, by node index. */\n readonly originals: ReadonlyMap<number, string>;\n /** 1 for a node written without a frame (a placeholder the re-import makes again). */\n readonly frameless: Uint8Array;\n /** The frame type of each node. */\n readonly kinds: readonly FrameKind[];\n /** The label column (written as `name`), or null. */\n readonly label: Column | null;\n /** The vocabulary columns written as their tags, by tag. */\n readonly tags: ReadonlyMap<string, Column>;\n /** The node columns written as `property_value` lines. */\n readonly properties: readonly PropertyColumn[];\n /** The written edges by source: edgeStart[i]..edgeStart[i + 1] in edgeOrder. */\n readonly edgeStart: Uint32Array;\n readonly edgeOrder: Uint32Array;\n /** The target of each edge. */\n readonly dst: ArrayLike<number>;\n /** The relation written for each edge. */\n readonly relations: readonly string[];\n /** The vocabulary `qualifiers` edge column, or null. */\n readonly qualifiers: Column | null;\n /** The other edge columns written as qualifiers. */\n readonly edgeColumns: readonly QualifierColumn[];\n readonly weights: ExplicitWeights;\n /** The header lines. */\n readonly header: readonly string[];\n /** The frames after the nodes (kept Typedefs, declared relations, unknown frames), as lines. */\n readonly tail: readonly string[];\n}\n\n/** Counts gathered while frames are written. */\ninterface FrameStats {\n /** Texts holding a carriage return or form feed. */\n lineEnds: number;\n /** Whether every `obo.qualifiers` entry found its clause. */\n qualifiersPlaced: boolean;\n}\n\n// ============================================================ values\n\n/**\n * Whether a text survives as an unquoted tag value: the reader trims it, and the OBO grammar\n * (fastobo, owlapi) refuses an empty one.\n * @param text - the text\n * @returns true when the text is not empty and has no surrounding whitespace\n */\nfunction isTrimmed(text: string): boolean {\n return text.length > 0 && text === text.trim();\n}\n\n/**\n * Whether a value is an array whose items all pass a test.\n * @param value - the value\n * @param item - the item test\n * @param nonEmpty - whether the array must have an item\n * @returns true when it is such an array\n */\nfunction arrayOf(value: unknown, item: (v: unknown) => boolean, nonEmpty = true): value is unknown[] {\n return Array.isArray(value) && (!nonEmpty || value.length > 0) && value.every(item);\n}\n\n/**\n * Whether a value is a string the unquoted xref slot keeps (non-empty, no surrounding whitespace).\n * @param value - the value\n * @returns true for such a string\n */\nfunction isXrefId(value: unknown): value is string {\n return typeof value === \"string\" && value.length > 0 && isTrimmed(value);\n}\n\n/**\n * Whether a value is an OBO word.\n * @param value - the value\n * @returns true for a string isOboWord() accepts\n */\nfunction isWord(value: unknown): value is string {\n return typeof value === \"string\" && isOboWord(value);\n}\n\n/**\n * Whether an object has exactly the given keys, `qualifiers` optional (and then a qualifier record).\n * @param value - the value\n * @param keys - the required keys\n * @returns true when it has those keys and nothing else\n */\nfunction hasKeys(value: unknown, keys: readonly string[]): value is Record<string, unknown> {\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) {\n return false;\n }\n const own = Object.keys(value);\n const record = value as Record<string, unknown>;\n if (Object.hasOwn(record, \"qualifiers\")) {\n if (!isQualifierRecord(record.qualifiers, isQualifierName)) {\n return false;\n }\n return own.length === keys.length + 1 && keys.every((k) => Object.hasOwn(record, k));\n }\n return own.length === keys.length && keys.every((k) => Object.hasOwn(record, k));\n}\n\n/**\n * Replace every character a word cannot hold with `_`.\n * @param text - the text\n * @returns a word\n */\nfunction wordOf(text: string): string {\n const out = text.replaceAll(new RegExp(NOT_IN_WORD.source, \"gu\"), \"_\");\n return out.length === 0 ? \"_\" : out;\n}\n\n/**\n * A qualifier record as name / value pairs (a list value as one pair per item).\n * @param record - a record isQualifierRecord() accepts\n * @returns the pairs\n */\nfunction qualifierPairs(record: unknown): [string, string][] {\n const out: [string, string][] = [];\n for (const [name, value] of Object.entries(record as Record<string, string | string[]>)) {\n for (const item of Array.isArray(value) ? value : [value]) {\n out.push([name, item]);\n }\n }\n return out;\n}\n\n// ============================================================ the plan\n\n/**\n * Resolve the OBO-specific options.\n * @param options - the caller's options\n * @returns the relation and the ontology; E_UNSUPPORTED for a value that is not an OBO id\n */\nfunction resolveOboOptions(options: OboExportOptions | undefined): {\n readonly relation: string;\n readonly ontology: string | null;\n} {\n const relation = options?.relation ?? \"is_a\";\n if (typeof relation !== \"string\" || !isOboWord(relation)) {\n throw new GraphFormatError(\"E_UNSUPPORTED\", `option relation: ${JSON.stringify(relation)} is not an OBO id`, {\n option: \"relation\",\n found: relation,\n });\n }\n const ontology = options?.ontology ?? null;\n if (ontology !== null && (typeof ontology !== \"string\" || !/^[A-Za-z0-9_.\\-/]+$/.test(ontology))) {\n throw new GraphFormatError(\n \"E_UNSUPPORTED\",\n `option ontology: ${JSON.stringify(ontology)} is not an ontology id (letters, digits, _ . - /)`,\n { option: \"ontology\", found: ontology },\n );\n }\n return { relation, ontology };\n}\n\n/**\n * The ids to write: each node's id text, or under \"mangle\" a word with `_` for the characters a\n * word cannot hold (and `_2`, `_3`... on a collision), the original kept.\n * @param snapshot - the snapshot\n * @param mode - the sanitizeIds option\n * @param note - records a note\n * @returns the ids, the originals and the fatal error, if any\n */\nfunction planIds(\n snapshot: GraphSnapshot,\n mode: \"error\" | \"mangle\",\n note: NoteFn,\n): { ids: string[]; originals: Map<number, string>; fatal: GraphFormatError | null } {\n const n = snapshot.nodeCount;\n const ids: string[] = new Array<string>(n);\n const bad: number[] = [];\n let numeric = 0;\n for (let i = 0; i < n; i++) {\n const id: NodeId = snapshot.ids.idOf(i);\n if (typeof id === \"number\") {\n numeric++;\n }\n ids[i] = String(id);\n if (!isOboWord(ids[i])) {\n bad.push(i);\n }\n }\n if (numeric > 0) {\n note(\n LOSS.ID_TEXT_TYPE,\n `${numeric} numeric node id${plural(numeric)} ${agree(numeric, \"is\", \"are\")} written as text and read back as strings`,\n null,\n numeric,\n );\n }\n const originals = new Map<number, string>();\n let fatal: GraphFormatError | null = null;\n if (bad.length > 0 && mode === \"error\") {\n fatal = refuseIds(snapshot, ids, bad, note);\n } else if (bad.length > 0) {\n mangleIds(ids, bad, originals, note);\n }\n return { ids, originals, fatal: fatal ?? collidingIds(snapshot, ids, note) };\n}\n\n/**\n * Note the ids that are not OBO words, for a save that refuses them.\n * @param snapshot - the snapshot\n * @param ids - the id texts\n * @param bad - the indices of the ids that are not OBO words\n * @param note - records a note\n * @returns the error the save throws\n */\nfunction refuseIds(\n snapshot: GraphSnapshot,\n ids: readonly string[],\n bad: readonly number[],\n note: NoteFn,\n): GraphFormatError {\n note(\n LOSS.ID_CHARSET,\n `${bad.length} node id${plural(bad.length)} ${agree(bad.length, \"is\", \"are\")} not OBO ids (empty, or holding whitespace, a control character, \"!\", \"{\" or \"}\"); the save fails unless sanitizeIds is \"mangle\"`,\n null,\n bad.length,\n );\n return new GraphFormatError(\n \"E_INVALID_ID\",\n `${bad.length} node id${plural(bad.length)} cannot be written as OBO ids (first: ${JSON.stringify(ids[bad[0]])}); pass sanitizeIds: \"mangle\" to rewrite them`,\n { reason: \"charset\", count: bad.length, id: snapshot.ids.idOf(bad[0]), index: bad[0] },\n );\n}\n\n/**\n * Rewrite the ids that are not OBO words with \"_\" (and `_2`, `_3`... on a collision), keeping the\n * originals.\n * @param ids - the id texts, rewritten in place\n * @param bad - the indices of the ids that are not OBO words\n * @param originals - receives each rewritten id's original text\n * @param note - records a note\n */\nfunction mangleIds(ids: string[], bad: readonly number[], originals: Map<number, string>, note: NoteFn): void {\n const badSet = new Set(bad);\n const used = new Set(ids.filter((_, i) => !badSet.has(i)));\n for (const i of bad) {\n const base = wordOf(ids[i]);\n let candidate = base;\n let k = 2;\n while (used.has(candidate)) {\n candidate = `${base}_${k}`;\n k++;\n }\n used.add(candidate);\n originals.set(i, ids[i]);\n ids[i] = candidate;\n }\n note(\n LOSS.ID_MANGLED,\n `${bad.length} node id${plural(bad.length)} that ${agree(bad.length, \"is\", \"are\")} not OBO ids ${agree(bad.length, \"is\", \"are\")} rewritten with \"_\"; the originals are kept as ${ORIGINAL_ID} property values (JSON text; an import with restoreMangledIds: true reads them back as the ids)`,\n null,\n bad.length,\n );\n}\n\n/**\n * Note the first two node ids that have the same text, which OBO cannot tell apart.\n * @param snapshot - the snapshot\n * @param ids - the id texts\n * @param note - records a note\n * @returns the error the save throws, or null when every text is unique\n */\nfunction collidingIds(snapshot: GraphSnapshot, ids: readonly string[], note: NoteFn): GraphFormatError | null {\n const seen = new Map<string, number>();\n for (let i = 0; i < ids.length; i++) {\n const before = seen.get(ids[i]);\n if (before !== undefined) {\n note(\n LOSS.ID_TEXT_COLLISION,\n `node ids ${JSON.stringify(snapshot.ids.idOf(before))} and ${JSON.stringify(snapshot.ids.idOf(i))} have the same text; the save fails`,\n null,\n 1,\n );\n return new GraphFormatError(\"E_INVALID_ID\", \"two node ids have the same text; OBO keeps ids as text\", {\n reason: \"collision\",\n });\n }\n seen.set(ids[i], i);\n }\n return null;\n}\n\n/**\n * The written edges (the mirror halves of folded pairs left out) grouped by source, in node order\n * then edge order, and the direction notes.\n * @param snapshot - the snapshot\n * @param folding - the pair folding\n * @param common - the common options\n * @param note - records a note\n * @returns the edge list, the CSR by source and the targets\n */\nfunction planEdges(\n snapshot: GraphSnapshot,\n folding: PairFolding,\n common: ResolvedExportOptions,\n note: NoteFn,\n): { written: number[]; edgeStart: Uint32Array; edgeOrder: Uint32Array; dst: ArrayLike<number> } {\n const { src, dst } = snapshot.edgeList();\n const written: number[] = [];\n for (let e = 0; e < snapshot.edgeCount; e++) {\n if (!folding.folded(e)) {\n written.push(e);\n }\n }\n const edgeStart = new Uint32Array(snapshot.nodeCount + 1);\n for (const e of written) {\n edgeStart[src[e] + 1]++;\n }\n for (let i = 0; i < snapshot.nodeCount; i++) {\n edgeStart[i + 1] += edgeStart[i];\n }\n const fill = edgeStart.slice(0, snapshot.nodeCount);\n const edgeOrder = new Uint32Array(written.length);\n for (const e of written) {\n edgeOrder[fill[src[e]]++] = e;\n }\n let moved = 0;\n for (let k = 0; k < edgeOrder.length; k++) {\n if (edgeOrder[k] !== written[k]) {\n moved++;\n }\n }\n if (moved > 0) {\n note(\n OBO_LOSS.EDGE_ORDER,\n `${moved} edge${plural(moved)} ${agree(moved, \"reads\", \"read\")} back at another position: edges are written on their source's frame, grouped by source in node order`,\n null,\n moved,\n );\n }\n if (!snapshot.directed) {\n note(\n OBO_LOSS.UNDIRECTED_AS_DIRECTED,\n `the snapshot is undirected; every edge is written from its source to its target and reads back directed (${written.length} edge${plural(written.length)})`,\n null,\n written.length,\n );\n } else if (common.onMixedDirection !== \"error\") {\n const undirected = written.filter((e) => !folding.sourceDirected(e)).length;\n if (undirected > 0) {\n note(\n OBO_LOSS.UNDIRECTED_AS_DIRECTED,\n `${undirected} undirected edge${plural(undirected)} ${agree(undirected, \"is\", \"are\")} written as one directed clause each; OBO has no undirected edge`,\n null,\n undirected,\n );\n }\n }\n if (folding.mutualCount > 0) {\n note(\n LOSS.MUTUAL_EXPANDED,\n `${folding.mutualCount} mutual pair${plural(folding.mutualCount)} ${agree(folding.mutualCount, \"is\", \"are\")} written as two clauses; the mutual mark is lost`,\n null,\n folding.mutualCount,\n );\n }\n return { written, edgeStart, edgeOrder, dst };\n}\n\n/**\n * The frame types: the `type` column when every written node has one of Term, Instance or\n * Typedef, else Term for every node (and the column is a property value).\n * @param snapshot - the snapshot\n * @param frameless - the frameless flags\n * @returns the kinds and the type column used, or null\n */\nfunction planKinds(snapshot: GraphSnapshot, frameless: Uint8Array): { kinds: FrameKind[]; type: Column | null } {\n const kinds = new Array<FrameKind>(snapshot.nodeCount).fill(\"Term\");\n const type = snapshot.nodes.get(\"type\");\n if (type === null || (type.dtype !== \"dict\" && type.dtype !== \"string\")) {\n return { kinds, type: null };\n }\n for (let i = 0; i < snapshot.nodeCount; i++) {\n if (frameless[i] === 1) {\n if (type.isSet(i)) {\n return { kinds: kinds.fill(\"Term\"), type: null };\n }\n continue;\n }\n const value = cellOf(type, i);\n if (typeof value !== \"string\" || !FRAME_KINDS.has(value)) {\n return { kinds: kinds.fill(\"Term\"), type: null };\n }\n kinds[i] = value as FrameKind;\n }\n return { kinds, type };\n}\n\n/**\n * Whether a vocabulary column's values are written by its tag and read back unchanged, on every\n * written node (the vocabulary's dtype, the shape the importer builds, OBO words where the tag\n * takes an id, no surrounding space in an unquoted value, a Typedef tag on Typedef frames only).\n * @param name - the column (a TAG_COLUMNS name)\n * @param column - the column\n * @param rows - the written nodes\n * @param kinds - the frame types\n * @param scopes - the default scope of each declared synonym type\n * @returns true when the tag carries the column\n */\nfunction tagCarries(\n name: string,\n column: Column,\n rows: readonly number[],\n kinds: readonly FrameKind[],\n scopes: ReadonlyMap<string, string | null>,\n): boolean {\n const spec = OBO_NODE_COLUMNS[name];\n if (!fitsVocabulary(spec.dtype, column) || column.meta.components > 1) {\n return false;\n }\n const typedefOnly = TYPEDEF_TAGS.has(name);\n const valid = (v: unknown): boolean => {\n if (TEXT_TAGS.has(name)) {\n return typeof v === \"string\" && isTrimmed(v);\n }\n if (BOOL_TAGS.has(name)) {\n return typeof v === \"boolean\";\n }\n if (ID_LIST_TAGS.has(name)) {\n return arrayOf(v, isWord);\n }\n switch (name) {\n case \"def\":\n return typeof v === \"string\";\n case \"def.xrefs\":\n return arrayOf(v, isXrefId, false);\n case \"xref\":\n return arrayOf(v, isXrefId);\n case \"xref.descriptions\":\n return (\n typeof v === \"object\" &&\n v !== null &&\n !Array.isArray(v) &&\n Object.values(v).every((d) => typeof d === \"string\")\n );\n case \"synonym\":\n return arrayOf(\n v,\n (s) =>\n hasKeys(s, [\"text\", \"scope\", \"type\", \"xrefs\"]) &&\n typeof s.text === \"string\" &&\n typeof s.scope === \"string\" &&\n SYNONYM_SCOPES.has(s.scope) &&\n (s.type === null || isWord(s.type)) &&\n (s.type === null || (scopes.get(s.type) ?? s.scope) === s.scope) &&\n arrayOf(s.xrefs, isXrefId, false),\n );\n case \"intersection_of\":\n return arrayOf(\n v,\n (x) =>\n hasKeys(x, [\"relation\", \"target\"]) &&\n (x.relation === null || isWord(x.relation)) &&\n isWord(x.target),\n );\n case \"property_value\":\n return arrayOf(\n v,\n (x) =>\n hasKeys(x, [\"relation\", \"value\", \"datatype\"]) &&\n isWord(x.relation) &&\n x.relation !== ORIGINAL_ID &&\n typeof x.value === \"string\" &&\n (x.datatype === null || isWord(x.datatype)),\n );\n case \"holds_over_chain\":\n case \"equivalent_to_chain\":\n return arrayOf(v, (pair) => arrayOf(pair, isWord) && pair.length === 2);\n case \"expand_assertion_to\":\n case \"expand_expression_to\":\n return arrayOf(\n v,\n (x) =>\n hasKeys(x, [\"template\", \"xrefs\"]) &&\n typeof x.template === \"string\" &&\n arrayOf(x.xrefs, isXrefId, false),\n );\n case \"obo.qualifiers\":\n return (\n typeof v === \"object\" &&\n v !== null &&\n !Array.isArray(v) &&\n Object.values(v).every((entries) =>\n arrayOf(\n entries,\n (entry) =>\n hasKeys(entry, [\"value\"]) &&\n Object.hasOwn(entry, \"qualifiers\") &&\n typeof entry.value === \"string\" &&\n isQualifierRecord(entry.qualifiers, isQualifierName),\n ),\n )\n );\n default:\n return false;\n }\n };\n for (const i of rows) {\n if (!column.isSet(i)) {\n continue;\n }\n if (typedefOnly && kinds[i] !== \"Typedef\") {\n return false;\n }\n if (!valid(cellOf(column, i))) {\n return false;\n }\n }\n return true;\n}\n\n/**\n * Whether the `obo.unrecognized` column reads back unchanged: a record of tag to texts, each tag\n * one the importer does not apply on that frame type.\n * @param column - the column\n * @param rows - the written nodes\n * @param kinds - the frame types\n * @returns true when every cell is written as unknown tags and read back as the same\n */\nfunction unrecognizedCarried(column: Column, rows: readonly number[], kinds: readonly FrameKind[]): boolean {\n if (column.dtype !== \"json\") {\n return false;\n }\n for (const i of rows) {\n const v = cellOf(column, i);\n if (v === undefined) {\n continue;\n }\n if (typeof v !== \"object\" || v === null || Array.isArray(v)) {\n return false;\n }\n for (const [tag, values] of Object.entries(v)) {\n const applied =\n (APPLIED_TAGS.has(tag) || TYPEDEF_TAGS.has(tag)) &&\n !(TYPEDEF_TAGS.has(tag) && kinds[i] !== \"Typedef\") &&\n !(tag === \"instance_of\" && kinds[i] !== \"Instance\");\n if (\n applied ||\n tag.length === 0 ||\n !isTrimmed(tag) ||\n !arrayOf(values, (t) => typeof t === \"string\" && isTrimmed(t))\n ) {\n return false;\n }\n }\n }\n return true;\n}\n\n/**\n * The default scope of each synonym type the kept header declares (null: none declared).\n * @param header - the kept header (tag to raw values)\n * @returns the scopes by type\n */\nfunction synonymTypeScopes(header: Readonly<Record<string, readonly string[]>>): Map<string, string | null> {\n const out = new Map<string, string | null>();\n for (const raw of header.synonymtypedef ?? []) {\n const tokens = tokenize(raw);\n if (tokens.length > 0 && tokens[0].kind === \"word\") {\n const scope = tokens.slice(1).find((t) => t.kind === \"word\" && SYNONYM_SCOPES.has(t.text));\n out.set(tokens[0].text, scope?.text ?? null);\n }\n }\n return out;\n}\n\n/**\n * The record of an OBO import kept under `meta.extra.obo`, or empty records.\n * @param snapshot - the snapshot\n * @returns the header, the Typedefs and the unknown frames\n */\nfunction keptObo(snapshot: GraphSnapshot): {\n header: Record<string, string[]>;\n typedefs: Record<string, Record<string, string[]>>;\n unknownFrames: { type: string; clauses: Record<string, string[]> }[];\n} {\n const raw = snapshot.meta.extra.obo;\n const record =\n typeof raw === \"object\" && raw !== null && !Array.isArray(raw) ? (raw as Record<string, unknown>) : {};\n const clauses = (value: unknown): Record<string, string[]> => {\n const out: Record<string, string[]> = {};\n if (typeof value === \"object\" && value !== null && !Array.isArray(value)) {\n for (const [tag, values] of Object.entries(value)) {\n if (Array.isArray(values)) {\n out[tag] = values.filter((v): v is string => typeof v === \"string\");\n }\n }\n }\n return out;\n };\n const typedefs: Record<string, Record<string, string[]>> = {};\n if (typeof record.typedefs === \"object\" && record.typedefs !== null && !Array.isArray(record.typedefs)) {\n for (const [id, frame] of Object.entries(record.typedefs)) {\n typedefs[id] = clauses(frame);\n }\n }\n const unknownFrames = Array.isArray(record.unknownFrames)\n ? record.unknownFrames.flatMap((f: unknown) =>\n typeof f === \"object\" && f !== null && typeof (f as { type?: unknown }).type === \"string\"\n ? [{ type: (f as { type: string }).type, clauses: clauses((f as { clauses?: unknown }).clauses) }]\n : [],\n )\n : [];\n return { header: clauses(record.header), typedefs, unknownFrames };\n}\n\n/**\n * Plan an export: the notes, the fatal condition and what is written.\n * @param snapshot - the snapshot\n * @param options - the caller's options\n * @returns the plan\n */\nfunction plan(snapshot: GraphSnapshot, options: (OboExportOptions & CommonExportOptions) | undefined): Plan {\n const common = resolveExportOptions(options);\n const obo = resolveOboOptions(options);\n const notes: LossNote[] = [];\n const note: NoteFn = (code, message, column = null, count = null) => {\n notes.push(Object.freeze({ code, message, column, count }));\n };\n let fatal: GraphFormatError | null = null;\n\n const { ids, originals, fatal: idFatal } = planIds(snapshot, common.sanitizeIds, note);\n fatal ??= idFatal;\n const folding = pairFolding(snapshot);\n const { written, edgeStart, edgeOrder, dst } = planEdges(snapshot, folding, common, note);\n const frameless = framelessNodes(snapshot, written, {\n outgoingAllowed: false,\n changed: (i) => originals.has(i),\n });\n const moved = movedNodes(\n frameless,\n Array.from(edgeOrder, (e) => dst[e]),\n );\n if (moved > 0) {\n note(\n NODE_ORDER_CODE,\n `${moved} node${plural(moved)} ${agree(moved, \"reads\", \"read\")} back at another position: placeholder nodes have no frame and read back after the written nodes`,\n null,\n moved,\n );\n }\n const rows: number[] = [];\n for (let i = 0; i < snapshot.nodeCount; i++) {\n if (frameless[i] === 0) {\n rows.push(i);\n }\n }\n const { kinds, type } = planKinds(snapshot, frameless);\n const typedefNodes = rows.filter((i) => kinds[i] === \"Typedef\").length;\n if (typedefNodes > 0) {\n note(\n OBO_LOSS.TYPEDEF_NODES,\n `${typedefNodes} node${plural(typedefNodes)} ${agree(typedefNodes, \"is\", \"are\")} written as [Typedef] frames; they read back as nodes only when imported with typedefs: \"nodes\", and then after the other nodes, with the [Typedef] frames that declare the relations`,\n \"type\",\n typedefNodes,\n );\n }\n\n const kept = keptObo(snapshot);\n const scopes = synonymTypeScopes(kept.header);\n // the label: the label column, or a role-less name column\n const labelSlot = slotColumn(snapshot.nodes, \"label\", \"name\");\n const labelColumn = labelSlot.column;\n const label =\n labelColumn !== null && rows.every((i) => !labelColumn.isSet(i) || isTrimmed(String(labelColumn.value(i))))\n ? labelColumn\n : null;\n const tags = planTags(snapshot, rows, kinds, scopes, label);\n fatal ??= capabilityNotes(snapshot, common, {\n caps: OBO_CAPABILITIES,\n label,\n labelAssumed: labelSlot.assumed,\n edgeSlot: \"a qualifier\",\n note,\n });\n oboColumnNotes(snapshot, label, tags, note);\n const properties = planProperties(snapshot, rows, frameless, label, tags, type, note);\n\n // edges\n const relationSlot = slotColumn(snapshot.edges, \"kind\", RELATION_COLUMN);\n const relations = planRelations(snapshot, written, relationSlot.column, obo.relation, note);\n if (relationSlot.assumed && relationSlot.column !== null) {\n note(\n ROLE_ASSUMED_CODE,\n `edge column \"${RELATION_COLUMN}\" has no role, so it is taken as the relation of each edge: it is written as each line's relation, and reads back with the relation role (\"kind\")`,\n RELATION_COLUMN,\n relationSlot.column.length - relationSlot.column.nullCount,\n );\n }\n const weights = explicitWeights(snapshot);\n const { qualifiers, edgeColumns } = planEdgeColumns(snapshot, written, relationSlot.column, weights, note);\n emptyColumnNotes(snapshot, rows, frameless, written, note);\n\n const p: Plan = {\n notes,\n fatal,\n options: obo,\n ids,\n originals,\n frameless,\n kinds,\n label,\n tags,\n properties,\n edgeStart,\n edgeOrder,\n dst,\n relations,\n qualifiers,\n edgeColumns,\n weights,\n header: [],\n tail: [],\n };\n // write every frame once: the duplicate clauses, the line ends and the qualifier placement\n let stats = simulate(p, rows);\n if (!stats.qualifiersPlaced) {\n tags.delete(\"obo.qualifiers\");\n const column = snapshot.nodes.get(\"obo.qualifiers\");\n if (column !== null) {\n properties.push({ column, relation: \"obo.qualifiers\" });\n notePropertyColumn(note, column, rows, \"property_value lines (relation obo.qualifiers)\");\n }\n stats = simulate(p, rows);\n }\n if (stats.duplicates > 0) {\n note(\n OBO_LOSS.DUPLICATE_CLAUSE,\n `${stats.duplicates} clause${plural(stats.duplicates)} ${agree(stats.duplicates, \"repeats\", \"repeat\")} another clause of their frame word for word (parallel edges with one relation and the same qualifiers, a repeated list item) and read back as one`,\n null,\n stats.duplicates,\n );\n }\n const header = planHeader(snapshot, kept.header, obo, rows, tags, note, stats);\n const tail = planTail({\n kept,\n rows,\n kinds,\n ids,\n properties,\n relations,\n edges: edgeOrder,\n xref: tags.get(\"xref\") ?? null,\n });\n if (stats.lineEnds > 0) {\n note(\n OBO_LOSS.LINE_END,\n `${stats.lineEnds} text${plural(stats.lineEnds)} ${agree(stats.lineEnds, \"holds\", \"hold\")} a carriage return or form feed, which OBO cannot carry; written as a line feed`,\n null,\n stats.lineEnds,\n );\n }\n return { ...p, header, tail };\n}\n\n/**\n * The vocabulary columns written as their tags: each one tagCarries() accepts, then the pairs\n * resolved (def.xrefs needs def, a def needs its def.xrefs written when that column exists, the\n * xref descriptions need their xrefs written).\n * @param snapshot - the snapshot\n * @param rows - the written nodes\n * @param kinds - the frame types\n * @param scopes - the default scope of each declared synonym type\n * @param label - the label column (never a tag)\n * @returns the columns by tag\n */\nfunction planTags(\n snapshot: GraphSnapshot,\n rows: readonly number[],\n kinds: readonly FrameKind[],\n scopes: ReadonlyMap<string, string | null>,\n label: Column | null,\n): Map<string, Column> {\n const tags = new Map<string, Column>();\n for (const name of TAG_COLUMNS) {\n const column = snapshot.nodes.get(name);\n if (column === null || column === label || (column.meta.role !== null && column.meta.role !== \"label\")) {\n continue;\n }\n if (\n name === UNRECOGNIZED\n ? unrecognizedCarried(column, rows, kinds)\n : tagCarries(name, column, rows, kinds, scopes)\n ) {\n tags.set(name, column);\n }\n }\n // pairs: def.xrefs needs def; xref.descriptions needs its xrefs written\n const def = tags.get(\"def\");\n const defXrefs = tags.get(\"def.xrefs\");\n if (defXrefs !== undefined && (def === undefined || rows.some((i) => def.isSet(i) !== defXrefs.isSet(i)))) {\n tags.delete(\"def.xrefs\");\n }\n if (def !== undefined && !tags.has(\"def.xrefs\") && snapshot.nodes.get(\"def.xrefs\") !== null) {\n // a def.xrefs column that is not written would read back as the empty list on every def\n tags.delete(\"def\");\n }\n const descriptions = tags.get(\"xref.descriptions\");\n if (descriptions !== undefined && !rows.every((i) => describedXrefsWritten(tags, descriptions, i))) {\n tags.delete(\"xref.descriptions\");\n }\n\n return tags;\n}\n\n/**\n * Whether every described xref of a node is written in one of its xref slots (so the description\n * has a place).\n * @param tags - the columns written as tags\n * @param descriptions - the `xref.descriptions` column\n * @param row - the node\n * @returns true when every description has its xref\n */\nfunction describedXrefsWritten(tags: ReadonlyMap<string, Column>, descriptions: Column, row: number): boolean {\n const map = cellOf(descriptions, row) as Record<string, string> | undefined;\n if (map === undefined) {\n return true;\n }\n const written = new Set<string>();\n const add = (values: unknown): void => {\n if (Array.isArray(values)) {\n for (const v of values) {\n if (typeof v === \"string\") {\n written.add(v);\n }\n }\n }\n };\n for (const name of [\"def.xrefs\", \"xref\"]) {\n const column = tags.get(name);\n if (column !== undefined) {\n add(cellOf(column, row));\n }\n }\n for (const name of [\"synonym\", \"expand_assertion_to\", \"expand_expression_to\"]) {\n const column = tags.get(name);\n const items = column === undefined ? undefined : cellOf(column, row);\n if (Array.isArray(items)) {\n for (const item of items as { xrefs: unknown }[]) {\n add(item.xrefs);\n }\n }\n }\n return Object.keys(map).every((id) => written.has(id));\n}\n\n/**\n * The OBO-only column notes: the vocabulary column of the other text dtype, and the graph columns\n * written as header property values.\n * @param snapshot - the snapshot\n * @param label - the label column written as `name`, or null\n * @param tags - the vocabulary columns written as tags\n * @param note - records a note\n */\nfunction oboColumnNotes(\n snapshot: GraphSnapshot,\n label: Column | null,\n tags: ReadonlyMap<string, Column>,\n note: NoteFn,\n): void {\n for (const [name, column] of [...tags, ...(label === null ? [] : ([[\"name\", label]] as const))]) {\n const want = name === \"name\" ? \"string\" : OBO_NODE_COLUMNS[name].dtype;\n if (\n ((want === \"string\" || want === \"dict\") && column.dtype !== want) ||\n (column.dtype === \"list\" && column.child.dtype !== \"string\")\n ) {\n const held = column.dtype === \"list\" ? `${column.child.dtype} items` : column.dtype;\n note(\n LOSS.DTYPE,\n `node column \"${column.meta.name}\" holds ${held}; it reads back as ${column.dtype === \"list\" ? \"string items\" : want}`,\n column.meta.name,\n column.length - column.nullCount,\n );\n }\n }\n for (const column of snapshot.graph) {\n note(\n GRAPH_COLUMN_AS_METADATA_CODE,\n `graph column \"${column.meta.name}\" is written as a header property_value and reads back in meta.extra.obo.header, not as a column`,\n column.meta.name,\n column.length - column.nullCount,\n );\n }\n}\n\n/**\n * The node columns written as `property_value` lines: every column that is not written by a tag,\n * the label or the type, and not one OBO leaves out (positions, visual and temporal columns), each\n * with its note.\n * @param snapshot - the snapshot\n * @param rows - the written nodes\n * @param frameless - the frameless flags\n * @param label - the label column\n * @param tags - the columns written as tags\n * @param type - the type column\n * @param note - records a note\n * @returns the columns\n */\nfunction planProperties(\n snapshot: GraphSnapshot,\n rows: readonly number[],\n frameless: Uint8Array,\n label: Column | null,\n tags: ReadonlyMap<string, Column>,\n type: Column | null,\n note: NoteFn,\n): PropertyColumn[] {\n const out: PropertyColumn[] = [];\n const slotted = new Set<Column>([\n ...tags.values(),\n ...(label === null ? [] : [label]),\n ...(type === null ? [] : [type]),\n ]);\n for (const column of snapshot.nodes) {\n const { role, name } = column.meta;\n if (slotted.has(column) || (role !== null && UNWRITTEN_ROLES.has(role))) {\n continue;\n }\n if (name === PLACEHOLDER_COLUMN && rows.every((i) => !column.isSet(i)) && frameless.includes(1)) {\n // read back from the frameless nodes alone\n continue;\n }\n const relation = isOboWord(name) && name !== ORIGINAL_ID ? name : wordOf(name.replaceAll(\":\", \"_\"));\n out.push({ column, relation });\n notePropertyColumn(note, column, rows, `property_value lines (relation ${relation})`);\n }\n return out;\n}\n\n/**\n * The relation written for each edge, with the notes of the assumed and renamed ones.\n * @param snapshot - the snapshot\n * @param written - the written edges\n * @param relation - the relation column, or null\n * @param fallback - the relation of an edge without one\n * @param note - records a note\n * @returns the relation per edge index\n */\nfunction planRelations(\n snapshot: GraphSnapshot,\n written: readonly number[],\n relation: Column | null,\n fallback: string,\n note: NoteFn,\n): string[] {\n const out = new Array<string>(snapshot.edgeCount).fill(fallback);\n let assumed = 0;\n let renamed = 0;\n for (const e of written) {\n const value = relation === null ? undefined : cellOf(relation, e);\n if (typeof value !== \"string\") {\n assumed++;\n continue;\n }\n if (isOboWord(value)) {\n out[e] = value;\n } else {\n out[e] = wordOf(value);\n renamed++;\n }\n }\n if (assumed > 0) {\n note(\n OBO_LOSS.RELATION_ASSUMED,\n `${assumed} edge${plural(assumed)} ${agree(assumed, \"has\", \"have\")} no relation; written as ${fallback} (an ontology reads is_a as subclassing)`,\n relation?.meta.name ?? null,\n assumed,\n );\n }\n if (renamed > 0) {\n note(\n OBO_LOSS.RELATION_RENAMED,\n `${renamed} relation${plural(renamed)} ${agree(renamed, \"is\", \"are\")} not OBO ids; written with \"_\" in place of the space, \"!\", \"{\" or \"}\"`,\n relation?.meta.name ?? null,\n renamed,\n );\n }\n return out;\n}\n\n/**\n * The edge columns written as qualifiers: the vocabulary `qualifiers` column when its cells are\n * qualifier records, every other edge column (and the explicit weights) as `name=\"value\"` pairs,\n * each with its note.\n * @param snapshot - the snapshot\n * @param written - the written edges\n * @param relation - the relation column\n * @param weights - the explicit weights\n * @param note - records a note\n * @returns the qualifiers column and the other columns\n */\nfunction planEdgeColumns(\n snapshot: GraphSnapshot,\n written: readonly number[],\n relation: Column | null,\n weights: ExplicitWeights,\n note: NoteFn,\n): { qualifiers: Column | null; edgeColumns: QualifierColumn[] } {\n const qualifiers = qualifierRecords(snapshot, written);\n const edgeColumns: QualifierColumn[] = [];\n const count = (column: Column): number => written.filter((e) => column.isSet(e)).length;\n const merged = qualifiers === null ? \"\" : \" (merged with its values)\";\n for (const column of snapshot.edges) {\n const { role, name } = column.meta;\n if (\n column === relation ||\n column === qualifiers ||\n role === \"id\" ||\n (role !== null && UNWRITTEN_ROLES.has(role))\n ) {\n continue;\n }\n const written2 = isQualifierName(name) ? name : wordOf(name.replaceAll(/[=\",[\\]\\\\]/g, \"_\"));\n edgeColumns.push({ column, name: written2 });\n const n = count(column);\n if (n > 0) {\n note(\n OBO_LOSS.EDGE_COLUMN_AS_QUALIFIER,\n `edge column \"${name}\" is written as the qualifier ${written2} and reads back inside the qualifiers column${merged}`,\n name,\n n,\n );\n }\n }\n const explicit = weights.weighted ? written.filter((e) => weights.isExplicit(e)).length : 0;\n if (explicit > 0) {\n note(\n OBO_LOSS.EDGE_COLUMN_AS_QUALIFIER,\n `${explicit} explicit edge weight${plural(explicit)} ${agree(explicit, \"is\", \"are\")} written as the qualifier ${WEIGHT_QUALIFIER} and read back inside the qualifiers column, not as weights`,\n snapshot.edges.byRole(\"weight\")?.meta.name ?? null,\n explicit,\n );\n }\n return { qualifiers, edgeColumns };\n}\n\n/**\n * The vocabulary `qualifiers` edge column, when every written cell of it is a qualifier record.\n * @param snapshot - the snapshot\n * @param written - the written edges\n * @returns the column, or null when there is none or it holds something else\n */\nfunction qualifierRecords(snapshot: GraphSnapshot, written: readonly number[]): Column | null {\n const qualifiers = snapshot.edges.get(QUALIFIERS_COLUMN);\n if (qualifiers?.dtype !== \"json\" || qualifiers.meta.role !== null) {\n return null;\n }\n const records = written.every(\n (e) => !qualifiers.isSet(e) || isQualifierRecord(cellOf(qualifiers, e), isQualifierName),\n );\n return records ? qualifiers : null;\n}\n\n/**\n * The header lines: the kept header in the guide's order with the missing fields filled from the\n * metadata, and the graph columns as `property_value` lines.\n * @param snapshot - the snapshot\n * @param kept - the kept header\n * @param obo - the OBO options\n * @param obo.ontology - the ontology option, or null\n * @param rows - the written nodes\n * @param tags - the columns written as tags\n * @param note - records a note\n * @param stats - the line-end counter\n * @returns the lines\n */\nfunction planHeader(\n snapshot: GraphSnapshot,\n kept: Readonly<Record<string, readonly string[]>>,\n obo: { readonly ontology: string | null },\n rows: readonly number[],\n tags: ReadonlyMap<string, Column>,\n note: NoteFn,\n stats: FrameStats,\n): string[] {\n const { values, filled } = headerFields(snapshot, kept, obo.ontology, note);\n // a default namespace applies to every frame without one: keep it only when none lacks one\n const namespace = tags.get(\"namespace\");\n if (values.has(\"default-namespace\") && (namespace === undefined || rows.some((i) => !namespace.isSet(i)))) {\n values.delete(\"default-namespace\");\n }\n const lines: string[] = [];\n // the filled fields in the guide's order, then the kept ones as the file had them\n const tagsInOrder = [\n ...HEADER_ORDER.filter((t) => filled.has(t)),\n ...[...values.keys()].filter((t) => !filled.has(t)),\n ];\n for (const tag of tagsInOrder) {\n for (const value of values.get(tag) ?? []) {\n lines.push(`${escapeTag(tag)}: ${value}`);\n }\n }\n if (lines.length === 0 && rows.length === 0) {\n // a file of nothing reads back as an empty input: the version line makes it an empty ontology\n lines.push(\"format-version: 1.4\");\n }\n for (const column of snapshot.graph) {\n const relation = isOboWord(column.meta.name) ? column.meta.name : wordOf(column.meta.name);\n for (const line of propertyLines({ column, relation }, 0, stats)) {\n lines.push(`property_value: ${line}`);\n }\n }\n return lines;\n}\n\n/**\n * The header fields: the kept ones, and for a graph not read from OBO the fields its metadata has.\n * @param snapshot - the snapshot\n * @param kept - the kept header\n * @param ontologyOption - the ontology option, or null\n * @param note - records a note\n * @returns the values by tag, and the tags filled in (not kept)\n */\nfunction headerFields(\n snapshot: GraphSnapshot,\n kept: Readonly<Record<string, readonly string[]>>,\n ontologyOption: string | null,\n note: NoteFn,\n): { values: Map<string, string[]>; filled: Set<string> } {\n const { meta } = snapshot;\n const values = new Map<string, string[]>(Object.entries(kept).map(([tag, v]) => [tag, v.map(rawValue)]));\n const filled = new Set<string>();\n const fill = (tag: string, value: string | null): void => {\n if (value !== null && !values.has(tag)) {\n values.set(tag, [value]);\n filled.add(tag);\n }\n };\n // a file read from OBO keeps its own header; any other graph gets the fields its metadata has\n if (meta.sourceFormat !== \"obo\") {\n fill(\"format-version\", \"1.4\");\n fill(\"date\", oboDate(meta.created));\n fill(\"saved-by\", meta.creator === null ? null : escapeOboValue(meta.creator));\n }\n const ontology = ontologyField(ontologyOption, meta.name, values.has(\"ontology\"), note);\n if (ontology !== null) {\n if (!values.has(\"ontology\")) {\n filled.add(\"ontology\");\n }\n values.set(\"ontology\", [ontology]);\n }\n return { values, filled };\n}\n\n/**\n * The ontology header field to write: the ontology option, else the graph name when it is an\n * ontology id, else the name rewritten with \"_\" when the kept header has none.\n * @param option - the ontology option, or null\n * @param name - the graph name, or null\n * @param kept - whether the kept header has an ontology field\n * @param note - records a note\n * @returns the value to set, or null to leave the field as it is\n */\nfunction ontologyField(option: string | null, name: string | null, kept: boolean, note: NoteFn): string | null {\n if (option !== null) {\n return option;\n }\n if (name === null || name.length === 0 || kept) {\n return null;\n }\n if (/^[A-Za-z0-9_.\\-/]+$/.test(name)) {\n return name;\n }\n const slug = name.replaceAll(/[^A-Za-z0-9_.-]/g, \"_\");\n note(\n OBO_LOSS.ONTOLOGY_NAME,\n `the graph name ${JSON.stringify(name)} is not an ontology id; written as ${slug}`,\n null,\n null,\n );\n return slug;\n}\n\n/**\n * A kept raw value made safe for one line (a line break in metadata a caller built becomes `\\n`).\n * @param raw - the raw value\n * @returns the value to write\n */\nfunction rawValue(raw: string): string {\n return raw.replaceAll(/\\r\\n|\\r|\\n|\\f/g, String.raw`\\n`);\n}\n\n/**\n * A tag name escaped for the left of its colon.\n * @param tag - the tag\n * @returns the escaped tag\n */\nfunction escapeTag(tag: string): string {\n return escapeOboValue(tag).replaceAll(\":\", String.raw`\\:`);\n}\n\n/**\n * An ISO date (`yyyy-MM-ddTHH:mm...`) as the OBO header date `dd:MM:yyyy HH:mm`.\n * @param iso - the date, or null\n * @returns the header text, or null when the date is not of that form\n */\nfunction oboDate(iso: string | null): string | null {\n const m = iso === null ? null : /^(\\d{4})-(\\d{2})-(\\d{2})(?:T(\\d{2}):(\\d{2}))?/.exec(iso);\n if (m === null) {\n return null;\n }\n return `${m[3]}:${m[2]}:${m[1]} ${m[4] ?? \"00\"}:${m[5] ?? \"00\"}`;\n}\n\n/** What the frames after the nodes are planned from. */\ninterface TailInput {\n /** The kept Typedef frames and unknown frames. */\n readonly kept: {\n typedefs: Record<string, Record<string, string[]>>;\n unknownFrames: { type: string; clauses: Record<string, string[]> }[];\n };\n /** The written nodes. */\n readonly rows: readonly number[];\n /** The frame type of each node. */\n readonly kinds: readonly FrameKind[];\n /** The written id of each node. */\n readonly ids: readonly string[];\n /** The property-value columns. */\n readonly properties: readonly PropertyColumn[];\n /** The relation of each edge. */\n readonly relations: readonly string[];\n /** The written edges. */\n readonly edges: Iterable<number>;\n /** The xref column written as tags (a Typedef node's xrefs declare relations), or null. */\n readonly xref: Column | null;\n}\n\n/**\n * The frames after the nodes: the kept Typedefs (unless a node is that Typedef), a declaration of\n * every relation and property-value relation no Typedef declares, and the kept unknown frames.\n * @param input - what the frames are planned from\n * @returns the lines\n */\nfunction planTail(input: TailInput): string[] {\n const { kept, rows, properties, relations } = input;\n const lines: string[] = [];\n const declared = nodeTypedefs(input);\n keptTypedefLines(kept.typedefs, declared, lines);\n const declare = (relation: string, metadata: boolean): void => {\n if (declared.has(relation)) {\n return;\n }\n declared.add(relation);\n lines.push(\"\", \"[Typedef]\", `id: ${escapeOboWord(relation)}`, `name: ${escapeOboValue(relation)}`);\n if (metadata) {\n lines.push(\"is_metadata_tag: true\");\n }\n };\n const used = new Set<string>();\n for (const e of input.edges) {\n used.add(relations[e]);\n }\n for (const { column, relation } of properties) {\n if (rows.some((i) => column.isSet(i))) {\n declare(relation, true);\n }\n }\n for (const relation of used) {\n declare(relation, false);\n }\n for (const frame of kept.unknownFrames) {\n lines.push(\"\", `[${frame.type.replaceAll(/[\\]\\r\\n]/g, \"_\")}]`, ...clauseLines(frame.clauses));\n }\n return lines;\n}\n\n/**\n * The relations the built-in ones, the Typedef nodes and their xrefs declare.\n * @param input - what the frames are planned from\n * @returns the declared relation ids\n */\nfunction nodeTypedefs(input: TailInput): Set<string> {\n const { rows, kinds, ids, xref } = input;\n const declared = new Set<string>(BUILTIN_RELATIONS);\n for (const i of rows) {\n if (kinds[i] !== \"Typedef\") {\n continue;\n }\n declared.add(ids[i]);\n const xrefs = xref === null ? undefined : cellOf(xref, i);\n for (const x of Array.isArray(xrefs) ? xrefs : []) {\n declared.add(String(x));\n }\n }\n return declared;\n}\n\n/**\n * Write the kept Typedef frames no node already declares, and declare them and their xrefs.\n * @param typedefs - the kept Typedef frames by id\n * @param declared - the declared relations, added to\n * @param lines - the lines, appended to\n */\nfunction keptTypedefLines(\n typedefs: Record<string, Record<string, string[]>>,\n declared: Set<string>,\n lines: string[],\n): void {\n for (const [id, clauses] of Object.entries(typedefs)) {\n if (declared.has(id) && !BUILTIN_RELATIONS.has(id)) {\n continue;\n }\n declared.add(id);\n lines.push(\"\", \"[Typedef]\", `id: ${escapeOboWord(id)}`, ...clauseLines(clauses, \"id\"));\n for (const xref of clauses.xref ?? []) {\n declared.add(xref.trim());\n }\n }\n}\n\n/**\n * The clause lines of a kept frame, each value made safe for one line.\n * @param clauses - the values by tag\n * @param skip - a tag to leave out, or null\n * @returns the lines\n */\nfunction clauseLines(clauses: Record<string, string[]>, skip: string | null = null): string[] {\n return Object.entries(clauses)\n .filter(([tag]) => tag !== skip)\n .flatMap(([tag, values]) => values.map((value) => `${escapeTag(tag)}: ${rawValue(value)}`));\n}\n\n// ============================================================ the frames\n\n/** Hands out the `obo.qualifiers` entries of one frame to the clauses they belong to, in order. */\nclass QualifierCursor {\n private readonly entries: Record<string, { value: string; qualifiers: unknown }[]>;\n\n private readonly next = new Map<string, number>();\n\n /**\n * Create a cursor.\n * @param cell - the frame's `obo.qualifiers` cell, or undefined\n */\n constructor(cell: unknown) {\n this.entries = (cell ?? {}) as Record<string, { value: string; qualifiers: unknown }[]>;\n }\n\n /**\n * The qualifier block of a clause: the next entry of its tag when that entry is for this value.\n * @param tag - the tag (or `<tag>.xrefs` for an xref inside a list)\n * @param value - the clause's value as the column holds it\n * @returns the block with a leading space, or \"\"\n */\n block(tag: string, value: string): string {\n const list = Object.hasOwn(this.entries, tag) ? this.entries[tag] : undefined;\n const k = this.next.get(tag) ?? 0;\n if (list === undefined || k >= list.length || list[k].value !== value) {\n return \"\";\n }\n this.next.set(tag, k + 1);\n return qualifierBlock(qualifierPairs(list[k].qualifiers));\n }\n\n /**\n * Whether every entry found its clause.\n * @returns true when all were placed\n */\n placed(): boolean {\n return Object.entries(this.entries).every(([tag, list]) => (this.next.get(tag) ?? 0) === list.length);\n }\n}\n\n/** The per-frame writer state. */\ninterface FrameState {\n readonly p: Plan;\n readonly row: number;\n readonly cursor: QualifierCursor;\n /** The xrefs whose description was written already. */\n readonly described: Set<string>;\n readonly stats: FrameStats;\n}\n\n/**\n * Count a text that loses a line end, and return it.\n * @param s - the frame state's stats\n * @param text - the text\n * @returns the text\n */\nfunction counted(s: FrameStats, text: string): string {\n if (hasLineEnd(text)) {\n s.lineEnds++;\n }\n return text;\n}\n\n/**\n * One xref as written inside a list or after `xref:`: its id, its description the first time the\n * frame names it, and its own qualifiers.\n * @param f - the frame state\n * @param id - the xref id\n * @param listTag - the `<tag>.xrefs` key of its qualifiers, or null after `xref:`\n * @returns the text\n */\nfunction xrefText(f: FrameState, id: string, listTag: string | null): string {\n let out = escapeOboValue(counted(f.stats, id));\n const descriptions = f.p.tags.get(\"xref.descriptions\");\n const map =\n descriptions === undefined ? undefined : (cellOf(descriptions, f.row) as Record<string, string> | undefined);\n if (map !== undefined && Object.hasOwn(map, id) && !f.described.has(id)) {\n f.described.add(id);\n out += ` \"${escapeOboQuoted(counted(f.stats, map[id]))}\"`;\n }\n if (listTag !== null) {\n out += f.cursor.block(listTag, id);\n }\n return out;\n}\n\n/**\n * An xref list: `[A:1, B:2 \"description\"]`.\n * @param f - the frame state\n * @param ids - the xref ids\n * @param tag - the clause's tag\n * @returns the list\n */\nfunction xrefList(f: FrameState, ids: readonly string[], tag: string): string {\n const field = `${tag}.xrefs`;\n return `[${ids.map((id) => xrefText(f, id, field)).join(\", \")}]`;\n}\n\n/**\n * The `property_value` values of one cell of a property column: `relation \"value\" xsd:type` per\n * value (a list item each, JSON text for nested values).\n * @param prop - the column and its relation\n * @param row - the row\n * @param stats - the line-end counter\n * @returns the values after `property_value: `\n */\nfunction propertyLines(prop: PropertyColumn, row: number, stats: FrameStats): string[] {\n const { column, relation } = prop;\n const value = cellOf(column, row);\n if (value === undefined) {\n return [];\n }\n const head = escapeOboWord(relation);\n const one = (v: unknown, dtype: string): string => {\n let text: string;\n let xsd = XSD[dtype] ?? \"xsd:string\";\n if (typeof v === \"number\" && xsd === \"xsd:double\") {\n text = xsdDouble(v, dtype);\n } else if (typeof v === \"string\" || typeof v === \"boolean\" || typeof v === \"number\") {\n text = textOf(v, dtype);\n } else {\n text = JSON.stringify(v) ?? \"null\";\n xsd = \"xsd:string\";\n }\n return `${head} \"${escapeOboQuoted(counted(stats, text))}\" ${xsd}`;\n };\n if (column.dtype === \"list\") {\n return (value as readonly unknown[]).map((item) => one(item, column.child.dtype));\n }\n if (column.dtype === \"json\" || column.meta.components > 1) {\n return [one(value, \"json\")];\n }\n return [one(value, column.dtype)];\n}\n\n/**\n * A double as xsd:double writes it: INF, -INF and NaN for the non-finite values.\n * @param v - the value\n * @param dtype - the column dtype (f32 values use their shortest text)\n * @returns the text\n */\nfunction xsdDouble(v: number, dtype: string): string {\n if (Number.isNaN(v)) {\n return \"NaN\";\n }\n if (!Number.isFinite(v)) {\n return v > 0 ? \"INF\" : \"-INF\";\n }\n return formatNumber(v, dtype === \"f32\" ? \"f32\" : \"f64\");\n}\n\n/**\n * The qualifier block of one edge: the `qualifiers` record, then the other columns and the weight.\n * @param f - the frame state\n * @param e - the edge\n * @returns the block with a leading space, or \"\"\n */\nfunction edgeQualifiers(f: FrameState, e: number): string {\n const { p } = f;\n const pairs: [string, string][] = [];\n if (p.qualifiers !== null) {\n const record = cellOf(p.qualifiers, e);\n if (record !== undefined) {\n pairs.push(...qualifierPairs(record));\n }\n }\n for (const { column, name } of p.edgeColumns) {\n pairs.push(...qualifierTexts(column, e).map((text): [string, string] => [name, text]));\n }\n const weight = p.weights.text(e);\n if (weight !== null) {\n pairs.push([WEIGHT_QUALIFIER, weight]);\n }\n for (const [, value] of pairs) {\n counted(f.stats, value);\n }\n return qualifierBlock(pairs);\n}\n\n/**\n * The qualifier values an edge column gives one edge: one per item of a list, none when unset.\n * @param column - the edge column\n * @param e - the edge\n * @returns the value texts\n */\nfunction qualifierTexts(column: Column, e: number): string[] {\n const value = cellOf(column, e);\n if (value === undefined) {\n return [];\n }\n if (column.dtype === \"list\") {\n return (value as readonly unknown[]).map((item) => textOf(item, column.child.dtype));\n }\n return [column.dtype === \"json\" ? (JSON.stringify(value) ?? \"null\") : textOf(value, column.dtype)];\n}\n\n/**\n * The clauses of one tag column on a frame.\n * @param f - the frame state\n * @param tag - the tag\n * @param column - the column\n * @param out - the lines\n */\nfunction tagLines(f: FrameState, tag: string, column: Column, out: string[]): void {\n const value = cellOf(column, f.row);\n if (value === undefined) {\n return;\n }\n const { cursor, stats } = f;\n const push = (text: string, stored: string, raw = false): void => {\n out.push(`${tag}: ${raw ? text : escapeOboValue(counted(stats, text))}${cursor.block(tag, stored)}`);\n };\n if (TEXT_TAGS.has(tag)) {\n push(value as string, value as string);\n return;\n }\n if (BOOL_TAGS.has(tag)) {\n push(value ? \"true\" : \"false\", value ? \"true\" : \"false\", true);\n return;\n }\n if (ID_LIST_TAGS.has(tag)) {\n for (const id of value as string[]) {\n push(escapeOboWord(id), id, true);\n }\n return;\n }\n // def.xrefs, xref.descriptions and obo.qualifiers are written with the clauses they belong to\n if (Object.hasOwn(STRUCTURED_TAGS, tag)) {\n STRUCTURED_TAGS[tag](f, tag, value, out);\n }\n}\n\n/** Writes the clauses of a structured tag column's cell. */\ntype StructuredLines = (f: FrameState, tag: string, value: unknown, out: string[]) => void;\n\n/**\n * The qualifier block of a structured value.\n * @param qualifiers - the value's qualifiers, or undefined\n * @returns the block with a leading space, or \"\"\n */\nfunction blockOf(qualifiers: unknown): string {\n return qualifiers === undefined ? \"\" : qualifierBlock(qualifierPairs(qualifiers));\n}\n\n/** The writers of the tags whose cells hold more than a text, an id list or a boolean. */\nconst STRUCTURED_TAGS: Readonly<Record<string, StructuredLines>> = {\n def(f, _tag, value, out) {\n const xrefs = f.p.tags.get(\"def.xrefs\");\n const ids = (xrefs === undefined ? [] : (cellOf(xrefs, f.row) ?? [])) as string[];\n const text = value as string;\n out.push(\n `def: \"${escapeOboQuoted(counted(f.stats, text))}\" ${xrefList(f, ids, \"def\")}${f.cursor.block(\"def\", text)}`,\n );\n },\n xref(f, _tag, value, out) {\n for (const id of value as string[]) {\n out.push(`xref: ${xrefText(f, id, null)}${f.cursor.block(\"xref\", id)}`);\n }\n },\n synonym(f, _tag, value, out) {\n for (const s of value as {\n text: string;\n scope: string;\n type: string | null;\n xrefs: string[];\n qualifiers?: unknown;\n }[]) {\n const type = s.type === null ? \"\" : ` ${escapeOboWord(s.type)}`;\n out.push(\n `synonym: \"${escapeOboQuoted(counted(f.stats, s.text))}\" ${s.scope}${type} ${xrefList(f, s.xrefs, \"synonym\")}${blockOf(s.qualifiers)}`,\n );\n }\n },\n intersection_of(_f, _tag, value, out) {\n for (const x of value as { relation: string | null; target: string; qualifiers?: unknown }[]) {\n const relation = x.relation === null ? \"\" : `${escapeOboWord(x.relation)} `;\n out.push(`intersection_of: ${relation}${escapeOboWord(x.target)}${blockOf(x.qualifiers)}`);\n }\n },\n property_value(f, _tag, value, out) {\n for (const x of value as { relation: string; value: string; datatype: string | null; qualifiers?: unknown }[]) {\n const datatype = x.datatype === null ? \"\" : ` ${escapeOboWord(x.datatype)}`;\n const literal =\n x.datatype === null && isOboWord(x.value)\n ? escapeOboWord(x.value)\n : `\"${escapeOboQuoted(counted(f.stats, x.value))}\"${datatype}`;\n out.push(`property_value: ${escapeOboWord(x.relation)} ${literal}${blockOf(x.qualifiers)}`);\n }\n },\n holds_over_chain: chainLines,\n equivalent_to_chain: chainLines,\n expand_assertion_to: expansionLines,\n expand_expression_to: expansionLines,\n [UNRECOGNIZED](f, _tag, value, out) {\n for (const [unknown, values] of Object.entries(value as Record<string, string[]>)) {\n for (const v of values) {\n out.push(`${escapeTag(unknown)}: ${escapeOboValue(counted(f.stats, v))}`);\n }\n }\n },\n};\n\n/**\n * The clauses of a relation chain tag (`holds_over_chain`, `equivalent_to_chain`).\n * @param f - the frame state\n * @param tag - the tag\n * @param value - the cell: pairs of relations\n * @param out - the lines\n */\nfunction chainLines(f: FrameState, tag: string, value: unknown, out: string[]): void {\n for (const [a, b] of value as [string, string][]) {\n const pair = `${a} ${b}`;\n out.push(`${tag}: ${escapeOboWord(a)} ${escapeOboWord(b)}${f.cursor.block(tag, pair)}`);\n }\n}\n\n/**\n * The clauses of a macro expansion tag (`expand_assertion_to`, `expand_expression_to`).\n * @param f - the frame state\n * @param tag - the tag\n * @param value - the cell: templates with their xrefs\n * @param out - the lines\n */\nfunction expansionLines(f: FrameState, tag: string, value: unknown, out: string[]): void {\n for (const x of value as { template: string; xrefs: string[]; qualifiers?: unknown }[]) {\n out.push(\n `${tag}: \"${escapeOboQuoted(counted(f.stats, x.template))}\" ${xrefList(f, x.xrefs, tag)}${blockOf(x.qualifiers)}`,\n );\n }\n}\n\n/**\n * The lines of one node's frame.\n * @param p - the plan\n * @param row - the node\n * @param stats - the counters\n * @returns the lines, the frame header first\n */\nfunction frameLines(p: Plan, row: number, stats: FrameStats): string[] {\n const qualifiersColumn = p.tags.get(\"obo.qualifiers\");\n const f: FrameState = {\n p,\n row,\n cursor: new QualifierCursor(qualifiersColumn === undefined ? undefined : cellOf(qualifiersColumn, row)),\n described: new Set(),\n stats,\n };\n const out = [`[${p.kinds[row]}]`, `id: ${escapeOboWord(p.ids[row])}`];\n for (const tag of TAG_ORDER) {\n if (tag === \"name\") {\n nameLine(f, out);\n } else if (tag === \"property_value\") {\n propertyValueLines(f, out);\n } else if (tag === EDGES) {\n edgeLines(f, out);\n } else {\n const column = p.tags.get(tag);\n if (column !== undefined) {\n tagLines(f, tag, column, out);\n }\n }\n }\n stats.qualifiersPlaced &&= f.cursor.placed();\n return out;\n}\n\n/**\n * The name clause of a frame, from the label column.\n * @param f - the frame state\n * @param out - the lines\n */\nfunction nameLine(f: FrameState, out: string[]): void {\n const name = f.p.label === null ? undefined : cellOf(f.p.label, f.row);\n if (typeof name === \"string\") {\n out.push(`name: ${escapeOboValue(counted(f.stats, name))}${f.cursor.block(\"name\", name)}`);\n }\n}\n\n/**\n * The property_value clauses of a frame: the original id of a rewritten one, the property_value\n * column, then the property-value columns.\n * @param f - the frame state\n * @param out - the lines\n */\nfunction propertyValueLines(f: FrameState, out: string[]): void {\n const { p, row } = f;\n const original = p.originals.get(row);\n if (original !== undefined) {\n // as JSON text, so a carriage return in the original survives\n out.push(`property_value: ${ORIGINAL_ID} \"${escapeOboQuoted(JSON.stringify(original))}\" xsd:string`);\n }\n const column = p.tags.get(\"property_value\");\n if (column !== undefined) {\n tagLines(f, \"property_value\", column, out);\n }\n for (const prop of p.properties) {\n for (const line of propertyLines(prop, row, f.stats)) {\n out.push(`property_value: ${line}`);\n }\n }\n}\n\n/**\n * The edge clauses of a frame: `is_a` (and `instance_of` on an Instance) as their own tags, any\n * other relation as a `relationship` clause.\n * @param f - the frame state\n * @param out - the lines\n */\nfunction edgeLines(f: FrameState, out: string[]): void {\n const { p, row } = f;\n for (let k = p.edgeStart[row]; k < p.edgeStart[row + 1]; k++) {\n const e = p.edgeOrder[k];\n const target = escapeOboWord(p.ids[p.dst[e]]);\n const relation = p.relations[e];\n const block = edgeQualifiers(f, e);\n if (relation === \"is_a\" || (relation === \"instance_of\" && p.kinds[row] === \"Instance\")) {\n out.push(`${relation}: ${target}${block}`);\n } else {\n out.push(`relationship: ${escapeOboWord(relation)} ${target}${block}`);\n }\n }\n}\n\n/**\n * Write every frame once without keeping the text: count the clauses that repeat another of their\n * frame (the importer reads them as one), the line ends and whether the qualifiers were placed.\n * @param p - the plan\n * @param rows - the written nodes\n * @returns the counts\n */\nfunction simulate(p: Plan, rows: readonly number[]): FrameStats & { duplicates: number } {\n const stats = { lineEnds: 0, qualifiersPlaced: true, duplicates: 0 };\n for (const i of rows) {\n const lines = frameLines(p, i, stats);\n const seen = new Set<string>();\n for (let k = 2; k < lines.length; k++) {\n if (seen.has(lines[k])) {\n stats.duplicates++;\n }\n seen.add(lines[k]);\n }\n }\n return stats;\n}\n\n/**\n * The text parts of the file: the header, one frame per written node, the tail frames.\n * @param p - the plan\n * @yields the header and one part per frame\n * @returns nothing\n */\nfunction* write(p: Plan): Generator<string, void, undefined> {\n if (p.fatal !== null) {\n throw p.fatal;\n }\n yield p.header.map((line) => `${line}\\n`).join(\"\");\n const stats: FrameStats = { lineEnds: 0, qualifiersPlaced: true };\n for (let i = 0; i < p.ids.length; i++) {\n if (p.frameless[i] === 0) {\n yield `\\n${frameLines(p, i, stats).join(\"\\n\")}\\n`;\n }\n }\n if (p.tail.length > 0) {\n yield `${p.tail.join(\"\\n\")}\\n`;\n }\n}\n\n/**\n * The text parts of an export, planned when the first part is asked for, so a refused option\n * rejects the export instead of throwing from the call.\n * @param snapshot - the snapshot\n * @param options - format-specific and common options\n * @yields the parts\n * @returns nothing\n */\nfunction* written(\n snapshot: GraphSnapshot,\n options: (OboExportOptions & CommonExportOptions) | undefined,\n): Generator<string, void, undefined> {\n yield* write(plan(snapshot, options));\n}\n\n/**\n * The OBO exporter plugin.\n * @category Built-in formats\n */\nexport const oboExporter: GraphExporter<OboExportOptions> = Object.freeze({\n format: \"obo\",\n options: Object.freeze([\"ontology\", \"relation\"]),\n capabilities: OBO_CAPABILITIES,\n\n /**\n * Pre-flight: what export() would lose, without writing anything.\n * @param snapshot - the snapshot\n * @param options - format-specific and common options\n * @returns the notes, empty when the export is exact\n */\n check(snapshot: GraphSnapshot, options?: OboExportOptions & CommonExportOptions): readonly LossNote[] {\n return Object.freeze([...plan(snapshot, options).notes]);\n },\n\n /**\n * Write the file as UTF-8 chunks.\n * @param snapshot - the snapshot\n * @param options - format-specific and common options\n * @returns the chunks\n */\n export(snapshot: GraphSnapshot, options?: OboExportOptions & CommonExportOptions): AsyncIterable<Uint8Array> {\n return encodeChunks(written(snapshot, options));\n },\n\n /**\n * Write the file as one string.\n * @param snapshot - the snapshot\n * @param options - format-specific and common options\n * @returns the file\n */\n exportToString(snapshot: GraphSnapshot, options?: OboExportOptions & CommonExportOptions): Promise<string> {\n return joinText(written(snapshot, options));\n },\n});\n"],"names":["end","ORIGINAL_ID","BUILTIN_RELATIONS","resolveOboOptions","oboDate","plan","tagLines","written","FRAME_KINDS","written2"],"mappings":"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"}