@graphty/graph-io 0.3.19 → 0.3.21

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 (201) hide show
  1. package/README.md +49 -4
  2. package/dist/chunks/{escape-CWExcecC.js → escape-B-tkk_Cl.js} +74 -16
  3. package/dist/chunks/escape-B-tkk_Cl.js.map +1 -0
  4. package/dist/chunks/{writer-DQiKgQJc.js → export-Bh60Dv-n.js} +5 -79
  5. package/dist/chunks/export-Bh60Dv-n.js.map +1 -0
  6. package/dist/chunks/{exporter-CbMZyVt-.js → exporter-BGrsWamJ.js} +7 -6
  7. package/dist/chunks/{exporter-CbMZyVt-.js.map → exporter-BGrsWamJ.js.map} +1 -1
  8. package/dist/chunks/exporter-DIeGJXAZ.js +834 -0
  9. package/dist/chunks/exporter-DIeGJXAZ.js.map +1 -0
  10. package/dist/chunks/{importer-BNFuV1-K.js → importer-BWY2FFc5.js} +28 -7
  11. package/dist/chunks/importer-BWY2FFc5.js.map +1 -0
  12. package/dist/chunks/importer-DD-xv9_Y.js +1471 -0
  13. package/dist/chunks/importer-DD-xv9_Y.js.map +1 -0
  14. package/dist/chunks/{importer-BAP4PrxR.js → importer-DET1tg6s.js} +30 -20
  15. package/dist/chunks/importer-DET1tg6s.js.map +1 -0
  16. package/dist/chunks/{importer-ByPGO-09.js → importer-DEcKhsmQ.js} +2 -2
  17. package/dist/chunks/{importer-ByPGO-09.js.map → importer-DEcKhsmQ.js.map} +1 -1
  18. package/dist/chunks/{importer-BW-Ft2ps.js → importer-DIrbbnAf.js} +6 -5
  19. package/dist/chunks/{importer-BW-Ft2ps.js.map → importer-DIrbbnAf.js.map} +1 -1
  20. package/dist/chunks/importer-D_e7e7LX.js +3055 -0
  21. package/dist/chunks/importer-D_e7e7LX.js.map +1 -0
  22. package/dist/chunks/{importer-Bm1_5vPS.js → importer-eUREhBGj.js} +11 -8
  23. package/dist/chunks/importer-eUREhBGj.js.map +1 -0
  24. package/dist/chunks/{importer-DOepkgnG.js → importer-vi3bSdtw.js} +4 -4
  25. package/dist/chunks/{importer-DOepkgnG.js.map → importer-vi3bSdtw.js.map} +1 -1
  26. package/dist/chunks/{importer-BVGtU1NA.js → importer-zGLo8Dg_.js} +6 -5
  27. package/dist/chunks/{importer-BVGtU1NA.js.map → importer-zGLo8Dg_.js.map} +1 -1
  28. package/dist/chunks/{json-elements-CZY1wiZh.js → json-elements-DDS8N2Dd.js} +2 -2
  29. package/dist/chunks/{json-elements-CZY1wiZh.js.map → json-elements-DDS8N2Dd.js.map} +1 -1
  30. package/dist/chunks/{records-BzNicMsf.js → records-dbRkxwaq.js} +2 -2
  31. package/dist/chunks/{records-BzNicMsf.js.map → records-dbRkxwaq.js.map} +1 -1
  32. package/dist/chunks/{report-BcWboivV.js → report-B1z4WT9e.js} +143 -111
  33. package/dist/chunks/{report-BcWboivV.js.map → report-B1z4WT9e.js.map} +1 -1
  34. package/dist/chunks/{weights-CwISIpCP.js → weights-Dzba96G3.js} +5 -5
  35. package/dist/chunks/{weights-CwISIpCP.js.map → weights-Dzba96G3.js.map} +1 -1
  36. package/dist/chunks/writer-C7flM-Ih.js +77 -0
  37. package/dist/chunks/writer-C7flM-Ih.js.map +1 -0
  38. package/dist/csv.js +6 -5
  39. package/dist/csv.js.map +1 -1
  40. package/dist/cx.js +1 -1
  41. package/dist/cx2.js +2 -2
  42. package/dist/cys.d.ts +1 -0
  43. package/dist/cys.js +6 -0
  44. package/dist/cys.js.map +1 -0
  45. package/dist/dot.js +1 -1
  46. package/dist/gexf.js +5 -4
  47. package/dist/gexf.js.map +1 -1
  48. package/dist/gml.js +12 -14
  49. package/dist/gml.js.map +1 -1
  50. package/dist/graph-io.js +288 -141
  51. package/dist/graph-io.js.map +1 -1
  52. package/dist/graphml.js +1 -1
  53. package/dist/json.js +1 -1
  54. package/dist/neo4j.js +6 -5
  55. package/dist/neo4j.js.map +1 -1
  56. package/dist/obo.js +1 -1
  57. package/dist/pajek.js +1 -1
  58. package/dist/src/common/cell-budget.d.ts +84 -0
  59. package/dist/src/common/cell-budget.d.ts.map +1 -0
  60. package/dist/src/common/cell-budget.js +138 -0
  61. package/dist/src/common/cell-budget.js.map +1 -0
  62. package/dist/src/common/input.d.ts +10 -0
  63. package/dist/src/common/input.d.ts.map +1 -1
  64. package/dist/src/common/input.js +39 -0
  65. package/dist/src/common/input.js.map +1 -1
  66. package/dist/src/common/options.d.ts +6 -0
  67. package/dist/src/common/options.d.ts.map +1 -1
  68. package/dist/src/common/options.js +1 -1
  69. package/dist/src/common/options.js.map +1 -1
  70. package/dist/src/common/xml.d.ts +37 -3
  71. package/dist/src/common/xml.d.ts.map +1 -1
  72. package/dist/src/common/xml.js +86 -6
  73. package/dist/src/common/xml.js.map +1 -1
  74. package/dist/src/common/zip.d.ts +92 -0
  75. package/dist/src/common/zip.d.ts.map +1 -0
  76. package/dist/src/common/zip.js +399 -0
  77. package/dist/src/common/zip.js.map +1 -0
  78. package/dist/src/formats/cx/importer.d.ts.map +1 -1
  79. package/dist/src/formats/cx/importer.js +26 -17
  80. package/dist/src/formats/cx/importer.js.map +1 -1
  81. package/dist/src/formats/cys/constants.d.ts +68 -0
  82. package/dist/src/formats/cys/constants.d.ts.map +1 -0
  83. package/dist/src/formats/cys/constants.js +76 -0
  84. package/dist/src/formats/cys/constants.js.map +1 -0
  85. package/dist/src/formats/cys/importer.d.ts +38 -0
  86. package/dist/src/formats/cys/importer.d.ts.map +1 -0
  87. package/dist/src/formats/cys/importer.js +830 -0
  88. package/dist/src/formats/cys/importer.js.map +1 -0
  89. package/dist/src/formats/cys/index.d.ts +7 -0
  90. package/dist/src/formats/cys/index.d.ts.map +1 -0
  91. package/dist/src/formats/cys/index.js +7 -0
  92. package/dist/src/formats/cys/index.js.map +1 -0
  93. package/dist/src/formats/cys/session.d.ts +132 -0
  94. package/dist/src/formats/cys/session.d.ts.map +1 -0
  95. package/dist/src/formats/cys/session.js +315 -0
  96. package/dist/src/formats/cys/session.js.map +1 -0
  97. package/dist/src/formats/cys/tables.d.ts +90 -0
  98. package/dist/src/formats/cys/tables.d.ts.map +1 -0
  99. package/dist/src/formats/cys/tables.js +293 -0
  100. package/dist/src/formats/cys/tables.js.map +1 -0
  101. package/dist/src/formats/dot/exporter.d.ts +2 -0
  102. package/dist/src/formats/dot/exporter.d.ts.map +1 -1
  103. package/dist/src/formats/dot/exporter.js +12 -0
  104. package/dist/src/formats/dot/exporter.js.map +1 -1
  105. package/dist/src/formats/dot/importer.js +6 -2
  106. package/dist/src/formats/dot/importer.js.map +1 -1
  107. package/dist/src/formats/gexf/importer.d.ts +2 -2
  108. package/dist/src/formats/gexf/importer.d.ts.map +1 -1
  109. package/dist/src/formats/gexf/importer.js +1 -1
  110. package/dist/src/formats/gexf/importer.js.map +1 -1
  111. package/dist/src/formats/gml/exporter.d.ts +0 -8
  112. package/dist/src/formats/gml/exporter.d.ts.map +1 -1
  113. package/dist/src/formats/gml/exporter.js +7 -17
  114. package/dist/src/formats/gml/exporter.js.map +1 -1
  115. package/dist/src/formats/json/exporter.d.ts.map +1 -1
  116. package/dist/src/formats/json/exporter.js +3 -1
  117. package/dist/src/formats/json/exporter.js.map +1 -1
  118. package/dist/src/formats/json/importer.d.ts.map +1 -1
  119. package/dist/src/formats/json/importer.js +3 -2
  120. package/dist/src/formats/json/importer.js.map +1 -1
  121. package/dist/src/formats/xgmml/columns.d.ts +152 -0
  122. package/dist/src/formats/xgmml/columns.d.ts.map +1 -0
  123. package/dist/src/formats/xgmml/columns.js +593 -0
  124. package/dist/src/formats/xgmml/columns.js.map +1 -0
  125. package/dist/src/formats/xgmml/constants.d.ts +196 -0
  126. package/dist/src/formats/xgmml/constants.d.ts.map +1 -0
  127. package/dist/src/formats/xgmml/constants.js +197 -0
  128. package/dist/src/formats/xgmml/constants.js.map +1 -0
  129. package/dist/src/formats/xgmml/document.d.ts +361 -0
  130. package/dist/src/formats/xgmml/document.d.ts.map +1 -0
  131. package/dist/src/formats/xgmml/document.js +695 -0
  132. package/dist/src/formats/xgmml/document.js.map +1 -0
  133. package/dist/src/formats/xgmml/emit.d.ts +341 -0
  134. package/dist/src/formats/xgmml/emit.d.ts.map +1 -0
  135. package/dist/src/formats/xgmml/emit.js +1275 -0
  136. package/dist/src/formats/xgmml/emit.js.map +1 -0
  137. package/dist/src/formats/xgmml/exporter.d.ts +24 -0
  138. package/dist/src/formats/xgmml/exporter.d.ts.map +1 -0
  139. package/dist/src/formats/xgmml/exporter.js +999 -0
  140. package/dist/src/formats/xgmml/exporter.js.map +1 -0
  141. package/dist/src/formats/xgmml/importer.d.ts +58 -0
  142. package/dist/src/formats/xgmml/importer.d.ts.map +1 -0
  143. package/dist/src/formats/xgmml/importer.js +360 -0
  144. package/dist/src/formats/xgmml/importer.js.map +1 -0
  145. package/dist/src/formats/xgmml/index.d.ts +8 -0
  146. package/dist/src/formats/xgmml/index.d.ts.map +1 -0
  147. package/dist/src/formats/xgmml/index.js +8 -0
  148. package/dist/src/formats/xgmml/index.js.map +1 -0
  149. package/dist/src/formats/xgmml/values.d.ts +60 -0
  150. package/dist/src/formats/xgmml/values.d.ts.map +1 -0
  151. package/dist/src/formats/xgmml/values.js +148 -0
  152. package/dist/src/formats/xgmml/values.js.map +1 -0
  153. package/dist/src/index.d.ts +2 -0
  154. package/dist/src/index.d.ts.map +1 -1
  155. package/dist/src/index.js +2 -0
  156. package/dist/src/index.js.map +1 -1
  157. package/dist/src/registry.d.ts +7 -0
  158. package/dist/src/registry.d.ts.map +1 -1
  159. package/dist/src/registry.js +25 -10
  160. package/dist/src/registry.js.map +1 -1
  161. package/dist/src/sniff.d.ts +1 -1
  162. package/dist/src/sniff.d.ts.map +1 -1
  163. package/dist/src/sniff.js +2 -0
  164. package/dist/src/sniff.js.map +1 -1
  165. package/dist/xgmml.d.ts +1 -0
  166. package/dist/xgmml.js +9 -0
  167. package/dist/xgmml.js.map +1 -0
  168. package/package.json +15 -2
  169. package/src/common/cell-budget.ts +170 -0
  170. package/src/common/input.ts +40 -0
  171. package/src/common/options.ts +1 -1
  172. package/src/common/xml.ts +127 -6
  173. package/src/common/zip.ts +472 -0
  174. package/src/formats/cx/importer.ts +27 -19
  175. package/src/formats/cys/constants.ts +99 -0
  176. package/src/formats/cys/importer.ts +1100 -0
  177. package/src/formats/cys/index.ts +7 -0
  178. package/src/formats/cys/session.ts +428 -0
  179. package/src/formats/cys/tables.ts +400 -0
  180. package/src/formats/dot/exporter.ts +17 -0
  181. package/src/formats/dot/importer.ts +6 -2
  182. package/src/formats/gexf/importer.ts +0 -1
  183. package/src/formats/gml/exporter.ts +7 -18
  184. package/src/formats/json/exporter.ts +3 -1
  185. package/src/formats/json/importer.ts +3 -2
  186. package/src/formats/xgmml/columns.ts +747 -0
  187. package/src/formats/xgmml/constants.ts +265 -0
  188. package/src/formats/xgmml/document.ts +975 -0
  189. package/src/formats/xgmml/emit.ts +1563 -0
  190. package/src/formats/xgmml/exporter.ts +1215 -0
  191. package/src/formats/xgmml/importer.ts +491 -0
  192. package/src/formats/xgmml/index.ts +8 -0
  193. package/src/formats/xgmml/values.ts +183 -0
  194. package/src/index.ts +9 -0
  195. package/src/registry.ts +41 -15
  196. package/src/sniff.ts +5 -1
  197. package/dist/chunks/escape-CWExcecC.js.map +0 -1
  198. package/dist/chunks/importer-BAP4PrxR.js.map +0 -1
  199. package/dist/chunks/importer-BNFuV1-K.js.map +0 -1
  200. package/dist/chunks/importer-Bm1_5vPS.js.map +0 -1
  201. package/dist/chunks/writer-DQiKgQJc.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"importer-ByPGO-09.js","sources":["../../src/formats/obo/syntax.ts","../../src/formats/obo/importer.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 */\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 * 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 */\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 */\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 */\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/** The qualifiers of a clause: name to value (a list when a name repeats). */\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.\n * @param value - the raw value without its comment\n * @returns the value and its qualifiers\n */\nexport function splitQualifiers(value: string): QualifiedValue {\n let rest = value;\n let qualifiers: Qualifiers | null = null;\n for (;;) {\n if (!rest.endsWith(\"}\") || isEscaped(rest, rest.length - 1)) {\n return { value: rest, qualifiers, badBlock: null };\n }\n const open = openingBrace(rest);\n const parsed = open < 0 ? null : parseQualifiers(rest.slice(open + 1, -1));\n if (parsed === null) {\n return { value: rest, qualifiers, badBlock: open < 0 ? rest : rest.slice(open) };\n }\n // a block read right to left: an earlier block's names come first\n qualifiers = qualifiers === null ? parsed : mergeQualifiers(parsed, qualifiers);\n rest = rest.slice(0, open).trimEnd();\n }\n}\n\n/**\n * The index of the unescaped `{` outside quotes that opens the block closing the value.\n * @param value - a raw value ending with `}`\n * @returns the index, or -1 when there is none\n */\nfunction openingBrace(value: string): number {\n let quoted = false;\n let open = -1;\n for (let i = 0; i < value.length - 1; 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 open = -1;\n }\n }\n return quoted ? -1 : open;\n}\n\n/**\n * Merge two qualifier records, a repeated name becoming a list.\n * @param first - the earlier record\n * @param second - the later record\n * @returns the merged record\n */\nfunction mergeQualifiers(first: Qualifiers, second: Qualifiers): Qualifiers {\n const out: Qualifiers = { ...first };\n for (const [name, value] of Object.entries(second)) {\n addQualifier(out, name, value);\n }\n return out;\n}\n\n/**\n * Add one qualifier, turning a repeated name into a list.\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 if (!Object.prototype.hasOwnProperty.call(record, name)) {\n record[name] = value;\n return;\n }\n const before = record[name];\n record[name] = [...(Array.isArray(before) ? before : [before]), ...(Array.isArray(value) ? value : [value])];\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 */\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/** One token of a value. */\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 */\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/** One cross-reference: `ID \"description\" {qualifiers}`. */\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}\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 */\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 if (quote >= 0) {\n const end = closingQuote(value, quote + 1);\n description = unescapeObo(value.slice(quote + 1, end < 0 ? value.length : end));\n }\n return { id, description, qualifiers };\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 */\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 */\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 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 EMPTY_INPUT_CODE,\n ENCODING_FALLBACK_CODE,\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 { 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 splitQualifiers,\n splitTagValue,\n stripComment,\n type Token,\n tokenize,\n unescapeObo,\n type Xref,\n} from \"./syntax.js\";\n\n/** The format-specific options of the OBO importer. */\nexport interface OboImportOptions {\n /** \"keep\" (default): obsolete terms are nodes with `is_obsolete` true; \"drop\": they and their edges are left out. */\n obsolete?: \"keep\" | \"drop\" | undefined;\n /** \"metadata\" (default): `[Typedef]` frames go to `meta.extra.obo.typedefs`; \"nodes\": they are nodes too, with their `is_a` edges. */\n typedefs?: \"metadata\" | \"nodes\" | undefined;\n}\n\n/** Issue codes of the OBO importer (design section 4.3). */\nexport const OBO_ISSUE = Object.freeze({\n /** The input is empty or whitespace (fatal). */\n EMPTY_INPUT: EMPTY_INPUT_CODE,\n /** The input holds invalid UTF-8 (fatal). */\n INVALID_UTF8: INVALID_UTF8_CODE,\n /** Invalid bytes in the encoding a BOM or the encoding option chose (fatal). */\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 with one id were merged (spec 4.1.1). */\n DUPLICATE_NODE: DUPLICATE_NODE_CODE,\n /** A single-valued tag given twice for one id (a cardinality violation); the first 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 /** 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 /** Fewer than two `intersection_of` or `union_of` clauses on a frame. */\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 /** A header clause kept in `meta.extra.obo.header` whose meaning is not applied (import, id-mapping, the treat-xrefs macros, owl-axioms). */\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 /** Two distinct id texts became one number under ids \"number\". */\n ID_MERGED: ID_MERGED_CODE,\n /** A vocabulary column renamed `<name>#obo` because the sink already holds the name. */\n COLUMN_RENAMED: RENAMED_CODE,\n /** A vocabulary column declared without its role because the sink already holds it. */\n ROLE_TAKEN: ROLE_TAKEN_CODE,\n /** A common option the format has no use for (defaultDirected, weightFrom, nodeIdFrom, ...). */\n OPTION_IGNORED: OPTION_IGNORED_CODE,\n /** A builder-policy option the caller passed that the caller's sink does not use. */\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]);\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/** The 1.0 / 1.2 frame tags read as their 1.4 meaning: tag to [1.4 tag, synonym scope]. */\nconst 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/** Single-valued text tags (first value kept). */\nconst 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/** Single-valued boolean tags. */\nconst BOOL_TAGS: ReadonlySet<string> = new Set(\n Object.keys(OBO_NODE_COLUMNS).filter((name) => OBO_NODE_COLUMNS[name].dtype === \"bool\"),\n);\n\n/** Tags whose value is one id, collected in a list column. */\nconst 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/** Tags that only a Typedef frame may carry (elsewhere they are unrecognized). */\nconst 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\";\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[]> = {};\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 */\n constructor(report: ImportReportBuilder, signal: AbortSignal | null) {\n this.report = report;\n this.signal = signal;\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 const header = /^\\[([^\\]]*)\\]\\s*(?:!.*)?$/.exec(t);\n if (header !== null) {\n this.startFrame(header[1].trim(), 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) {\n this.tally(\"parse-error\", OBO_ISSUE.SYNTAX, \"a line without a colon was skipped\", \"line\", line);\n return;\n }\n const clause: Clause = { tag: tv.tag, value: stripComment(tv.rest), line };\n if (this.frame === null) {\n this.headerClause(clause);\n } else {\n this.frame.clauses.push(clause);\n }\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 */\n private startFrame(name: string, line: number): void {\n this.finishFrame();\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 (this.header[clause.tag] ??= []).push(clause.value);\n const { tag } = clause;\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\" && 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: Record<string, string[]> = {};\n for (const clause of frame.clauses) {\n (clauses[clause.tag] ??= []).push(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 id = idAt < 0 ? \"\" : unescapeObo(splitQualifiers(frame.clauses[idAt].value).value).trim();\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 this.report.counts.skippedNodes++;\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 record = this.recordFor(frame.kind, id, frame.line);\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(record, clause);\n }\n if (record.kind === \"Typedef\") {\n record.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.report.warning(\n \"merged\",\n OBO_ISSUE.DUPLICATE_NODE,\n `two [${kind}] frames have the id ${id}; they are merged (spec 4.1.1)`,\n {\n line,\n element: id,\n },\n );\n }\n return existing;\n }\n const record: NodeRecord = {\n id,\n kind,\n line,\n values: new Map(),\n lists: new Map(),\n edges: [],\n seen: new Set(),\n raw: {},\n };\n map.set(id, record);\n return record;\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 const split = splitQualifiers(clause.value);\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 (record.raw[clause.tag] ??= []).push(clause.value);\n }\n const { tag, scope, qualifiers, value } = this.clauseParts(clause);\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.single(record, tag, unescapeObo(value).trim(), clause.line);\n this.extraQualifiers(record, tag, unescapeObo(value).trim(), qualifiers);\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]);\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 * 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 const xrefs = parseXrefList(list.text);\n this.describe(record, xrefs);\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 xrefs = list === undefined ? [] : parseXrefList(list.text);\n this.describe(record, xrefs);\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 const datatype = tokens.length === 3 ? tokens[2].text : null;\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`.\n * @param record - the record\n * @param xrefs - the xrefs\n */\n private describe(record: NodeRecord, xrefs: readonly Xref[]): void {\n for (const xref of xrefs) {\n if (xref.description !== null) {\n const map = (record.values.get(\"xref.descriptions\") ?? {}) as Record<string, string>;\n map[xref.id] ??= xref.description;\n record.values.set(\"xref.descriptions\", map);\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[]>;\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 const map = (record.values.get(\"obo.unrecognized\") ?? {}) as Record<string, string[]>;\n (map[clause.tag] ??= []).push(unescapeObo(clause.value));\n record.values.set(\"obo.unrecognized\", map);\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 /** Record the counted warnings, in the order they were first seen. */\n flushTallies(): void {\n for (const t of this.tallies.values()) {\n this.report.warning(\n t.category,\n t.code,\n `${t.element}: ${t.what} (${t.count} time(s), first at line ${t.line})`,\n {\n line: t.line,\n element: t.element,\n },\n );\n }\n this.tallies.clear();\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 if (Number(mm) < 1 || Number(mm) > 12 || Number(dd) < 1 || Number(dd) > 31 || 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);\n if (dropped.size > 0) {\n report.warning(\n \"merged\",\n OBO_ISSUE.OBSOLETE_DROPPED,\n `${dropped.size} obsolete term(s) and ${droppedEdges} edge(s) 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 */\nfunction reportDangling(\n records: readonly NodeRecord[],\n dangling: readonly string[],\n addMissingNodes: boolean,\n droppedEdges: number,\n report: ImportReportBuilder,\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 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(s) to them were dropped (addMissingNodes false)`;\n report.warning(\n \"validation-error\",\n OBO_ISSUE.DANGLING_REFERENCE,\n `${dangling.length} target(s) 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 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(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 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 * 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 * 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 (design section 4).\n */\nexport const oboImporter: GraphImporter<OboImportOptions> = Object.freeze({\n format: \"obo\",\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);\n const lines = new LineReader(input, report, resolved);\n let pending: string | null = null;\n for await (const physical of lines) {\n const { line } = lines;\n const text: string = pending === null ? physical : pending + physical;\n pending = null;\n if (endsWithContinuation(text)) {\n reader.tally(\n \"coercion\",\n OBO_ISSUE.DEPRECATED_SYNTAX,\n \"a backslash line continuation was joined (deprecated in 1.4)\",\n \"\\\\\",\n line,\n );\n pending = text.slice(0, -1);\n continue;\n }\n // the 1.4 grammar counts form feed as a line end; LineReader does not\n for (const piece of text.includes(\"\\f\") ? text.split(\"\\f\") : [text]) {\n reader.line(piece, line);\n }\n }\n if (pending !== null) {\n reader.line(pending, lines.line);\n }\n reader.finishFrame();\n if (!reader.significant) {\n report.fail(OBO_ISSUE.EMPTY_INPUT, \"the input is empty\");\n }\n throwIfAborted(resolved.signal);\n writeGraph(reader, sink, report, resolved, obo);\n const typedefs: Record<string, 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"],"names":["end"],"mappings":"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"}
1
+ {"version":3,"file":"importer-DEcKhsmQ.js","sources":["../../src/formats/obo/syntax.ts","../../src/formats/obo/importer.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 */\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 * 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 */\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 */\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 */\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/** The qualifiers of a clause: name to value (a list when a name repeats). */\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.\n * @param value - the raw value without its comment\n * @returns the value and its qualifiers\n */\nexport function splitQualifiers(value: string): QualifiedValue {\n let rest = value;\n let qualifiers: Qualifiers | null = null;\n for (;;) {\n if (!rest.endsWith(\"}\") || isEscaped(rest, rest.length - 1)) {\n return { value: rest, qualifiers, badBlock: null };\n }\n const open = openingBrace(rest);\n const parsed = open < 0 ? null : parseQualifiers(rest.slice(open + 1, -1));\n if (parsed === null) {\n return { value: rest, qualifiers, badBlock: open < 0 ? rest : rest.slice(open) };\n }\n // a block read right to left: an earlier block's names come first\n qualifiers = qualifiers === null ? parsed : mergeQualifiers(parsed, qualifiers);\n rest = rest.slice(0, open).trimEnd();\n }\n}\n\n/**\n * The index of the unescaped `{` outside quotes that opens the block closing the value.\n * @param value - a raw value ending with `}`\n * @returns the index, or -1 when there is none\n */\nfunction openingBrace(value: string): number {\n let quoted = false;\n let open = -1;\n for (let i = 0; i < value.length - 1; 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 open = -1;\n }\n }\n return quoted ? -1 : open;\n}\n\n/**\n * Merge two qualifier records, a repeated name becoming a list.\n * @param first - the earlier record\n * @param second - the later record\n * @returns the merged record\n */\nfunction mergeQualifiers(first: Qualifiers, second: Qualifiers): Qualifiers {\n const out: Qualifiers = { ...first };\n for (const [name, value] of Object.entries(second)) {\n addQualifier(out, name, value);\n }\n return out;\n}\n\n/**\n * Add one qualifier, turning a repeated name into a list.\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 if (!Object.prototype.hasOwnProperty.call(record, name)) {\n record[name] = value;\n return;\n }\n const before = record[name];\n record[name] = [...(Array.isArray(before) ? before : [before]), ...(Array.isArray(value) ? value : [value])];\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 */\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/** One token of a value. */\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 */\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/** One cross-reference: `ID \"description\" {qualifiers}`. */\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}\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 */\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 if (quote >= 0) {\n const end = closingQuote(value, quote + 1);\n description = unescapeObo(value.slice(quote + 1, end < 0 ? value.length : end));\n }\n return { id, description, qualifiers };\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 */\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 */\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 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 EMPTY_INPUT_CODE,\n ENCODING_FALLBACK_CODE,\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 { 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 splitQualifiers,\n splitTagValue,\n stripComment,\n type Token,\n tokenize,\n unescapeObo,\n type Xref,\n} from \"./syntax.js\";\n\n/** The format-specific options of the OBO importer. */\nexport interface OboImportOptions {\n /** \"keep\" (default): obsolete terms are nodes with `is_obsolete` true; \"drop\": they and their edges are left out. */\n obsolete?: \"keep\" | \"drop\" | undefined;\n /** \"metadata\" (default): `[Typedef]` frames go to `meta.extra.obo.typedefs`; \"nodes\": they are nodes too, with their `is_a` edges. */\n typedefs?: \"metadata\" | \"nodes\" | undefined;\n}\n\n/** Issue codes of the OBO importer (design section 4.3). */\nexport const OBO_ISSUE = Object.freeze({\n /** The input is empty or whitespace (fatal). */\n EMPTY_INPUT: EMPTY_INPUT_CODE,\n /** The input holds invalid UTF-8 (fatal). */\n INVALID_UTF8: INVALID_UTF8_CODE,\n /** Invalid bytes in the encoding a BOM or the encoding option chose (fatal). */\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 with one id were merged (spec 4.1.1). */\n DUPLICATE_NODE: DUPLICATE_NODE_CODE,\n /** A single-valued tag given twice for one id (a cardinality violation); the first 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 /** 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 /** Fewer than two `intersection_of` or `union_of` clauses on a frame. */\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 /** A header clause kept in `meta.extra.obo.header` whose meaning is not applied (import, id-mapping, the treat-xrefs macros, owl-axioms). */\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 /** Two distinct id texts became one number under ids \"number\". */\n ID_MERGED: ID_MERGED_CODE,\n /** A vocabulary column renamed `<name>#obo` because the sink already holds the name. */\n COLUMN_RENAMED: RENAMED_CODE,\n /** A vocabulary column declared without its role because the sink already holds it. */\n ROLE_TAKEN: ROLE_TAKEN_CODE,\n /** A common option the format has no use for (defaultDirected, weightFrom, nodeIdFrom, ...). */\n OPTION_IGNORED: OPTION_IGNORED_CODE,\n /** A builder-policy option the caller passed that the caller's sink does not use. */\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]);\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/** The 1.0 / 1.2 frame tags read as their 1.4 meaning: tag to [1.4 tag, synonym scope]. */\nconst 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/** Single-valued text tags (first value kept). */\nconst 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/** Single-valued boolean tags. */\nconst BOOL_TAGS: ReadonlySet<string> = new Set(\n Object.keys(OBO_NODE_COLUMNS).filter((name) => OBO_NODE_COLUMNS[name].dtype === \"bool\"),\n);\n\n/** Tags whose value is one id, collected in a list column. */\nconst 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/** Tags that only a Typedef frame may carry (elsewhere they are unrecognized). */\nconst 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\";\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[]> = {};\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 */\n constructor(report: ImportReportBuilder, signal: AbortSignal | null) {\n this.report = report;\n this.signal = signal;\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 const header = /^\\[([^\\]]*)\\]\\s*(?:!.*)?$/.exec(t);\n if (header !== null) {\n this.startFrame(header[1].trim(), 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) {\n this.tally(\"parse-error\", OBO_ISSUE.SYNTAX, \"a line without a colon was skipped\", \"line\", line);\n return;\n }\n const clause: Clause = { tag: tv.tag, value: stripComment(tv.rest), line };\n if (this.frame === null) {\n this.headerClause(clause);\n } else {\n this.frame.clauses.push(clause);\n }\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 */\n private startFrame(name: string, line: number): void {\n this.finishFrame();\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 (this.header[clause.tag] ??= []).push(clause.value);\n const { tag } = clause;\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\" && 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: Record<string, string[]> = {};\n for (const clause of frame.clauses) {\n (clauses[clause.tag] ??= []).push(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 id = idAt < 0 ? \"\" : unescapeObo(splitQualifiers(frame.clauses[idAt].value).value).trim();\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 this.report.counts.skippedNodes++;\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 record = this.recordFor(frame.kind, id, frame.line);\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(record, clause);\n }\n if (record.kind === \"Typedef\") {\n record.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.report.warning(\n \"merged\",\n OBO_ISSUE.DUPLICATE_NODE,\n `two [${kind}] frames have the id ${id}; they are merged (spec 4.1.1)`,\n {\n line,\n element: id,\n },\n );\n }\n return existing;\n }\n const record: NodeRecord = {\n id,\n kind,\n line,\n values: new Map(),\n lists: new Map(),\n edges: [],\n seen: new Set(),\n raw: {},\n };\n map.set(id, record);\n return record;\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 const split = splitQualifiers(clause.value);\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 (record.raw[clause.tag] ??= []).push(clause.value);\n }\n const { tag, scope, qualifiers, value } = this.clauseParts(clause);\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.single(record, tag, unescapeObo(value).trim(), clause.line);\n this.extraQualifiers(record, tag, unescapeObo(value).trim(), qualifiers);\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]);\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 * 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 const xrefs = parseXrefList(list.text);\n this.describe(record, xrefs);\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 xrefs = list === undefined ? [] : parseXrefList(list.text);\n this.describe(record, xrefs);\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 const datatype = tokens.length === 3 ? tokens[2].text : null;\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`.\n * @param record - the record\n * @param xrefs - the xrefs\n */\n private describe(record: NodeRecord, xrefs: readonly Xref[]): void {\n for (const xref of xrefs) {\n if (xref.description !== null) {\n const map = (record.values.get(\"xref.descriptions\") ?? {}) as Record<string, string>;\n map[xref.id] ??= xref.description;\n record.values.set(\"xref.descriptions\", map);\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[]>;\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 const map = (record.values.get(\"obo.unrecognized\") ?? {}) as Record<string, string[]>;\n (map[clause.tag] ??= []).push(unescapeObo(clause.value));\n record.values.set(\"obo.unrecognized\", map);\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 /** Record the counted warnings, in the order they were first seen. */\n flushTallies(): void {\n for (const t of this.tallies.values()) {\n this.report.warning(\n t.category,\n t.code,\n `${t.element}: ${t.what} (${t.count} time(s), first at line ${t.line})`,\n {\n line: t.line,\n element: t.element,\n },\n );\n }\n this.tallies.clear();\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 if (Number(mm) < 1 || Number(mm) > 12 || Number(dd) < 1 || Number(dd) > 31 || 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);\n if (dropped.size > 0) {\n report.warning(\n \"merged\",\n OBO_ISSUE.OBSOLETE_DROPPED,\n `${dropped.size} obsolete term(s) and ${droppedEdges} edge(s) 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 */\nfunction reportDangling(\n records: readonly NodeRecord[],\n dangling: readonly string[],\n addMissingNodes: boolean,\n droppedEdges: number,\n report: ImportReportBuilder,\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 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(s) to them were dropped (addMissingNodes false)`;\n report.warning(\n \"validation-error\",\n OBO_ISSUE.DANGLING_REFERENCE,\n `${dangling.length} target(s) 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 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(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 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 * 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 * 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 (design section 4).\n */\nexport const oboImporter: GraphImporter<OboImportOptions> = Object.freeze({\n format: \"obo\",\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);\n const lines = new LineReader(input, report, resolved);\n let pending: string | null = null;\n for await (const physical of lines) {\n const { line } = lines;\n const text: string = pending === null ? physical : pending + physical;\n pending = null;\n if (endsWithContinuation(text)) {\n reader.tally(\n \"coercion\",\n OBO_ISSUE.DEPRECATED_SYNTAX,\n \"a backslash line continuation was joined (deprecated in 1.4)\",\n \"\\\\\",\n line,\n );\n pending = text.slice(0, -1);\n continue;\n }\n // the 1.4 grammar counts form feed as a line end; LineReader does not\n for (const piece of text.includes(\"\\f\") ? text.split(\"\\f\") : [text]) {\n reader.line(piece, line);\n }\n }\n if (pending !== null) {\n reader.line(pending, lines.line);\n }\n reader.finishFrame();\n if (!reader.significant) {\n report.fail(OBO_ISSUE.EMPTY_INPUT, \"the input is empty\");\n }\n throwIfAborted(resolved.signal);\n writeGraph(reader, sink, report, resolved, obo);\n const typedefs: Record<string, 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"],"names":["end"],"mappings":"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"}
@@ -1,9 +1,10 @@
1
1
  import { GraphFormatError, INVALID_INDEX, MAX_COUNT } from "@graphty/graph-format";
2
2
  import { c as childrenCsr } from "./children-CL3Cy0ez.js";
3
- import { N as MIXED_DIRECTION_CODE, j as DIRECTION_FORCED_CODE, k as DIRECTION_REFUSED_CODE, a2 as SINK_OPTION_CODE, Z as PRECISION_CODE, b as BAD_DEFAULT_CODE, ad as UNKNOWN_ATTR_TYPE_CODE, a1 as ROLE_TAKEN_CODE, C as COLUMN_RENAMED_CODE, U as OPTION_IGNORED_CODE, u as ID_MERGED_CODE, a6 as STRAY_TEXT_CODE, ae as UNKNOWN_ELEMENT_CODE, H as HYPEREDGE_CODE, f as COUNT_HINT_CODE, O as MULTIPLE_GRAPHS_CODE, m as DUPLICATE_EDGE_ID_CODE, o as DUPLICATE_NODE_CODE, M as MISSING_ENDPOINT_CODE, K as MISSING_ID_CODE, n as DUPLICATE_KEY_CODE, S as NO_GRAPH_CODE, af as UNKNOWN_ENCODING_CODE, r as ENCODING_FALLBACK_CODE, y as INVALID_ENCODING_CODE, z as INVALID_UTF8_CODE, al as XML_SYNTAX_CODE, w as ID_TEXT_TYPE_CODE, a0 as ROLE_DROPPED_CODE, W as PARENTS_DROPPED_CODE, P as MUTUAL_AS_UNDIRECTED_CODE, aB as resolveExportOptions, ax as pairFolding, av as isCanonicalIntegerText, aC as resolveImportOptions, I as ImportReportBuilder, az as reportSinkOptions, aA as reportUnusedOptions, aD as textChunks, t as throwIfAborted, F as IdCoercer, p as DirectionResolver, aI as declareAttribute, aE as uniqueColumnName, ar as declareResolved, aW as takenIn, aK as parseDeclaredValue, aL as losesPrecision } from "./report-BcWboivV.js";
4
- import { f as escapeXmlText, e as isWhitespace, n as isXmlName, g as escapeXmlAttribute, l as localName, x as xmlIllegalTextNotes, t as tokenizeXml, d as xmlDeclaredEncoding, X as XmlSyntaxError } from "./escape-CWExcecC.js";
5
- import { j as joinText, e as encodeChunks, c as capabilities, a as checkCapabilities, L as LOSS, s as sanitizeIds, i as isNmtoken, m as mangleNmtoken } from "./writer-DQiKgQJc.js";
6
- import { e as explicitWeights, d as formatInteger, b as formatF64, a as formatF32, i as isWeightField, p as parseWeightText } from "./weights-CwISIpCP.js";
3
+ import { af as MIXED_DIRECTION_CODE, D as DIRECTION_FORCED_CODE, a as DIRECTION_REFUSED_CODE, S as SINK_OPTION_CODE, P as PRECISION_CODE, Z as BAD_DEFAULT_CODE, k as UNKNOWN_ATTR_TYPE_CODE, R as ROLE_TAKEN_CODE, C as COLUMN_RENAMED_CODE, O as OPTION_IGNORED_CODE, I as ID_MERGED_CODE, au as STRAY_TEXT_CODE, Y as UNKNOWN_ELEMENT_CODE, an as HYPEREDGE_CODE, ai as COUNT_HINT_CODE, M as MULTIPLE_GRAPHS_CODE, c as DUPLICATE_EDGE_ID_CODE, d as DUPLICATE_NODE_CODE, e as MISSING_ENDPOINT_CODE, f as MISSING_ID_CODE, al as DUPLICATE_KEY_CODE, N as NO_GRAPH_CODE, q as UNKNOWN_ENCODING_CODE, E as ENCODING_FALLBACK_CODE, r as INVALID_ENCODING_CODE, s as INVALID_UTF8_CODE, aw as XML_SYNTAX_CODE, b as ID_TEXT_TYPE_CODE, ac as ROLE_DROPPED_CODE, ab as PARENTS_DROPPED_CODE, a9 as MUTUAL_AS_UNDIRECTED_CODE, V as resolveExportOptions, X as pairFolding, aE as isCanonicalIntegerText, v as resolveImportOptions, w as ImportReportBuilder, F as reportSinkOptions, z as reportUnusedOptions, x as textChunks, y as throwIfAborted, K as IdCoercer, J as DirectionResolver, aK as declareAttribute, Q as uniqueColumnName, L as declareResolved, aX as takenIn, aM as parseDeclaredValue, aN as losesPrecision } from "./report-B1z4WT9e.js";
4
+ import { a as escapeXmlText, g as isWhitespace, n as isXmlName, e as escapeXmlAttribute, l as localName, x as xmlIllegalTextNotes, t as tokenizeXml, f as xmlDeclaredEncoding, X as XmlSyntaxError } from "./escape-B-tkk_Cl.js";
5
+ import { c as capabilities, a as checkCapabilities, L as LOSS, s as sanitizeIds, i as isNmtoken, m as mangleNmtoken } from "./export-Bh60Dv-n.js";
6
+ import { e as explicitWeights, d as formatInteger, a as formatF64, f as formatF32, i as isWeightField, p as parseWeightText } from "./weights-Dzba96G3.js";
7
+ import { j as joinText, e as encodeChunks } from "./writer-C7flM-Ih.js";
7
8
  const GRAPHML_NAMESPACE = "http://graphml.graphdrawing.org/xmlns";
8
9
  const YFILES_NAMESPACE = "http://www.yworks.com/xml/graphml";
9
10
  const XSI_NAMESPACE = "http://www.w3.org/2001/XMLSchema-instance";
@@ -3337,4 +3338,4 @@ export {
3337
3338
  graphmlImporter as b,
3338
3339
  graphmlExporter as g
3339
3340
  };
3340
- //# sourceMappingURL=importer-BW-Ft2ps.js.map
3341
+ //# sourceMappingURL=importer-DIrbbnAf.js.map