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