@graphty/graph-io 0.3.18 → 0.3.20

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 (235) hide show
  1. package/README.md +80 -2
  2. package/dist/chunks/{escape-D-gZWO26.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-GAdltGmC.js → export-Bh60Dv-n.js} +7 -252
  5. package/dist/chunks/export-Bh60Dv-n.js.map +1 -0
  6. package/dist/chunks/exporter-BGrsWamJ.js +736 -0
  7. package/dist/chunks/exporter-BGrsWamJ.js.map +1 -0
  8. package/dist/chunks/exporter-DIeGJXAZ.js +834 -0
  9. package/dist/chunks/exporter-DIeGJXAZ.js.map +1 -0
  10. package/dist/chunks/{importer-Br_QeAeE.js → importer-BWY2FFc5.js} +28 -6
  11. package/dist/chunks/importer-BWY2FFc5.js.map +1 -0
  12. package/dist/chunks/importer-BaQpCEcJ.js +2194 -0
  13. package/dist/chunks/importer-BaQpCEcJ.js.map +1 -0
  14. package/dist/chunks/importer-DD-xv9_Y.js +1471 -0
  15. package/dist/chunks/importer-DD-xv9_Y.js.map +1 -0
  16. package/dist/chunks/{importer-aNJfe0qu.js → importer-DEcKhsmQ.js} +2 -2
  17. package/dist/chunks/{importer-aNJfe0qu.js.map → importer-DEcKhsmQ.js.map} +1 -1
  18. package/dist/chunks/{importer-DHagxvDD.js → importer-DIrbbnAf.js} +6 -4
  19. package/dist/chunks/{importer-DHagxvDD.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-Du5crN9l.js → importer-Wv4C4gaF.js} +278 -82
  23. package/dist/chunks/importer-Wv4C4gaF.js.map +1 -0
  24. package/dist/chunks/importer-vi3bSdtw.js +1713 -0
  25. package/dist/chunks/importer-vi3bSdtw.js.map +1 -0
  26. package/dist/chunks/{importer-d0uQxFp6.js → importer-zGLo8Dg_.js} +6 -4
  27. package/dist/chunks/{importer-d0uQxFp6.js.map → importer-zGLo8Dg_.js.map} +1 -1
  28. package/dist/chunks/json-elements-DDS8N2Dd.js +779 -0
  29. package/dist/chunks/json-elements-DDS8N2Dd.js.map +1 -0
  30. package/dist/chunks/{records-Bk9jgodz.js → records-dbRkxwaq.js} +2 -2
  31. package/dist/chunks/{records-Bk9jgodz.js.map → records-dbRkxwaq.js.map} +1 -1
  32. package/dist/chunks/{report-BOk0p5y8.js → report-B1z4WT9e.js} +143 -111
  33. package/dist/chunks/{report-BOk0p5y8.js.map → report-B1z4WT9e.js.map} +1 -1
  34. package/dist/chunks/weights-Dzba96G3.js +176 -0
  35. package/dist/chunks/weights-Dzba96G3.js.map +1 -0
  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 -4
  39. package/dist/csv.js.map +1 -1
  40. package/dist/cx.d.ts +1 -0
  41. package/dist/cx.js +6 -0
  42. package/dist/cx.js.map +1 -0
  43. package/dist/cx2.d.ts +1 -0
  44. package/dist/cx2.js +10 -0
  45. package/dist/cx2.js.map +1 -0
  46. package/dist/cys.d.ts +1 -0
  47. package/dist/cys.js +6 -0
  48. package/dist/cys.js.map +1 -0
  49. package/dist/dot.js +1 -1
  50. package/dist/gexf.js +16 -4
  51. package/dist/gexf.js.map +1 -1
  52. package/dist/gml.js +13 -14
  53. package/dist/gml.js.map +1 -1
  54. package/dist/graph-io.js +302 -399
  55. package/dist/graph-io.js.map +1 -1
  56. package/dist/graphml.js +1 -1
  57. package/dist/json.js +1 -1
  58. package/dist/neo4j.js +6 -4
  59. package/dist/neo4j.js.map +1 -1
  60. package/dist/obo.js +1 -1
  61. package/dist/pajek.js +1 -1
  62. package/dist/src/common/cell-budget.d.ts +84 -0
  63. package/dist/src/common/cell-budget.d.ts.map +1 -0
  64. package/dist/src/common/cell-budget.js +138 -0
  65. package/dist/src/common/cell-budget.js.map +1 -0
  66. package/dist/src/common/input.d.ts +10 -0
  67. package/dist/src/common/input.d.ts.map +1 -1
  68. package/dist/src/common/input.js +39 -0
  69. package/dist/src/common/input.js.map +1 -1
  70. package/dist/src/common/json-elements.d.ts +286 -0
  71. package/dist/src/common/json-elements.d.ts.map +1 -0
  72. package/dist/src/common/json-elements.js +926 -0
  73. package/dist/src/common/json-elements.js.map +1 -0
  74. package/dist/src/common/options.d.ts +6 -0
  75. package/dist/src/common/options.d.ts.map +1 -1
  76. package/dist/src/common/options.js +1 -1
  77. package/dist/src/common/options.js.map +1 -1
  78. package/dist/src/common/xml.d.ts +37 -3
  79. package/dist/src/common/xml.d.ts.map +1 -1
  80. package/dist/src/common/xml.js +86 -6
  81. package/dist/src/common/xml.js.map +1 -1
  82. package/dist/src/common/zip.d.ts +92 -0
  83. package/dist/src/common/zip.d.ts.map +1 -0
  84. package/dist/src/common/zip.js +399 -0
  85. package/dist/src/common/zip.js.map +1 -0
  86. package/dist/src/formats/cx/importer.d.ts +133 -0
  87. package/dist/src/formats/cx/importer.d.ts.map +1 -0
  88. package/dist/src/formats/cx/importer.js +2220 -0
  89. package/dist/src/formats/cx/importer.js.map +1 -0
  90. package/dist/src/formats/cx/index.d.ts +7 -0
  91. package/dist/src/formats/cx/index.d.ts.map +1 -0
  92. package/dist/src/formats/cx/index.js +7 -0
  93. package/dist/src/formats/cx/index.js.map +1 -0
  94. package/dist/src/formats/cx2/exporter.d.ts +59 -0
  95. package/dist/src/formats/cx2/exporter.d.ts.map +1 -0
  96. package/dist/src/formats/cx2/exporter.js +864 -0
  97. package/dist/src/formats/cx2/exporter.js.map +1 -0
  98. package/dist/src/formats/cx2/importer.d.ts +169 -0
  99. package/dist/src/formats/cx2/importer.d.ts.map +1 -0
  100. package/dist/src/formats/cx2/importer.js +1652 -0
  101. package/dist/src/formats/cx2/importer.js.map +1 -0
  102. package/dist/src/formats/cx2/index.d.ts +7 -0
  103. package/dist/src/formats/cx2/index.d.ts.map +1 -0
  104. package/dist/src/formats/cx2/index.js +7 -0
  105. package/dist/src/formats/cx2/index.js.map +1 -0
  106. package/dist/src/formats/cys/constants.d.ts +68 -0
  107. package/dist/src/formats/cys/constants.d.ts.map +1 -0
  108. package/dist/src/formats/cys/constants.js +76 -0
  109. package/dist/src/formats/cys/constants.js.map +1 -0
  110. package/dist/src/formats/cys/importer.d.ts +38 -0
  111. package/dist/src/formats/cys/importer.d.ts.map +1 -0
  112. package/dist/src/formats/cys/importer.js +830 -0
  113. package/dist/src/formats/cys/importer.js.map +1 -0
  114. package/dist/src/formats/cys/index.d.ts +7 -0
  115. package/dist/src/formats/cys/index.d.ts.map +1 -0
  116. package/dist/src/formats/cys/index.js +7 -0
  117. package/dist/src/formats/cys/index.js.map +1 -0
  118. package/dist/src/formats/cys/session.d.ts +132 -0
  119. package/dist/src/formats/cys/session.d.ts.map +1 -0
  120. package/dist/src/formats/cys/session.js +315 -0
  121. package/dist/src/formats/cys/session.js.map +1 -0
  122. package/dist/src/formats/cys/tables.d.ts +90 -0
  123. package/dist/src/formats/cys/tables.d.ts.map +1 -0
  124. package/dist/src/formats/cys/tables.js +293 -0
  125. package/dist/src/formats/cys/tables.js.map +1 -0
  126. package/dist/src/formats/dot/exporter.d.ts +2 -0
  127. package/dist/src/formats/dot/exporter.d.ts.map +1 -1
  128. package/dist/src/formats/dot/exporter.js +12 -0
  129. package/dist/src/formats/dot/exporter.js.map +1 -1
  130. package/dist/src/formats/dot/importer.js +6 -2
  131. package/dist/src/formats/dot/importer.js.map +1 -1
  132. package/dist/src/formats/gexf/exporter.d.ts +2 -0
  133. package/dist/src/formats/gexf/exporter.d.ts.map +1 -1
  134. package/dist/src/formats/gexf/exporter.js +6 -0
  135. package/dist/src/formats/gexf/exporter.js.map +1 -1
  136. package/dist/src/formats/gexf/importer.d.ts +0 -2
  137. package/dist/src/formats/gexf/importer.d.ts.map +1 -1
  138. package/dist/src/formats/gexf/importer.js +1 -3
  139. package/dist/src/formats/gexf/importer.js.map +1 -1
  140. package/dist/src/formats/gexf/index.d.ts +1 -1
  141. package/dist/src/formats/gexf/index.js +2 -2
  142. package/dist/src/formats/gexf/index.js.map +1 -1
  143. package/dist/src/formats/gml/exporter.d.ts +0 -8
  144. package/dist/src/formats/gml/exporter.d.ts.map +1 -1
  145. package/dist/src/formats/gml/exporter.js +8 -18
  146. package/dist/src/formats/gml/exporter.js.map +1 -1
  147. package/dist/src/formats/json/importer.d.ts.map +1 -1
  148. package/dist/src/formats/json/importer.js +6 -104
  149. package/dist/src/formats/json/importer.js.map +1 -1
  150. package/dist/src/formats/xgmml/columns.d.ts +152 -0
  151. package/dist/src/formats/xgmml/columns.d.ts.map +1 -0
  152. package/dist/src/formats/xgmml/columns.js +593 -0
  153. package/dist/src/formats/xgmml/columns.js.map +1 -0
  154. package/dist/src/formats/xgmml/constants.d.ts +196 -0
  155. package/dist/src/formats/xgmml/constants.d.ts.map +1 -0
  156. package/dist/src/formats/xgmml/constants.js +197 -0
  157. package/dist/src/formats/xgmml/constants.js.map +1 -0
  158. package/dist/src/formats/xgmml/document.d.ts +361 -0
  159. package/dist/src/formats/xgmml/document.d.ts.map +1 -0
  160. package/dist/src/formats/xgmml/document.js +695 -0
  161. package/dist/src/formats/xgmml/document.js.map +1 -0
  162. package/dist/src/formats/xgmml/emit.d.ts +341 -0
  163. package/dist/src/formats/xgmml/emit.d.ts.map +1 -0
  164. package/dist/src/formats/xgmml/emit.js +1275 -0
  165. package/dist/src/formats/xgmml/emit.js.map +1 -0
  166. package/dist/src/formats/xgmml/exporter.d.ts +24 -0
  167. package/dist/src/formats/xgmml/exporter.d.ts.map +1 -0
  168. package/dist/src/formats/xgmml/exporter.js +999 -0
  169. package/dist/src/formats/xgmml/exporter.js.map +1 -0
  170. package/dist/src/formats/xgmml/importer.d.ts +58 -0
  171. package/dist/src/formats/xgmml/importer.d.ts.map +1 -0
  172. package/dist/src/formats/xgmml/importer.js +360 -0
  173. package/dist/src/formats/xgmml/importer.js.map +1 -0
  174. package/dist/src/formats/xgmml/index.d.ts +8 -0
  175. package/dist/src/formats/xgmml/index.d.ts.map +1 -0
  176. package/dist/src/formats/xgmml/index.js +8 -0
  177. package/dist/src/formats/xgmml/index.js.map +1 -0
  178. package/dist/src/formats/xgmml/values.d.ts +60 -0
  179. package/dist/src/formats/xgmml/values.d.ts.map +1 -0
  180. package/dist/src/formats/xgmml/values.js +148 -0
  181. package/dist/src/formats/xgmml/values.js.map +1 -0
  182. package/dist/src/index.d.ts +4 -0
  183. package/dist/src/index.d.ts.map +1 -1
  184. package/dist/src/index.js +4 -0
  185. package/dist/src/index.js.map +1 -1
  186. package/dist/src/registry.d.ts +7 -0
  187. package/dist/src/registry.d.ts.map +1 -1
  188. package/dist/src/registry.js +30 -10
  189. package/dist/src/registry.js.map +1 -1
  190. package/dist/src/sniff.d.ts +1 -1
  191. package/dist/src/sniff.d.ts.map +1 -1
  192. package/dist/src/sniff.js +4 -0
  193. package/dist/src/sniff.js.map +1 -1
  194. package/dist/xgmml.d.ts +1 -0
  195. package/dist/xgmml.js +9 -0
  196. package/dist/xgmml.js.map +1 -0
  197. package/package.json +25 -2
  198. package/src/common/cell-budget.ts +170 -0
  199. package/src/common/input.ts +40 -0
  200. package/src/common/json-elements.ts +1147 -0
  201. package/src/common/options.ts +1 -1
  202. package/src/common/xml.ts +127 -6
  203. package/src/common/zip.ts +472 -0
  204. package/src/formats/cx/importer.ts +2733 -0
  205. package/src/formats/cx/index.ts +7 -0
  206. package/src/formats/cx2/exporter.ts +1036 -0
  207. package/src/formats/cx2/importer.ts +2187 -0
  208. package/src/formats/cx2/index.ts +7 -0
  209. package/src/formats/cys/constants.ts +99 -0
  210. package/src/formats/cys/importer.ts +1100 -0
  211. package/src/formats/cys/index.ts +7 -0
  212. package/src/formats/cys/session.ts +428 -0
  213. package/src/formats/cys/tables.ts +400 -0
  214. package/src/formats/dot/exporter.ts +17 -0
  215. package/src/formats/dot/importer.ts +6 -2
  216. package/src/formats/gexf/exporter.ts +11 -0
  217. package/src/formats/gexf/importer.ts +1 -2
  218. package/src/formats/gexf/index.ts +1 -1
  219. package/src/formats/gml/exporter.ts +8 -19
  220. package/src/formats/json/importer.ts +6 -105
  221. package/src/formats/xgmml/columns.ts +747 -0
  222. package/src/formats/xgmml/constants.ts +265 -0
  223. package/src/formats/xgmml/document.ts +975 -0
  224. package/src/formats/xgmml/emit.ts +1563 -0
  225. package/src/formats/xgmml/exporter.ts +1215 -0
  226. package/src/formats/xgmml/importer.ts +491 -0
  227. package/src/formats/xgmml/index.ts +8 -0
  228. package/src/formats/xgmml/values.ts +183 -0
  229. package/src/index.ts +19 -0
  230. package/src/registry.ts +46 -15
  231. package/src/sniff.ts +18 -1
  232. package/dist/chunks/escape-D-gZWO26.js.map +0 -1
  233. package/dist/chunks/importer-Br_QeAeE.js.map +0 -1
  234. package/dist/chunks/importer-Du5crN9l.js.map +0 -1
  235. package/dist/chunks/writer-GAdltGmC.js.map +0 -1
@@ -0,0 +1,736 @@
1
+ import { GraphFormatError } from "@graphty/graph-format";
2
+ import { V as resolveExportOptions, X as pairFolding } from "./report-B1z4WT9e.js";
3
+ import { c as capabilities, L as LOSS, a as checkCapabilities } from "./export-Bh60Dv-n.js";
4
+ import { i as isRecord, P as POSITION_COLUMN } from "./json-elements-DDS8N2Dd.js";
5
+ import { e as explicitWeights } from "./weights-Dzba96G3.js";
6
+ import { j as joinText, e as encodeChunks } from "./writer-C7flM-Ih.js";
7
+ import { a as CX2_FORMAT, O as ORIGINAL_ID_ATTRIBUTE, b as cx2Type, B as BYPASS_NAMESPACE } from "./importer-vi3bSdtw.js";
8
+ const CX2_LOSS = Object.freeze({
9
+ /** Every edge is written directed: an undirected snapshot, or the undirected pairs of a mixed one. */
10
+ UNDIRECTED_AS_DIRECTED: "W_CX2_UNDIRECTED_AS_DIRECTED",
11
+ /** A nested (json) column is written as a string attribute holding its JSON text. */
12
+ JSON_AS_STRING: "W_CX2_JSON_AS_STRING",
13
+ /** NaN and the infinities cannot be written; they are written as null and read back unset. */
14
+ NONFINITE_AS_NULL: "W_CX2_NONFINITE_AS_NULL",
15
+ /** A mutual pair is written as two directed edges without its mark. */
16
+ MUTUAL_EXPANDED: LOSS.MUTUAL_EXPANDED,
17
+ /** A plain edge column named like the weight key reads back as THE weight (or is skipped when weights are written). */
18
+ WEIGHT_KEY_CLASH: LOSS.WEIGHT_KEY_CLASH,
19
+ /** A parent / parents column: CX2 has no containment. */
20
+ HIERARCHY_DROPPED: LOSS.HIERARCHY,
21
+ /** A start / end / timestamp column: CX2 has no time. */
22
+ TEMPORAL_DROPPED: LOSS.TEMPORAL,
23
+ /** A role column written as a plain attribute. */
24
+ ROLE_DROPPED: LOSS.ROLE,
25
+ /** A dtype CX2 declares as another (f32 as double, u32 as long, dict as string, ...). */
26
+ DTYPE_UNSUPPORTED: LOSS.DTYPE,
27
+ /** Node ids that are not integers under the default sanitizeIds "error": export() throws E_INVALID_ID. */
28
+ ID_CHARSET: LOSS.ID_CHARSET,
29
+ /** Node ids that are not integers under sanitizeIds "mangle": renumbered, originals kept. */
30
+ ID_MANGLED: LOSS.ID_MANGLED,
31
+ /** Edges without a usable id get generated integer ids. */
32
+ EDGE_IDS_GENERATED: LOSS.EDGE_IDS_GENERATED
33
+ });
34
+ const CX2_CAPABILITIES = capabilities({
35
+ mixedDirection: false,
36
+ multiEdges: true,
37
+ selfLoops: true,
38
+ edgeIds: "required",
39
+ idCharset: "integer",
40
+ dtypes: ["string", "f64", "i32", "bool"],
41
+ components: false,
42
+ lists: true,
43
+ json: false,
44
+ defaults: true,
45
+ options: false,
46
+ hierarchy: false,
47
+ temporal: "none",
48
+ graphAttributes: true,
49
+ positions: true,
50
+ viz: false
51
+ });
52
+ const SLOT_ROLES = /* @__PURE__ */ new Set(["label", "position", "id"]);
53
+ const ROLE_NAMES = Object.freeze({
54
+ label: "name",
55
+ position: POSITION_COLUMN
56
+ });
57
+ const SKIPPED_ROLES = /* @__PURE__ */ new Set([
58
+ "directed",
59
+ "pair",
60
+ "mutual",
61
+ "weight",
62
+ "timeText",
63
+ "originalId",
64
+ "parent",
65
+ "parents",
66
+ "start",
67
+ "end",
68
+ "timestamp",
69
+ "timestamps",
70
+ "spells",
71
+ "open",
72
+ "spellsOpen",
73
+ "position",
74
+ "color",
75
+ "size",
76
+ "shape",
77
+ "thickness"
78
+ ]);
79
+ const CORE_ASPECTS = /* @__PURE__ */ new Set([
80
+ "nodes",
81
+ "edges",
82
+ "attributeDeclarations",
83
+ "networkAttributes",
84
+ "nodeBypasses",
85
+ "edgeBypasses",
86
+ "metaData",
87
+ "status"
88
+ ]);
89
+ const WEIGHT_ATTRIBUTE = "weight";
90
+ const RAW = `${String.fromCharCode(0)}cx2:`;
91
+ const RAW_JSON = /"\\u0000cx2:(-?[0-9]+)"/g;
92
+ const BIG_INTEGER_TEXT = /^-?[1-9][0-9]{15,}$/;
93
+ function writableId(id) {
94
+ return typeof id === "number" ? Number.isSafeInteger(id) : BIG_INTEGER_TEXT.test(id) && !Number.isSafeInteger(Number(id));
95
+ }
96
+ function writtenIds(snapshot, mode) {
97
+ const { ids } = snapshot;
98
+ const bad = [];
99
+ const used = /* @__PURE__ */ new Set();
100
+ for (let i = 0; i < ids.size; i++) {
101
+ const id = ids.idOf(i);
102
+ if (!writableId(id)) {
103
+ bad.push(i);
104
+ } else if (typeof id === "number") {
105
+ used.add(id);
106
+ }
107
+ }
108
+ if (bad.length > 0 && mode === "error") {
109
+ const first = ids.idOf(bad[0]);
110
+ throw new GraphFormatError(
111
+ "E_INVALID_ID",
112
+ `${bad.length} node id(s) cannot be written as CX2 integers (first: ${JSON.stringify(first)} at index ${bad[0]}); pass sanitizeIds: "mangle" to rewrite them`,
113
+ { reason: "charset", charset: "integer", count: bad.length, index: bad[0] }
114
+ );
115
+ }
116
+ const renumbered = /* @__PURE__ */ new Map();
117
+ let next = 0;
118
+ for (const i of bad) {
119
+ while (used.has(next)) {
120
+ next++;
121
+ }
122
+ used.add(next);
123
+ renumbered.set(i, next);
124
+ }
125
+ return {
126
+ changed: bad.length,
127
+ idAt: (i) => {
128
+ const id = renumbered.get(i) ?? ids.idOf(i);
129
+ return typeof id === "string" ? `${RAW}${id}` : id;
130
+ },
131
+ isChanged: (i) => renumbered.has(i),
132
+ originalAt: (i) => ids.idOf(i)
133
+ };
134
+ }
135
+ function unwritableIds(snapshot) {
136
+ let count = 0;
137
+ for (let i = 0; i < snapshot.ids.size; i++) {
138
+ if (!writableId(snapshot.ids.idOf(i))) {
139
+ count++;
140
+ }
141
+ }
142
+ return count;
143
+ }
144
+ function isBypass(column) {
145
+ return column.meta.origin?.namespace === BYPASS_NAMESPACE;
146
+ }
147
+ function isZ(column) {
148
+ return column.meta.extra.cytoscape === "z";
149
+ }
150
+ function scalarType(dtype, longOrigin) {
151
+ switch (dtype) {
152
+ case "f64":
153
+ return longOrigin ? "long" : "double";
154
+ case "f32":
155
+ return "double";
156
+ case "i32":
157
+ case "u8":
158
+ return "integer";
159
+ case "u32":
160
+ return "long";
161
+ case "bool":
162
+ return "boolean";
163
+ default:
164
+ return "string";
165
+ }
166
+ }
167
+ function allIntegral(column) {
168
+ for (let i = 0; i < column.length; i++) {
169
+ if (column.isSet(i) && !Number.isSafeInteger(column.value(i))) {
170
+ return false;
171
+ }
172
+ }
173
+ return true;
174
+ }
175
+ function declaredType(column) {
176
+ const { meta } = column;
177
+ const origin = meta.origin?.type ?? null;
178
+ const longOrigin = origin !== null && /long$/.test(origin) && (meta.dtype !== "f64" || allIntegral(column));
179
+ if (meta.dtype === "list") {
180
+ return meta.itemDtype === null || meta.itemDtype === "json" ? "string" : `list_of_${scalarType(meta.itemDtype, longOrigin)}`;
181
+ }
182
+ return meta.components > 1 ? `list_of_${scalarType(meta.dtype, false)}` : scalarType(meta.dtype, longOrigin);
183
+ }
184
+ function nonFiniteCount(column) {
185
+ const { dtype, itemDtype } = column.meta;
186
+ const numeric = dtype === "f32" || dtype === "f64" || dtype === "list" && (itemDtype === "f32" || itemDtype === "f64");
187
+ if (!numeric) {
188
+ return 0;
189
+ }
190
+ let count = 0;
191
+ for (let i = 0; i < column.length; i++) {
192
+ if (!column.isSet(i)) {
193
+ continue;
194
+ }
195
+ const value = column.value(i);
196
+ if (dtype === "list") {
197
+ if (value.some((v) => !Number.isFinite(v))) {
198
+ count++;
199
+ }
200
+ } else if (!Number.isFinite(value)) {
201
+ count++;
202
+ }
203
+ }
204
+ return count;
205
+ }
206
+ function planAttributes(table, skip, rename, reserved = /* @__PURE__ */ new Set()) {
207
+ const plans = [];
208
+ const used = new Set(reserved);
209
+ const candidates = [...table].filter((c) => !skip(c));
210
+ for (const column of candidates) {
211
+ used.add(rename(column));
212
+ }
213
+ for (const column of candidates) {
214
+ const name = rename(column);
215
+ const { origin } = column.meta;
216
+ let key = name;
217
+ const alias = origin?.format === CX2_FORMAT && typeof origin.id === "string" ? origin.id : null;
218
+ if (alias !== null && alias.length > 0 && alias !== name && !used.has(alias)) {
219
+ key = alias;
220
+ used.add(alias);
221
+ }
222
+ plans.push({ column, name, key, d: declaredType(column), jsonText: column.meta.dtype === "json" });
223
+ }
224
+ return plans;
225
+ }
226
+ function plan(snapshot, common) {
227
+ const notes = [];
228
+ let fatal = null;
229
+ const note = (code, message, column = null, count = null) => {
230
+ notes.push(Object.freeze({ code, message, column, count }));
231
+ };
232
+ const bypassNames = new Set(
233
+ [...snapshot.nodes, ...snapshot.edges].filter((c) => isBypass(c) || isZ(c)).map((c) => c.meta.name)
234
+ );
235
+ for (const gen of checkCapabilities(snapshot, CX2_CAPABILITIES, common, {
236
+ roles: SLOT_ROLES,
237
+ roleNames: ROLE_NAMES
238
+ })) {
239
+ if (gen.column !== null && bypassNames.has(gen.column) && (gen.code === LOSS.JSON || gen.code === LOSS.DTYPE)) {
240
+ continue;
241
+ }
242
+ if (gen.code === LOSS.ID_CHARSET || gen.code === LOSS.ID_MANGLED) {
243
+ continue;
244
+ }
245
+ if (gen.code === LOSS.JSON) {
246
+ note(
247
+ CX2_LOSS.JSON_AS_STRING,
248
+ `${gen.column === null ? "a column" : `column "${gen.column}"`} holds nested values; written as a string attribute holding their JSON text`,
249
+ gen.column,
250
+ gen.count
251
+ );
252
+ continue;
253
+ }
254
+ if (gen.code === LOSS.MIXED_DIRECTION_ERROR && fatal === null) {
255
+ fatal = new GraphFormatError("E_DIRECTED", gen.message, { reason: "mixed direction" });
256
+ }
257
+ notes.push(gen);
258
+ }
259
+ const folding = pairFolding(snapshot);
260
+ directionNotes(snapshot, folding, common, note);
261
+ const unwritable = unwritableIds(snapshot);
262
+ if (unwritable > 0) {
263
+ note(
264
+ common.sanitizeIds === "mangle" ? LOSS.ID_MANGLED : LOSS.ID_CHARSET,
265
+ common.sanitizeIds === "mangle" ? `${unwritable} node id(s) that are not integers are renumbered; the originals are kept in the ${ORIGINAL_ID_ATTRIBUTE} attribute (restored by restoreMangledIds)` : `${unwritable} node id(s) that are not integers; export() will throw unless sanitizeIds is "mangle"`,
266
+ null,
267
+ unwritable
268
+ );
269
+ }
270
+ let ids = null;
271
+ try {
272
+ ids = writtenIds(snapshot, common.sanitizeIds);
273
+ } catch (err) {
274
+ if (!(err instanceof GraphFormatError)) {
275
+ throw err;
276
+ }
277
+ fatal ??= err;
278
+ }
279
+ const weights = explicitWeights(snapshot);
280
+ const label = snapshot.nodes.byRole("label");
281
+ const nodeAttrs = planAttributes(
282
+ snapshot.nodes,
283
+ (c) => c.meta.role !== null && SKIPPED_ROLES.has(c.meta.role) || isBypass(c) || isZ(c),
284
+ (c) => c === label && !snapshot.nodes.has("name") ? "name" : c.meta.name,
285
+ ids !== null && ids.changed > 0 ? /* @__PURE__ */ new Set([ORIGINAL_ID_ATTRIBUTE]) : /* @__PURE__ */ new Set()
286
+ );
287
+ const plainWeight = snapshot.edges.get(WEIGHT_ATTRIBUTE);
288
+ const weightColumnClash = plainWeight !== null && plainWeight.meta.role === null;
289
+ if (weightColumnClash) {
290
+ note(
291
+ LOSS.WEIGHT_KEY_CLASH,
292
+ weights.weighted ? `edge column "${WEIGHT_ATTRIBUTE}" is not written: the explicit weights are written under that name` : `edge column "${WEIGHT_ATTRIBUTE}" reads back as the edge weight`,
293
+ WEIGHT_ATTRIBUTE,
294
+ null
295
+ );
296
+ }
297
+ const edgeAttrs = planAttributes(
298
+ snapshot.edges,
299
+ (c) => c.meta.role !== null && (SKIPPED_ROLES.has(c.meta.role) || c.meta.role === "id") || isBypass(c) || weights.weighted && c === plainWeight,
300
+ (c) => c.meta.name,
301
+ weights.weighted ? /* @__PURE__ */ new Set([WEIGHT_ATTRIBUTE]) : /* @__PURE__ */ new Set()
302
+ );
303
+ const graphAttrs = planAttributes(
304
+ snapshot.graph,
305
+ () => false,
306
+ (c) => c.meta.name
307
+ ).map((p) => ({ ...p, key: p.name }));
308
+ let nonfinite = 0;
309
+ for (const p of [...nodeAttrs, ...edgeAttrs, ...graphAttrs]) {
310
+ nonfinite += nonFiniteCount(p.column);
311
+ }
312
+ for (let e = 0; e < snapshot.edgeCount; e++) {
313
+ if (weights.isExplicit(e) && !Number.isFinite(weights.value(e))) {
314
+ nonfinite++;
315
+ }
316
+ }
317
+ const position = snapshot.nodes.byRole("position");
318
+ if (position !== null) {
319
+ nonfinite += nonFinitePositions(position);
320
+ }
321
+ if (nonfinite > 0) {
322
+ note(
323
+ CX2_LOSS.NONFINITE_AS_NULL,
324
+ `${nonfinite} NaN or infinite value(s) cannot be written in CX2; written as null, they read back unset`,
325
+ null,
326
+ nonfinite
327
+ );
328
+ }
329
+ const edgeIds = planEdgeIds(snapshot, note);
330
+ const idColumn = snapshot.edges.byRole("id");
331
+ if (idColumn !== null && idColumn.dtype !== "f64") {
332
+ note(
333
+ LOSS.DTYPE,
334
+ `edge id column "${idColumn.meta.name}" is ${idColumn.dtype}; CX2 edge ids are integers and read back as f64`,
335
+ idColumn.meta.name,
336
+ snapshot.edgeCount - idColumn.nullCount
337
+ );
338
+ }
339
+ const z = [...snapshot.nodes].find(isZ) ?? null;
340
+ const positionZ = position !== null && z === null && position.meta.extra.sourceDims === 3;
341
+ return {
342
+ notes,
343
+ fatal,
344
+ ids,
345
+ folding,
346
+ weights,
347
+ nodeAttrs,
348
+ edgeAttrs,
349
+ graphAttrs,
350
+ nodeBypasses: [...snapshot.nodes].filter(isBypass),
351
+ edgeBypasses: [...snapshot.edges].filter(isBypass),
352
+ position,
353
+ positionZ,
354
+ z,
355
+ edgeIds,
356
+ originalIds: ids !== null && ids.changed > 0
357
+ };
358
+ }
359
+ function directionNotes(snapshot, folding, common, note) {
360
+ if (!snapshot.directed) {
361
+ note(
362
+ CX2_LOSS.UNDIRECTED_AS_DIRECTED,
363
+ `the snapshot is undirected; every edge is written as a directed CX2 edge (${snapshot.edgeCount} edge(s))`,
364
+ null,
365
+ snapshot.edgeCount
366
+ );
367
+ } else if (common.onMixedDirection !== "error") {
368
+ let undirected = 0;
369
+ for (let e = 0; e < snapshot.edgeCount; e++) {
370
+ if (!folding.folded(e) && !folding.sourceDirected(e)) {
371
+ undirected++;
372
+ }
373
+ }
374
+ if (undirected > 0) {
375
+ note(
376
+ CX2_LOSS.UNDIRECTED_AS_DIRECTED,
377
+ `${undirected} undirected edge(s) are written as one directed edge each (a pair folded to its primary); CX2 has no undirected edge`,
378
+ null,
379
+ undirected
380
+ );
381
+ }
382
+ }
383
+ if (folding.mutualCount > 0) {
384
+ note(
385
+ LOSS.MUTUAL_EXPANDED,
386
+ `${folding.mutualCount} mutual pair(s) are written as two directed edges; the mutual mark is lost`,
387
+ null,
388
+ folding.mutualCount
389
+ );
390
+ }
391
+ }
392
+ function nonFinitePositions(position) {
393
+ let count = 0;
394
+ for (let i = 0; i < position.length; i++) {
395
+ if (position.isSet(i)) {
396
+ const p = position.value(i);
397
+ if (!Number.isFinite(p[0]) || !Number.isFinite(p[1])) {
398
+ count++;
399
+ }
400
+ }
401
+ }
402
+ return count;
403
+ }
404
+ function planEdgeIds(snapshot, note) {
405
+ const column = snapshot.edges.byRole("id");
406
+ const ids = new Array(snapshot.edgeCount).fill(null);
407
+ const used = /* @__PURE__ */ new Set();
408
+ let generated = 0;
409
+ if (column !== null) {
410
+ for (let e = 0; e < snapshot.edgeCount; e++) {
411
+ const value = column.isSet(e) ? column.value(e) : void 0;
412
+ let n = NaN;
413
+ if (typeof value === "number") {
414
+ n = value;
415
+ } else if (typeof value === "string") {
416
+ n = Number(value);
417
+ }
418
+ if (Number.isSafeInteger(n) && !used.has(n)) {
419
+ ids[e] = n === 0 ? 0 : n;
420
+ used.add(n);
421
+ }
422
+ }
423
+ }
424
+ let next = 0;
425
+ const out = [];
426
+ for (let e = 0; e < snapshot.edgeCount; e++) {
427
+ let id = ids[e];
428
+ if (id === null) {
429
+ while (used.has(next)) {
430
+ next++;
431
+ }
432
+ id = next;
433
+ used.add(next);
434
+ generated++;
435
+ }
436
+ out.push(id);
437
+ }
438
+ if (column !== null && generated > 0) {
439
+ note(
440
+ LOSS.EDGE_IDS_GENERATED,
441
+ `${generated} edge(s) have no distinct integer id in "${column.meta.name}"; they are written with generated ids`,
442
+ column.meta.name,
443
+ generated
444
+ );
445
+ }
446
+ return out;
447
+ }
448
+ function stringify(value) {
449
+ const text = JSON.stringify(value, (_key, v) => Object.is(v, -0) ? `${RAW}-0` : v);
450
+ return text.includes("\\u0000cx2:") ? text.replace(RAW_JSON, "$1") : text;
451
+ }
452
+ function cellValue(p, row) {
453
+ const { column } = p;
454
+ if (!column.isSet(row)) {
455
+ return void 0;
456
+ }
457
+ const value = column.value(row);
458
+ if (p.jsonText) {
459
+ return JSON.stringify(value);
460
+ }
461
+ if (column.meta.dtype === "list" || column.meta.components > 1) {
462
+ const items = Array.from(value);
463
+ if (p.d === "string") {
464
+ return JSON.stringify(items);
465
+ }
466
+ return items.some((v) => typeof v === "number" && !Number.isFinite(v)) ? null : items;
467
+ }
468
+ if (typeof value === "number" && !Number.isFinite(value)) {
469
+ return null;
470
+ }
471
+ return value;
472
+ }
473
+ function declarations(plans, defaults) {
474
+ const out = {};
475
+ for (const p of plans) {
476
+ const decl = { d: p.d };
477
+ if (defaults && p.key !== p.name) {
478
+ decl.a = p.key;
479
+ }
480
+ const fallback = p.column.meta.default;
481
+ if (defaults && fallback !== void 0 && fallback !== null) {
482
+ if (defaultFits(cx2Type(p.d), fallback)) {
483
+ decl.v = fallback;
484
+ }
485
+ }
486
+ out[p.name] = decl;
487
+ }
488
+ return out;
489
+ }
490
+ function defaultFits(type, fallback) {
491
+ if (type === null) {
492
+ return false;
493
+ }
494
+ if (type.list) {
495
+ return Array.isArray(fallback);
496
+ }
497
+ switch (type.scalar) {
498
+ case "string":
499
+ return typeof fallback === "string";
500
+ case "boolean":
501
+ return typeof fallback === "boolean";
502
+ default:
503
+ return typeof fallback === "number" && Number.isFinite(fallback);
504
+ }
505
+ }
506
+ function attributesOf(plans, row) {
507
+ let out = null;
508
+ for (const p of plans) {
509
+ const value = cellValue(p, row);
510
+ if (value !== void 0) {
511
+ out ??= {};
512
+ out[p.key] = value;
513
+ }
514
+ }
515
+ return out;
516
+ }
517
+ function* write(snapshot, p) {
518
+ if (p.fatal !== null) {
519
+ throw p.fatal;
520
+ }
521
+ const { ids } = p;
522
+ if (ids === null) {
523
+ throw new GraphFormatError("E_INVALID_ID", "node ids cannot be written as CX2 integers", { reason: "charset" });
524
+ }
525
+ const { src, dst } = snapshot.edgeList();
526
+ const edges = [];
527
+ for (let e = 0; e < snapshot.edgeCount; e++) {
528
+ if (!p.folding.folded(e)) {
529
+ edges.push(e);
530
+ }
531
+ }
532
+ const nodeDecls = declarations(p.nodeAttrs, true);
533
+ if (p.originalIds) {
534
+ nodeDecls[ORIGINAL_ID_ATTRIBUTE] = { d: "string" };
535
+ }
536
+ const edgeDecls = declarations(p.edgeAttrs, true);
537
+ if (p.weights.weighted) {
538
+ edgeDecls[WEIGHT_ATTRIBUTE] = { d: "double" };
539
+ }
540
+ const networkDecls = declarations(p.graphAttrs, false);
541
+ const network = {};
542
+ for (const a of p.graphAttrs) {
543
+ const value = cellValue(a, 0);
544
+ if (value !== void 0) {
545
+ network[a.name] = value;
546
+ }
547
+ }
548
+ const { meta } = snapshot;
549
+ for (const [key, value] of [
550
+ ["name", meta.name],
551
+ ["description", meta.description]
552
+ ]) {
553
+ if (value !== null && !(key in network) && !(key in networkDecls)) {
554
+ network[key] = value;
555
+ networkDecls[key] = { d: "string" };
556
+ }
557
+ }
558
+ const kept = isRecord(meta.extra.cx2) ? meta.extra.cx2 : {};
559
+ const otherDecls = isRecord(kept.declarations) ? kept.declarations : {};
560
+ const opaque = meta.sourceFormat === CX2_FORMAT && isRecord(kept.opaque) ? kept.opaque : {};
561
+ const declarationsElement = { ...otherDecls };
562
+ for (const [key, table] of [
563
+ ["networkAttributes", networkDecls],
564
+ ["nodes", nodeDecls],
565
+ ["edges", edgeDecls]
566
+ ]) {
567
+ if (Object.keys(table).length > 0) {
568
+ declarationsElement[key] = table;
569
+ }
570
+ }
571
+ const nodeBypassRows = bypassRows(p.nodeBypasses, snapshot.nodeCount);
572
+ const edgeBypassRows = bypassRows(p.edgeBypasses, snapshot.edgeCount).filter((e) => !p.folding.folded(e));
573
+ const opaqueAspects = Object.entries(opaque).filter(
574
+ (entry) => !CORE_ASPECTS.has(entry[0]) && Array.isArray(entry[1])
575
+ );
576
+ const counts = [];
577
+ const hasDeclarations = Object.keys(declarationsElement).length > 0;
578
+ if (hasDeclarations) {
579
+ counts.push(["attributeDeclarations", 1]);
580
+ }
581
+ if (Object.keys(network).length > 0) {
582
+ counts.push(["networkAttributes", 1]);
583
+ }
584
+ counts.push(["nodes", snapshot.nodeCount], ["edges", edges.length]);
585
+ if (nodeBypassRows.length > 0) {
586
+ counts.push(["nodeBypasses", nodeBypassRows.length]);
587
+ }
588
+ if (edgeBypassRows.length > 0) {
589
+ counts.push(["edgeBypasses", edgeBypassRows.length]);
590
+ }
591
+ for (const [name, elements] of opaqueAspects) {
592
+ counts.push([name, elements.length]);
593
+ }
594
+ yield '[{"CXVersion":"2.0","hasFragments":false},\n';
595
+ yield `{"metaData":${stringify(counts.map(([name, elementCount]) => ({ name, elementCount })))}},
596
+ `;
597
+ if (hasDeclarations) {
598
+ yield `{"attributeDeclarations":[${stringify(declarationsElement)}]},
599
+ `;
600
+ }
601
+ if (Object.keys(network).length > 0) {
602
+ yield `{"networkAttributes":[${stringify(network)}]},
603
+ `;
604
+ }
605
+ yield* block("nodes", snapshot.nodeCount, (i) => stringify(nodeElement(p, ids, i)));
606
+ yield* block("edges", edges.length, (k) => {
607
+ const e = edges[k];
608
+ const element = {
609
+ id: p.edgeIds[e],
610
+ s: ids.idAt(src[e]),
611
+ t: ids.idAt(dst[e])
612
+ };
613
+ let v = attributesOf(p.edgeAttrs, e);
614
+ if (p.weights.isExplicit(e)) {
615
+ const w = p.weights.value(e);
616
+ v ??= {};
617
+ v[WEIGHT_ATTRIBUTE] = Number.isFinite(w) ? w : null;
618
+ }
619
+ if (v !== null) {
620
+ element.v = v;
621
+ }
622
+ return stringify(element);
623
+ });
624
+ if (nodeBypassRows.length > 0) {
625
+ yield* block("nodeBypasses", nodeBypassRows.length, (k) => {
626
+ const i = nodeBypassRows[k];
627
+ return stringify({ id: ids.idAt(i), v: bypassValues(p.nodeBypasses, i) });
628
+ });
629
+ }
630
+ if (edgeBypassRows.length > 0) {
631
+ yield* block("edgeBypasses", edgeBypassRows.length, (k) => {
632
+ const e = edgeBypassRows[k];
633
+ return stringify({ id: p.edgeIds[e], v: bypassValues(p.edgeBypasses, e) });
634
+ });
635
+ }
636
+ for (const [name, elements] of opaqueAspects) {
637
+ yield* block(name, elements.length, (k) => stringify(elements[k]));
638
+ }
639
+ yield '{"status":[{"error":"","success":true}]}]\n';
640
+ }
641
+ function* block(aspect, count, element) {
642
+ yield `{${JSON.stringify(aspect)}:[`;
643
+ for (let k = 0; k < count; k++) {
644
+ yield k === 0 ? `
645
+ ${element(k)}` : `,
646
+ ${element(k)}`;
647
+ }
648
+ yield "]},\n";
649
+ }
650
+ function nodeElement(p, ids, i) {
651
+ const element = { id: ids.idAt(i) };
652
+ if (p.position?.isSet(i) === true) {
653
+ const point = p.position.value(i);
654
+ if (Number.isFinite(point[0]) && Number.isFinite(point[1])) {
655
+ element.x = point[0];
656
+ element.y = point[1] === 0 ? 0 : -point[1];
657
+ if (p.positionZ && Number.isFinite(point[2])) {
658
+ element.z = point[2];
659
+ }
660
+ }
661
+ }
662
+ if (p.z?.isSet(i) === true) {
663
+ const z = p.z.value(i);
664
+ if (typeof z === "number" && Number.isFinite(z)) {
665
+ element.z = z;
666
+ }
667
+ }
668
+ let v = attributesOf(p.nodeAttrs, i);
669
+ if (p.originalIds && ids.isChanged(i)) {
670
+ v ??= {};
671
+ v[ORIGINAL_ID_ATTRIBUTE] = String(ids.originalAt(i));
672
+ }
673
+ if (v !== null) {
674
+ element.v = v;
675
+ }
676
+ return element;
677
+ }
678
+ function bypassRows(columns, rows) {
679
+ const out = [];
680
+ if (columns.length === 0) {
681
+ return out;
682
+ }
683
+ for (let i = 0; i < rows; i++) {
684
+ if (columns.some((c) => c.isSet(i))) {
685
+ out.push(i);
686
+ }
687
+ }
688
+ return out;
689
+ }
690
+ function bypassValues(columns, row) {
691
+ const out = {};
692
+ for (const column of columns) {
693
+ if (column.isSet(row)) {
694
+ const property = column.meta.origin?.id;
695
+ out[typeof property === "string" && property.length > 0 ? property : column.meta.name] = column.value(row);
696
+ }
697
+ }
698
+ return out;
699
+ }
700
+ const cx2Exporter = Object.freeze({
701
+ format: CX2_FORMAT,
702
+ capabilities: CX2_CAPABILITIES,
703
+ /**
704
+ * Pre-flight: what export() would lose, without writing anything.
705
+ * @param snapshot - the snapshot
706
+ * @param options - the common options
707
+ * @returns the notes, empty when the export is exact
708
+ */
709
+ check(snapshot, options) {
710
+ return Object.freeze([...plan(snapshot, resolveExportOptions(options)).notes]);
711
+ },
712
+ /**
713
+ * Write the document as UTF-8 chunks.
714
+ * @param snapshot - the snapshot
715
+ * @param options - the common options
716
+ * @returns the chunks
717
+ */
718
+ export(snapshot, options) {
719
+ return encodeChunks(write(snapshot, plan(snapshot, resolveExportOptions(options))));
720
+ },
721
+ /**
722
+ * Write the document as one string.
723
+ * @param snapshot - the snapshot
724
+ * @param options - the common options
725
+ * @returns the document
726
+ */
727
+ exportToString(snapshot, options) {
728
+ return joinText(write(snapshot, plan(snapshot, resolveExportOptions(options))));
729
+ }
730
+ });
731
+ export {
732
+ CX2_CAPABILITIES as C,
733
+ CX2_LOSS as a,
734
+ cx2Exporter as c
735
+ };
736
+ //# sourceMappingURL=exporter-BGrsWamJ.js.map