@graphty/graph-io 0.3.40 → 0.3.42

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 (210) hide show
  1. package/README.md +2 -0
  2. package/dist/chunks/{children-CL3Cy0ez.js → children-CA4coBi0.js} +36 -27
  3. package/dist/chunks/children-CA4coBi0.js.map +1 -0
  4. package/dist/chunks/{choose-CS3fvGT1.js → choose-DvpbdRuz.js} +2 -2
  5. package/dist/chunks/{choose-CS3fvGT1.js.map → choose-DvpbdRuz.js.map} +1 -1
  6. package/dist/chunks/{constants-DqKZT6cH.js → constants-fT3E8JYY.js} +2 -2
  7. package/dist/chunks/{constants-DqKZT6cH.js.map → constants-fT3E8JYY.js.map} +1 -1
  8. package/dist/chunks/{escape-BJRLd3vJ.js → escape-B62ZGM_a.js} +2 -2
  9. package/dist/chunks/{escape-BJRLd3vJ.js.map → escape-B62ZGM_a.js.map} +1 -1
  10. package/dist/chunks/{export-B-aVCwyG.js → export-rKLeGQMo.js} +404 -243
  11. package/dist/chunks/export-rKLeGQMo.js.map +1 -0
  12. package/dist/chunks/{exporter-6ocL_9x_.js → exporter-8hLNemFk.js} +4 -4
  13. package/dist/chunks/{exporter-6ocL_9x_.js.map → exporter-8hLNemFk.js.map} +1 -1
  14. package/dist/chunks/{exporter-BVXnV9-9.js → exporter-BWwEuOPT.js} +29 -17
  15. package/dist/chunks/exporter-BWwEuOPT.js.map +1 -0
  16. package/dist/chunks/{exporter-Bcp-l4Bo.js → exporter-CpRyHZ3H.js} +574 -475
  17. package/dist/chunks/exporter-CpRyHZ3H.js.map +1 -0
  18. package/dist/chunks/{exporter-SFYkDzD0.js → exporter-yLxKBvLE.js} +23 -20
  19. package/dist/chunks/{exporter-SFYkDzD0.js.map → exporter-yLxKBvLE.js.map} +1 -1
  20. package/dist/chunks/{importer-DcKB97kW.js → importer-BbNb7eNg.js} +111 -71
  21. package/dist/chunks/importer-BbNb7eNg.js.map +1 -0
  22. package/dist/chunks/{importer-D_srHyj6.js → importer-C98dpSH4.js} +5 -5
  23. package/dist/chunks/{importer-D_srHyj6.js.map → importer-C98dpSH4.js.map} +1 -1
  24. package/dist/chunks/{importer-BJlGAOht.js → importer-D794XUTe.js} +3 -3
  25. package/dist/chunks/{importer-BJlGAOht.js.map → importer-D794XUTe.js.map} +1 -1
  26. package/dist/chunks/{importer-AjwOJrn2.js → importer-Dz7tI8Sa.js} +202 -181
  27. package/dist/chunks/importer-Dz7tI8Sa.js.map +1 -0
  28. package/dist/chunks/{importer-DEp_fYjf.js → importer-Ht7LNg8L.js} +92 -64
  29. package/dist/chunks/importer-Ht7LNg8L.js.map +1 -0
  30. package/dist/chunks/{importer-CPqnIY8m.js → importer-WrGRZb0N.js} +42 -29
  31. package/dist/chunks/importer-WrGRZb0N.js.map +1 -0
  32. package/dist/chunks/{importer-BpuS3J8C.js → importer-xZ-3suY1.js} +74 -61
  33. package/dist/chunks/importer-xZ-3suY1.js.map +1 -0
  34. package/dist/chunks/{json-elements-DpO6AXIc.js → json-elements-DKSqpNW1.js} +3 -3
  35. package/dist/chunks/{json-elements-DpO6AXIc.js.map → json-elements-DKSqpNW1.js.map} +1 -1
  36. package/dist/chunks/{ontology-export-50L9DOV4.js → ontology-export-CtRXjg_i.js} +2 -2
  37. package/dist/chunks/{ontology-export-50L9DOV4.js.map → ontology-export-CtRXjg_i.js.map} +1 -1
  38. package/dist/chunks/{records-r3SFHz11.js → records-Cu4bxYOm.js} +69 -36
  39. package/dist/chunks/records-Cu4bxYOm.js.map +1 -0
  40. package/dist/chunks/{text-Bjfa1xYL.js → text-DHOJXnED.js} +20 -11
  41. package/dist/chunks/text-DHOJXnED.js.map +1 -0
  42. package/dist/csv.js +323 -241
  43. package/dist/csv.js.map +1 -1
  44. package/dist/cx.js +1 -1
  45. package/dist/cx2.js +2 -2
  46. package/dist/cys.js +1 -1
  47. package/dist/dot.js +1 -1
  48. package/dist/gexf.js +195 -97
  49. package/dist/gexf.js.map +1 -1
  50. package/dist/gml.js +170 -149
  51. package/dist/gml.js.map +1 -1
  52. package/dist/graph-io.js +27 -27
  53. package/dist/graphml.js +2 -2
  54. package/dist/json.js +1 -1
  55. package/dist/neo4j.js +103 -65
  56. package/dist/neo4j.js.map +1 -1
  57. package/dist/obo.js +1 -1
  58. package/dist/pajek.js +1 -1
  59. package/dist/src/children.d.ts.map +1 -1
  60. package/dist/src/children.js +50 -27
  61. package/dist/src/children.js.map +1 -1
  62. package/dist/src/common/attributes.d.ts.map +1 -1
  63. package/dist/src/common/attributes.js +86 -42
  64. package/dist/src/common/attributes.js.map +1 -1
  65. package/dist/src/common/input.d.ts.map +1 -1
  66. package/dist/src/common/input.js +358 -184
  67. package/dist/src/common/input.js.map +1 -1
  68. package/dist/src/common/lists.js +30 -15
  69. package/dist/src/common/lists.js.map +1 -1
  70. package/dist/src/common/text.d.ts +7 -0
  71. package/dist/src/common/text.d.ts.map +1 -1
  72. package/dist/src/common/text.js +15 -7
  73. package/dist/src/common/text.js.map +1 -1
  74. package/dist/src/common/zip.d.ts.map +1 -1
  75. package/dist/src/common/zip.js +36 -19
  76. package/dist/src/common/zip.js.map +1 -1
  77. package/dist/src/formats/csv/exporter.d.ts.map +1 -1
  78. package/dist/src/formats/csv/exporter.js +288 -146
  79. package/dist/src/formats/csv/exporter.js.map +1 -1
  80. package/dist/src/formats/csv/importer.d.ts.map +1 -1
  81. package/dist/src/formats/csv/importer.js +129 -80
  82. package/dist/src/formats/csv/importer.js.map +1 -1
  83. package/dist/src/formats/csv/records.d.ts.map +1 -1
  84. package/dist/src/formats/csv/records.js +78 -36
  85. package/dist/src/formats/csv/records.js.map +1 -1
  86. package/dist/src/formats/cys/tables.d.ts.map +1 -1
  87. package/dist/src/formats/cys/tables.js +11 -8
  88. package/dist/src/formats/cys/tables.js.map +1 -1
  89. package/dist/src/formats/dot/tokenizer.d.ts +39 -0
  90. package/dist/src/formats/dot/tokenizer.d.ts.map +1 -1
  91. package/dist/src/formats/dot/tokenizer.js +112 -66
  92. package/dist/src/formats/dot/tokenizer.js.map +1 -1
  93. package/dist/src/formats/gexf/exporter.d.ts.map +1 -1
  94. package/dist/src/formats/gexf/exporter.js +65 -37
  95. package/dist/src/formats/gexf/exporter.js.map +1 -1
  96. package/dist/src/formats/gexf/importer.d.ts.map +1 -1
  97. package/dist/src/formats/gexf/importer.js +138 -50
  98. package/dist/src/formats/gexf/importer.js.map +1 -1
  99. package/dist/src/formats/gml/exporter.d.ts.map +1 -1
  100. package/dist/src/formats/gml/exporter.js +51 -35
  101. package/dist/src/formats/gml/exporter.js.map +1 -1
  102. package/dist/src/formats/gml/importer.d.ts.map +1 -1
  103. package/dist/src/formats/gml/importer.js +103 -58
  104. package/dist/src/formats/gml/importer.js.map +1 -1
  105. package/dist/src/formats/gml/syntax.d.ts.map +1 -1
  106. package/dist/src/formats/gml/syntax.js +17 -8
  107. package/dist/src/formats/gml/syntax.js.map +1 -1
  108. package/dist/src/formats/graphml/exporter.d.ts.map +1 -1
  109. package/dist/src/formats/graphml/exporter.js +34 -24
  110. package/dist/src/formats/graphml/exporter.js.map +1 -1
  111. package/dist/src/formats/graphml/importer.d.ts.map +1 -1
  112. package/dist/src/formats/graphml/importer.js +17 -13
  113. package/dist/src/formats/graphml/importer.js.map +1 -1
  114. package/dist/src/formats/graphml/tree.js +23 -14
  115. package/dist/src/formats/graphml/tree.js.map +1 -1
  116. package/dist/src/formats/graphml/yfiles.d.ts.map +1 -1
  117. package/dist/src/formats/graphml/yfiles.js +22 -10
  118. package/dist/src/formats/graphml/yfiles.js.map +1 -1
  119. package/dist/src/formats/json/dialect.d.ts.map +1 -1
  120. package/dist/src/formats/json/dialect.js +54 -20
  121. package/dist/src/formats/json/dialect.js.map +1 -1
  122. package/dist/src/formats/json/exporter.d.ts.map +1 -1
  123. package/dist/src/formats/json/exporter.js +38 -21
  124. package/dist/src/formats/json/exporter.js.map +1 -1
  125. package/dist/src/formats/json/importer.d.ts.map +1 -1
  126. package/dist/src/formats/json/importer.js +536 -343
  127. package/dist/src/formats/json/importer.js.map +1 -1
  128. package/dist/src/formats/json/obographs.js +29 -17
  129. package/dist/src/formats/json/obographs.js.map +1 -1
  130. package/dist/src/formats/neo4j/exporter.d.ts.map +1 -1
  131. package/dist/src/formats/neo4j/exporter.js +73 -43
  132. package/dist/src/formats/neo4j/exporter.js.map +1 -1
  133. package/dist/src/formats/neo4j/header.d.ts.map +1 -1
  134. package/dist/src/formats/neo4j/header.js +37 -16
  135. package/dist/src/formats/neo4j/header.js.map +1 -1
  136. package/dist/src/formats/neo4j/importer.d.ts.map +1 -1
  137. package/dist/src/formats/neo4j/importer.js +21 -11
  138. package/dist/src/formats/neo4j/importer.js.map +1 -1
  139. package/dist/src/formats/obo/exporter.d.ts.map +1 -1
  140. package/dist/src/formats/obo/exporter.js +18 -7
  141. package/dist/src/formats/obo/exporter.js.map +1 -1
  142. package/dist/src/formats/pajek/exporter.d.ts.map +1 -1
  143. package/dist/src/formats/pajek/exporter.js +142 -73
  144. package/dist/src/formats/pajek/exporter.js.map +1 -1
  145. package/dist/src/formats/pajek/importer.d.ts.map +1 -1
  146. package/dist/src/formats/pajek/importer.js +26 -15
  147. package/dist/src/formats/pajek/importer.js.map +1 -1
  148. package/dist/src/formats/pajek/syntax.d.ts.map +1 -1
  149. package/dist/src/formats/pajek/syntax.js +85 -58
  150. package/dist/src/formats/pajek/syntax.js.map +1 -1
  151. package/dist/src/formats/xgmml/emit.d.ts +7 -0
  152. package/dist/src/formats/xgmml/emit.d.ts.map +1 -1
  153. package/dist/src/formats/xgmml/emit.js +79 -40
  154. package/dist/src/formats/xgmml/emit.js.map +1 -1
  155. package/dist/src/formats/xgmml/exporter.d.ts.map +1 -1
  156. package/dist/src/formats/xgmml/exporter.js +38 -12
  157. package/dist/src/formats/xgmml/exporter.js.map +1 -1
  158. package/dist/src/formats/xgmml/importer.d.ts.map +1 -1
  159. package/dist/src/formats/xgmml/importer.js +38 -18
  160. package/dist/src/formats/xgmml/importer.js.map +1 -1
  161. package/dist/src/sniff.js +109 -57
  162. package/dist/src/sniff.js.map +1 -1
  163. package/dist/xgmml.js +2 -2
  164. package/package.json +2 -2
  165. package/src/children.ts +54 -27
  166. package/src/common/attributes.ts +118 -49
  167. package/src/common/input.ts +439 -197
  168. package/src/common/lists.ts +29 -15
  169. package/src/common/text.ts +24 -15
  170. package/src/common/zip.ts +47 -18
  171. package/src/formats/csv/exporter.ts +377 -175
  172. package/src/formats/csv/importer.ts +155 -84
  173. package/src/formats/csv/records.ts +90 -35
  174. package/src/formats/cys/tables.ts +11 -10
  175. package/src/formats/dot/tokenizer.ts +118 -68
  176. package/src/formats/gexf/exporter.ts +67 -36
  177. package/src/formats/gexf/importer.ts +173 -63
  178. package/src/formats/gml/exporter.ts +78 -82
  179. package/src/formats/gml/importer.ts +119 -68
  180. package/src/formats/gml/syntax.ts +18 -8
  181. package/src/formats/graphml/exporter.ts +44 -24
  182. package/src/formats/graphml/importer.ts +18 -11
  183. package/src/formats/graphml/tree.ts +22 -12
  184. package/src/formats/graphml/yfiles.ts +23 -10
  185. package/src/formats/json/dialect.ts +61 -22
  186. package/src/formats/json/exporter.ts +40 -21
  187. package/src/formats/json/importer.ts +701 -385
  188. package/src/formats/json/obographs.ts +35 -15
  189. package/src/formats/neo4j/exporter.ts +79 -41
  190. package/src/formats/neo4j/header.ts +50 -16
  191. package/src/formats/neo4j/importer.ts +21 -10
  192. package/src/formats/obo/exporter.ts +34 -17
  193. package/src/formats/pajek/exporter.ts +180 -117
  194. package/src/formats/pajek/importer.ts +27 -15
  195. package/src/formats/pajek/syntax.ts +99 -58
  196. package/src/formats/xgmml/emit.ts +88 -40
  197. package/src/formats/xgmml/exporter.ts +40 -12
  198. package/src/formats/xgmml/importer.ts +45 -23
  199. package/src/sniff.ts +115 -59
  200. package/dist/chunks/children-CL3Cy0ez.js.map +0 -1
  201. package/dist/chunks/export-B-aVCwyG.js.map +0 -1
  202. package/dist/chunks/exporter-BVXnV9-9.js.map +0 -1
  203. package/dist/chunks/exporter-Bcp-l4Bo.js.map +0 -1
  204. package/dist/chunks/importer-AjwOJrn2.js.map +0 -1
  205. package/dist/chunks/importer-BpuS3J8C.js.map +0 -1
  206. package/dist/chunks/importer-CPqnIY8m.js.map +0 -1
  207. package/dist/chunks/importer-DEp_fYjf.js.map +0 -1
  208. package/dist/chunks/importer-DcKB97kW.js.map +0 -1
  209. package/dist/chunks/records-r3SFHz11.js.map +0 -1
  210. package/dist/chunks/text-Bjfa1xYL.js.map +0 -1
package/dist/cx.js CHANGED
@@ -1,4 +1,4 @@
1
- import { C, a, b, c, d } from "./chunks/importer-D_srHyj6.js";
1
+ import { C, a, b, c, d } from "./chunks/importer-C98dpSH4.js";
2
2
  export {
3
3
  C as CX_CAPABILITIES,
4
4
  a as CX_ISSUE,
package/dist/cx2.js CHANGED
@@ -1,5 +1,5 @@
1
- import { C, a, c } from "./chunks/exporter-6ocL_9x_.js";
2
- import { C as C2, c as c2 } from "./chunks/importer-BJlGAOht.js";
1
+ import { C, a, c } from "./chunks/exporter-8hLNemFk.js";
2
+ import { C as C2, c as c2 } from "./chunks/importer-D794XUTe.js";
3
3
  export {
4
4
  C as CX2_CAPABILITIES,
5
5
  C2 as CX2_ISSUE,
package/dist/cys.js CHANGED
@@ -1,4 +1,4 @@
1
- import { C, a, b, c, d } from "./chunks/importer-CPqnIY8m.js";
1
+ import { C, a, b, c, d } from "./chunks/importer-WrGRZb0N.js";
2
2
  export {
3
3
  C as CYS_CAPABILITIES,
4
4
  a as CYS_ISSUE,
package/dist/dot.js CHANGED
@@ -1,4 +1,4 @@
1
- import { D, a, d, b } from "./chunks/importer-DcKB97kW.js";
1
+ import { D, a, d, b } from "./chunks/importer-BbNb7eNg.js";
2
2
  export {
3
3
  D as DOT_ISSUE,
4
4
  a as DOT_LOSS,
package/dist/gexf.js CHANGED
@@ -1,6 +1,6 @@
1
- import { bF as TIME_TEXT_ROLE, bG as TIME_TEXT_SUFFIX, al as resolveImportOptions, a8 as ImportReportBuilder, ao as reportSinkOptions, an as reportUnusedOptions, a4 as textChunks, E as EMPTY_INPUT_CODE, X as XML_SYNTAX_CODE, am as throwIfAborted, ar as IdCoercer, aq as DirectionResolver, f as STRAY_TEXT_CODE, N as NO_GRAPH_CODE, h as UNKNOWN_XML_ATTRIBUTE_CODE, l as MULTIPLE_GRAPHS_CODE, j as COUNT_MISMATCH_CODE, k as COUNT_HINT_CODE, o as DUPLICATE_ATTRIBUTE_CODE, aJ as isWeightField, bH as declareAttribute, a1 as declareResolved, t as MISSING_ID_CODE, n as DUPLICATE_NODE_CODE, q as UNKNOWN_PARENT_CODE, ai as PARENT_CYCLE_CODE, s as MISSING_ENDPOINT_CODE, m as DUPLICATE_EDGE_ID_CODE, aK as parseWeightText, bI as overflowsToInfinity, P as PRECISION_CODE, bJ as parseDeclaredTemporal, br as declareCompanion, bK as parseDeclaredValue, bL as losesPrecision, bM as parseTimeText, a3 as BAD_VALUE_CODE, bN as splitListText, g as UNKNOWN_ELEMENT_CODE, I as ID_MERGED_CODE, bO as timeTextCompanion, bP as parseDecimalText, c as capabilities, L as LOSS, aE as sanitizeIds, p as pairFolding, e as explicitWeights, r as resolveExportOptions, a as checkCapabilities, bQ as formatTimeValue, aa as formatF32, ab as formatF64, bR as mapDeclaredType, bS as joinListText, bT as formatTemporal, aG as formatInteger, b as plural, $ as agree, bx as isCanonicalIntegerText, M as MIXED_DIRECTION_CODE, D as DIRECTION_FORCED_CODE, d as DIRECTION_REFUSED_CODE, S as SINK_OPTION_CODE, O as OPTION_IGNORED_CODE, R as ROLE_TAKEN_CODE, C as COLUMN_RENAMED_CODE, aZ as BAD_OPTIONS_CODE, B as BAD_DEFAULT_CODE, U as UNKNOWN_ATTR_TYPE_CODE, v as ENCODING_CONFLICT_CODE, w as UNKNOWN_ENCODING_CODE, x as ENCODING_FALLBACK_CODE, y as INVALID_ENCODING_CODE, z as INVALID_UTF8_CODE, A as COLUMN_TYPE_CODE, F as ELEMENT_ISSUE, G as INPUT_ISSUE } from "./chunks/export-B-aVCwyG.js";
1
+ import { bF as TIME_TEXT_ROLE, bG as TIME_TEXT_SUFFIX, al as resolveImportOptions, a8 as ImportReportBuilder, ao as reportSinkOptions, an as reportUnusedOptions, a4 as textChunks, E as EMPTY_INPUT_CODE, X as XML_SYNTAX_CODE, am as throwIfAborted, ar as IdCoercer, aq as DirectionResolver, f as STRAY_TEXT_CODE, N as NO_GRAPH_CODE, h as UNKNOWN_XML_ATTRIBUTE_CODE, l as MULTIPLE_GRAPHS_CODE, j as COUNT_MISMATCH_CODE, k as COUNT_HINT_CODE, o as DUPLICATE_ATTRIBUTE_CODE, aJ as isWeightField, bH as declareAttribute, a1 as declareResolved, t as MISSING_ID_CODE, n as DUPLICATE_NODE_CODE, q as UNKNOWN_PARENT_CODE, ai as PARENT_CYCLE_CODE, s as MISSING_ENDPOINT_CODE, m as DUPLICATE_EDGE_ID_CODE, aK as parseWeightText, bI as overflowsToInfinity, P as PRECISION_CODE, bJ as parseDeclaredTemporal, br as declareCompanion, bK as parseDeclaredValue, bL as losesPrecision, bM as parseTimeText, a3 as BAD_VALUE_CODE, bN as splitListText, g as UNKNOWN_ELEMENT_CODE, I as ID_MERGED_CODE, bO as timeTextCompanion, bP as parseDecimalText, c as capabilities, L as LOSS, aE as sanitizeIds, p as pairFolding, e as explicitWeights, r as resolveExportOptions, a as checkCapabilities, aa as formatF32, ab as formatF64, bQ as formatTimeValue, bR as mapDeclaredType, bS as joinListText, bT as formatTemporal, aG as formatInteger, b as plural, $ as agree, bx as isCanonicalIntegerText, M as MIXED_DIRECTION_CODE, D as DIRECTION_FORCED_CODE, d as DIRECTION_REFUSED_CODE, S as SINK_OPTION_CODE, O as OPTION_IGNORED_CODE, R as ROLE_TAKEN_CODE, C as COLUMN_RENAMED_CODE, aZ as BAD_OPTIONS_CODE, B as BAD_DEFAULT_CODE, U as UNKNOWN_ATTR_TYPE_CODE, v as ENCODING_CONFLICT_CODE, w as UNKNOWN_ENCODING_CODE, x as ENCODING_FALLBACK_CODE, y as INVALID_ENCODING_CODE, z as INVALID_UTF8_CODE, A as COLUMN_TYPE_CODE, F as ELEMENT_ISSUE, G as INPUT_ISSUE } from "./chunks/export-rKLeGQMo.js";
2
2
  import { GraphFormatError, INVALID_INDEX, MAX_COUNT } from "@graphty/graph-format";
3
- import { t as tokenizeXml, f as xmlDeclaredEncoding, g as XmlEmptyInputError, X as XmlSyntaxError, s as sniffXmlText, l as localName, j as isWhitespace, x as xmlIllegalTextNotes, a as escapeXmlText, e as escapeXmlAttribute } from "./chunks/escape-BJRLd3vJ.js";
3
+ import { t as tokenizeXml, f as xmlDeclaredEncoding, g as XmlEmptyInputError, X as XmlSyntaxError, s as sniffXmlText, l as localName, j as isWhitespace, x as xmlIllegalTextNotes, a as escapeXmlText, e as escapeXmlAttribute } from "./chunks/escape-B62ZGM_a.js";
4
4
  import { j as joinText, e as encodeChunks } from "./chunks/writer-DxjgHwSe.js";
5
5
  const GEXF_FORMAT = "gexf";
6
6
  const GEXF_NAMESPACES = {
@@ -1121,20 +1121,15 @@ class GexfReader {
1121
1121
  }
1122
1122
  }
1123
1123
  /**
1124
- * Declare one `<attribute id title type>` with its `<default>` and `<options>` (design
1125
- * sections 5.1, 5.5, 5.6). The edge attribute titled `weightFrom` is the weight and gets no
1126
- * column; its declaration is recorded in meta.weightOrigin.
1127
- * @param pending - the attribute as read
1124
+ * Whether an attribute was already declared (warning that the first declaration is kept), and
1125
+ * a warning when values that use it came before its declaration.
1126
+ * @param domain - node or edge
1127
+ * @param id - the attribute id
1128
+ * @param where - the report location
1129
+ * @returns true when the declaration is a duplicate and must be skipped
1128
1130
  */
1129
- declareOne(pending) {
1130
- const { report, sink, options } = this;
1131
- const { domain, dynamic, attrs } = pending;
1132
- const id = attrs.get("id");
1133
- const where = { line: pending.line, element: id ?? null };
1134
- if (id === void 0) {
1135
- report.error("validation-error", ATTRIBUTE_ID_CODE, "<attribute> without an id", where);
1136
- return;
1137
- }
1131
+ isDuplicateAttribute(domain, id, where) {
1132
+ const { report } = this;
1138
1133
  const tracked = domain === "node" ? this.nodeAttrs : this.edgeAttrs;
1139
1134
  if (tracked.has(id) || domain === "edge" && this.weightAttr !== null && this.weightAttr.id === id) {
1140
1135
  report.warning(
@@ -1143,7 +1138,7 @@ class GexfReader {
1143
1138
  `${domain} attribute "${id}" is declared twice; the first declaration is kept`,
1144
1139
  where
1145
1140
  );
1146
- return;
1141
+ return true;
1147
1142
  }
1148
1143
  if (this.unknownAttributes.has(`${domain}:${id}`)) {
1149
1144
  report.warning(
@@ -1153,6 +1148,62 @@ class GexfReader {
1153
1148
  where
1154
1149
  );
1155
1150
  }
1151
+ return false;
1152
+ }
1153
+ /**
1154
+ * Whether an edge attribute becomes THE weight: the first attribute of the weight's title does
1155
+ * (declared here), a later one only warns and stays a plain column.
1156
+ * @param attribute - the attribute's domain, id, display name, title and type
1157
+ * @param attribute.domain - node or edge
1158
+ * @param attribute.id - the attribute id
1159
+ * @param attribute.name - the column name
1160
+ * @param attribute.title - the declared title, or null
1161
+ * @param attribute.type - the declared type, or null
1162
+ * @param where - the report location
1163
+ * @returns true when the attribute was declared as the weight
1164
+ */
1165
+ claimsWeight(attribute, where) {
1166
+ const { report, sink, options } = this;
1167
+ const { domain, id, name, title, type } = attribute;
1168
+ if (domain !== "edge" || !isWeightField(name, options.weightFrom)) {
1169
+ return false;
1170
+ }
1171
+ if (this.weightAttr !== null) {
1172
+ report.warning(
1173
+ "validation-error",
1174
+ DUPLICATE_ATTRIBUTE_CODE,
1175
+ `edge attribute "${id}" is also titled ${name}; attribute "${this.weightAttr.id}" is the weight, "${id}" is kept as a column`,
1176
+ where
1177
+ );
1178
+ return false;
1179
+ }
1180
+ const declared = declareAttribute({ format: GEXF_FORMAT, id, title, type, long: options.long });
1181
+ for (const issue of declared.issues) {
1182
+ report.warning(issue.category, issue.code, issue.message, where);
1183
+ }
1184
+ this.weightAttr = { id, spec: declared.spec, table: INVALID_INDEX };
1185
+ sink.setMeta({ weightOrigin: { format: GEXF_FORMAT, id, title, type, namespace: null } });
1186
+ return true;
1187
+ }
1188
+ /**
1189
+ * Declare one `<attribute id title type>` with its `<default>` and `<options>` (design
1190
+ * sections 5.1, 5.5, 5.6). The edge attribute titled `weightFrom` is the weight and gets no
1191
+ * column; its declaration is recorded in meta.weightOrigin.
1192
+ * @param pending - the attribute as read
1193
+ */
1194
+ declareOne(pending) {
1195
+ const { report, sink, options } = this;
1196
+ const { domain, dynamic, attrs } = pending;
1197
+ const id = attrs.get("id");
1198
+ const where = { line: pending.line, element: id ?? null };
1199
+ if (id === void 0) {
1200
+ report.error("validation-error", ATTRIBUTE_ID_CODE, "<attribute> without an id", where);
1201
+ return;
1202
+ }
1203
+ const tracked = domain === "node" ? this.nodeAttrs : this.edgeAttrs;
1204
+ if (this.isDuplicateAttribute(domain, id, where)) {
1205
+ return;
1206
+ }
1156
1207
  const title = attrs.get("title") ?? null;
1157
1208
  const type = attrs.get("type") ?? null;
1158
1209
  if (type === null) {
@@ -1164,20 +1215,7 @@ class GexfReader {
1164
1215
  );
1165
1216
  }
1166
1217
  const name = title !== null && title.length > 0 ? title : id;
1167
- if (domain === "edge" && this.weightAttr !== null && isWeightField(name, options.weightFrom)) {
1168
- report.warning(
1169
- "validation-error",
1170
- DUPLICATE_ATTRIBUTE_CODE,
1171
- `edge attribute "${id}" is also titled ${name}; attribute "${this.weightAttr.id}" is the weight, "${id}" is kept as a column`,
1172
- where
1173
- );
1174
- } else if (domain === "edge" && isWeightField(name, options.weightFrom)) {
1175
- const declared2 = declareAttribute({ format: GEXF_FORMAT, id, title, type, long: options.long });
1176
- for (const issue of declared2.issues) {
1177
- report.warning(issue.category, issue.code, issue.message, where);
1178
- }
1179
- this.weightAttr = { id, spec: declared2.spec, table: INVALID_INDEX };
1180
- sink.setMeta({ weightOrigin: { format: GEXF_FORMAT, id, title, type, namespace: null } });
1218
+ if (this.claimsWeight({ domain, id, name, title, type }, where)) {
1181
1219
  return;
1182
1220
  }
1183
1221
  const declaredNames = domain === "node" ? this.declaredNodeNames : this.declaredEdgeNames;
@@ -1513,6 +1551,14 @@ class GexfReader {
1513
1551
  report.recordError(err, ref.where);
1514
1552
  }
1515
1553
  }
1554
+ this.resolveParentsLists(lists);
1555
+ }
1556
+ /**
1557
+ * Resolve the `<parents>` lists read so far into the parents column.
1558
+ * @param lists - the queued `<parents>` lists
1559
+ */
1560
+ resolveParentsLists(lists) {
1561
+ const { sink, report } = this;
1516
1562
  for (const ref of lists) {
1517
1563
  const indices = [];
1518
1564
  for (const id of ref.ids) {
@@ -1556,7 +1602,7 @@ class GexfReader {
1556
1602
  * @param line - the line
1557
1603
  */
1558
1604
  beginEdge(attrs, line) {
1559
- const { report, sink, options } = this;
1605
+ const { report, sink } = this;
1560
1606
  this.checkAbort();
1561
1607
  this.ctx.push(
1562
1608
  13
@@ -1611,18 +1657,7 @@ class GexfReader {
1611
1657
  try {
1612
1658
  const source = this.coerceId(sourceText, where);
1613
1659
  const target = this.coerceId(targetText, where);
1614
- if (!options.addMissingNodes) {
1615
- if (sink.indexOf(source) === INVALID_INDEX) {
1616
- throw new GraphFormatError("E_UNKNOWN_NODE", `edge references undeclared node "${sourceText}"`, {
1617
- id: source
1618
- });
1619
- }
1620
- if (sink.indexOf(target) === INVALID_INDEX) {
1621
- throw new GraphFormatError("E_UNKNOWN_NODE", `edge references undeclared node "${targetText}"`, {
1622
- id: target
1623
- });
1624
- }
1625
- }
1660
+ this.requireDeclaredEndpoints(source, target, sourceText, targetText);
1626
1661
  const weight = this.xmlWeight(attrs, where);
1627
1662
  const before = sink.edgeCount;
1628
1663
  index = this.resolver.addEdge(source, target, kind, weight, where);
@@ -1640,6 +1675,40 @@ class GexfReader {
1640
1675
  frame.mirror = this.resolver.lastMirror;
1641
1676
  frame.xmlWeight = attrs.get("weight") ?? null;
1642
1677
  this.edge = frame;
1678
+ this.writeEdgeColumns(attrs, index, idText, where);
1679
+ }
1680
+ /**
1681
+ * Throw when addMissingNodes is off and an endpoint names an undeclared node.
1682
+ * @param source - the coerced source id
1683
+ * @param target - the coerced target id
1684
+ * @param sourceText - the source as written
1685
+ * @param targetText - the target as written
1686
+ */
1687
+ requireDeclaredEndpoints(source, target, sourceText, targetText) {
1688
+ const { sink, options } = this;
1689
+ if (options.addMissingNodes) {
1690
+ return;
1691
+ }
1692
+ if (sink.indexOf(source) === INVALID_INDEX) {
1693
+ throw new GraphFormatError("E_UNKNOWN_NODE", `edge references undeclared node "${sourceText}"`, {
1694
+ id: source
1695
+ });
1696
+ }
1697
+ if (sink.indexOf(target) === INVALID_INDEX) {
1698
+ throw new GraphFormatError("E_UNKNOWN_NODE", `edge references undeclared node "${targetText}"`, {
1699
+ id: target
1700
+ });
1701
+ }
1702
+ }
1703
+ /**
1704
+ * Write the id, label, kind and lifetime columns of an added edge; a failure is reported.
1705
+ * @param attrs - the edge's attributes
1706
+ * @param index - the edge's index
1707
+ * @param idText - the edge's id, or undefined
1708
+ * @param where - the edge's location
1709
+ */
1710
+ writeEdgeColumns(attrs, index, idText, where) {
1711
+ const { report, sink } = this;
1643
1712
  try {
1644
1713
  if (idText !== void 0) {
1645
1714
  this.edgeIdColumn.set(sink, report, index, idText, where);
@@ -2293,35 +2362,18 @@ class GexfReader {
2293
2362
  case "color":
2294
2363
  columns.color.set(sink, report, index, parseColor(attrs), where);
2295
2364
  break;
2296
- case "position": {
2297
- const x = vizNumber(attrs, "x");
2298
- const y = vizNumber(attrs, "y");
2299
- const z = attrs.has("z") ? vizNumber(attrs, "z") : 0;
2300
- this.positionColumn ??= new LazyColumn("node", {
2301
- ...NODE_DECLS.position,
2302
- extra: { ...NODE_DECLS.position.extra, sourceDims: attrs.has("z") ? 3 : 2 }
2303
- });
2304
- this.positionColumn.set(sink, report, index, [x, y, z], where);
2365
+ case "position":
2366
+ this.writePosition(attrs, index, where);
2305
2367
  break;
2306
- }
2307
2368
  case "size":
2308
2369
  this.sizeColumn.set(sink, report, index, vizNumber(attrs, "value"), where);
2309
2370
  break;
2310
2371
  case "thickness":
2311
2372
  this.thicknessColumn.set(sink, report, index, vizNumber(attrs, "value"), where);
2312
2373
  break;
2313
- case "shape": {
2314
- const value = attrs.get("value");
2315
- if (value === void 0) {
2316
- throw new GraphFormatError("E_COLUMN_TYPE", "<viz:shape> without a value", { element: name });
2317
- }
2318
- columns.shape.set(sink, report, index, value, where);
2319
- const uri = attrs.get("uri");
2320
- if (domain === "node" && uri !== void 0) {
2321
- this.shapeUriColumn.set(sink, report, index, uri, where);
2322
- }
2374
+ case "shape":
2375
+ this.writeShape(name, attrs, domain, index, where);
2323
2376
  break;
2324
- }
2325
2377
  default:
2326
2378
  break;
2327
2379
  }
@@ -2332,6 +2384,43 @@ class GexfReader {
2332
2384
  report.warning("validation-error", VIZ_VALUE_CODE, `<${name}> skipped: ${err.message}`, where);
2333
2385
  }
2334
2386
  }
2387
+ /**
2388
+ * Write a `<viz:position>`.
2389
+ * @param attrs - its attributes
2390
+ * @param index - the node's index
2391
+ * @param where - the node's location
2392
+ */
2393
+ writePosition(attrs, index, where) {
2394
+ const x = vizNumber(attrs, "x");
2395
+ const y = vizNumber(attrs, "y");
2396
+ const z = attrs.has("z") ? vizNumber(attrs, "z") : 0;
2397
+ this.positionColumn ??= new LazyColumn("node", {
2398
+ ...NODE_DECLS.position,
2399
+ extra: { ...NODE_DECLS.position.extra, sourceDims: attrs.has("z") ? 3 : 2 }
2400
+ });
2401
+ this.positionColumn.set(this.sink, this.report, index, [x, y, z], where);
2402
+ }
2403
+ /**
2404
+ * Write a `<viz:shape>` and, on a node, its `uri`.
2405
+ * @param name - the element name as written
2406
+ * @param attrs - its attributes
2407
+ * @param domain - node or edge
2408
+ * @param index - the element's index
2409
+ * @param where - the element's location
2410
+ */
2411
+ writeShape(name, attrs, domain, index, where) {
2412
+ const { sink, report } = this;
2413
+ const columns = domain === "node" ? this.nodeColumns : this.edgeColumns;
2414
+ const value = attrs.get("value");
2415
+ if (value === void 0) {
2416
+ throw new GraphFormatError("E_COLUMN_TYPE", "<viz:shape> without a value", { element: name });
2417
+ }
2418
+ columns.shape.set(sink, report, index, value, where);
2419
+ const uri = attrs.get("uri");
2420
+ if (domain === "node" && uri !== void 0) {
2421
+ this.shapeUriColumn.set(sink, report, index, uri, where);
2422
+ }
2423
+ }
2335
2424
  // ---------------------------------------------------------------- helpers
2336
2425
  /**
2337
2426
  * Report an element the schema does not define at this place and skip its subtree.
@@ -3376,6 +3465,18 @@ function lifetimeAttrs(roles, row, plan) {
3376
3465
  }
3377
3466
  return out;
3378
3467
  }
3468
+ function spellBounds(s, e, open, plan) {
3469
+ let attrs = "";
3470
+ if (Number.isFinite(s)) {
3471
+ const name = (open & OPEN_START) === 0 ? "start" : "startopen";
3472
+ attrs += ` ${name}="${escapeXmlAttribute(formatTimeValue(s, plan.timeFormat))}"`;
3473
+ }
3474
+ if (Number.isFinite(e)) {
3475
+ const name = (open & OPEN_END) === 0 ? "end" : "endopen";
3476
+ attrs += ` ${name}="${escapeXmlAttribute(formatTimeValue(e, plan.timeFormat))}"`;
3477
+ }
3478
+ return attrs;
3479
+ }
3379
3480
  function spellsElement(roles, row, plan, indent) {
3380
3481
  const pairs = [];
3381
3482
  if (roles.spells?.isSet(row)) {
@@ -3396,16 +3497,7 @@ function spellsElement(roles, row, plan, indent) {
3396
3497
  let out = `${indent}<spells>
3397
3498
  `;
3398
3499
  for (const [s, e, open] of pairs) {
3399
- let attrs = "";
3400
- if (Number.isFinite(s)) {
3401
- const name = (open & OPEN_START) === 0 ? "start" : "startopen";
3402
- attrs += ` ${name}="${escapeXmlAttribute(formatTimeValue(s, plan.timeFormat))}"`;
3403
- }
3404
- if (Number.isFinite(e)) {
3405
- const name = (open & OPEN_END) === 0 ? "end" : "endopen";
3406
- attrs += ` ${name}="${escapeXmlAttribute(formatTimeValue(e, plan.timeFormat))}"`;
3407
- }
3408
- out += `${indent} <spell${attrs}/>
3500
+ out += `${indent} <spell${spellBounds(s, e, open, plan)}/>
3409
3501
  `;
3410
3502
  }
3411
3503
  return `${out}${indent}</spells>
@@ -3739,18 +3831,8 @@ function metaElement(meta) {
3739
3831
  ${body} </meta>
3740
3832
  `;
3741
3833
  }
3742
- function graphStart(snapshot, plan) {
3743
- const { meta } = snapshot;
3744
- let attrs = ` defaultedgetype="${defaultEdgeType(snapshot)}"`;
3745
- let mode = meta.mode ?? "static";
3746
- if (plan.temporal && mode === "static") {
3747
- mode = "dynamic";
3748
- }
3749
- if (plan.version === "1.2" && mode === "slice") {
3750
- mode = "dynamic";
3751
- }
3752
- attrs += ` mode="${mode}"`;
3753
- let { idType } = meta;
3834
+ function graphIdTypeAttr(snapshot) {
3835
+ let { idType } = snapshot.meta;
3754
3836
  if (idType === null) {
3755
3837
  const { kind } = snapshot.ids;
3756
3838
  if (kind === "string") {
@@ -3759,17 +3841,9 @@ function graphStart(snapshot, plan) {
3759
3841
  idType = "integer";
3760
3842
  }
3761
3843
  }
3762
- if (idType === "integer" || idType === "string") {
3763
- attrs += ` idtype="${idType}"`;
3764
- }
3765
- if (plan.timeFormat !== null) {
3766
- attrs += ` timeformat="${plan.timeFormat}"`;
3767
- } else if (plan.temporal) {
3768
- attrs += ' timeformat="double"';
3769
- }
3770
- if (plan.version === "1.3" && plan.timeRepresentation !== null) {
3771
- attrs += ` timerepresentation="${plan.timeRepresentation}"`;
3772
- }
3844
+ return idType === "integer" || idType === "string" ? ` idtype="${idType}"` : "";
3845
+ }
3846
+ function graphHeaderAttrs(snapshot, plan) {
3773
3847
  const timestamp = graphExtraText(snapshot, "timestamp");
3774
3848
  const header = {
3775
3849
  start: graphExtraText(snapshot, "start"),
@@ -3781,11 +3855,35 @@ function graphStart(snapshot, plan) {
3781
3855
  header.end ??= timestamp;
3782
3856
  header.timestamp = null;
3783
3857
  }
3858
+ let attrs = "";
3784
3859
  for (const [key, value] of Object.entries(header)) {
3785
3860
  if (value !== null) {
3786
3861
  attrs += ` ${key}="${escapeXmlAttribute(value)}"`;
3787
3862
  }
3788
3863
  }
3864
+ return attrs;
3865
+ }
3866
+ function graphStart(snapshot, plan) {
3867
+ const { meta } = snapshot;
3868
+ let attrs = ` defaultedgetype="${defaultEdgeType(snapshot)}"`;
3869
+ let mode = meta.mode ?? "static";
3870
+ if (plan.temporal && mode === "static") {
3871
+ mode = "dynamic";
3872
+ }
3873
+ if (plan.version === "1.2" && mode === "slice") {
3874
+ mode = "dynamic";
3875
+ }
3876
+ attrs += ` mode="${mode}"`;
3877
+ attrs += graphIdTypeAttr(snapshot);
3878
+ if (plan.timeFormat !== null) {
3879
+ attrs += ` timeformat="${plan.timeFormat}"`;
3880
+ } else if (plan.temporal) {
3881
+ attrs += ' timeformat="double"';
3882
+ }
3883
+ if (plan.version === "1.3" && plan.timeRepresentation !== null) {
3884
+ attrs += ` timerepresentation="${plan.timeRepresentation}"`;
3885
+ }
3886
+ attrs += graphHeaderAttrs(snapshot, plan);
3789
3887
  return ` <graph${attrs}>
3790
3888
  `;
3791
3889
  }