@graphty/graph-io 0.3.9 → 0.3.10
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 +29 -5
- package/dist/chunks/{escape-BjmIaFFo.js → escape-D1f9-cwf.js} +4 -4
- package/dist/chunks/{escape-BjmIaFFo.js.map → escape-D1f9-cwf.js.map} +1 -1
- package/dist/chunks/{importer-BddBW3sf.js → importer-9PxhqH4v.js} +336 -92
- package/dist/chunks/importer-9PxhqH4v.js.map +1 -0
- package/dist/chunks/{importer-DfI8POXb.js → importer-B8lsjFWx.js} +6 -5
- package/dist/chunks/importer-B8lsjFWx.js.map +1 -0
- package/dist/chunks/{importer-BtHFICnf.js → importer-C3HcYWAn.js} +5 -3
- package/dist/chunks/importer-C3HcYWAn.js.map +1 -0
- package/dist/chunks/{importer-BOxwmef_.js → importer-C7mnGdr_.js} +125 -8
- package/dist/chunks/importer-C7mnGdr_.js.map +1 -0
- package/dist/chunks/{records-BKSMowhR.js → records-IHsCfv7s.js} +20 -7
- package/dist/chunks/records-IHsCfv7s.js.map +1 -0
- package/dist/chunks/{writer-BdMak4_J.js → writer-BtWpUaiH.js} +4 -4
- package/dist/chunks/{writer-BdMak4_J.js.map → writer-BtWpUaiH.js.map} +1 -1
- package/dist/csv.js +239 -18
- package/dist/csv.js.map +1 -1
- package/dist/dot.js +1 -1
- package/dist/gexf.js +72 -33
- package/dist/gexf.js.map +1 -1
- package/dist/gml.js +44 -23
- package/dist/gml.js.map +1 -1
- package/dist/graph-io.js +11 -11
- 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/pajek.js +1 -1
- package/dist/src/common/export.js +1 -1
- package/dist/src/common/export.js.map +1 -1
- package/dist/src/formats/csv/exporter.d.ts +15 -4
- package/dist/src/formats/csv/exporter.d.ts.map +1 -1
- package/dist/src/formats/csv/exporter.js +125 -6
- package/dist/src/formats/csv/exporter.js.map +1 -1
- package/dist/src/formats/csv/importer.d.ts +36 -4
- package/dist/src/formats/csv/importer.d.ts.map +1 -1
- package/dist/src/formats/csv/importer.js +169 -8
- package/dist/src/formats/csv/importer.js.map +1 -1
- package/dist/src/formats/csv/records.d.ts +14 -1
- package/dist/src/formats/csv/records.d.ts.map +1 -1
- package/dist/src/formats/csv/records.js +28 -7
- package/dist/src/formats/csv/records.js.map +1 -1
- package/dist/src/formats/dot/exporter.d.ts.map +1 -1
- package/dist/src/formats/dot/exporter.js +2 -0
- package/dist/src/formats/dot/exporter.js.map +1 -1
- package/dist/src/formats/gexf/exporter.d.ts.map +1 -1
- package/dist/src/formats/gexf/exporter.js +36 -10
- package/dist/src/formats/gexf/exporter.js.map +1 -1
- package/dist/src/formats/gexf/importer.d.ts +9 -4
- package/dist/src/formats/gexf/importer.d.ts.map +1 -1
- package/dist/src/formats/gexf/importer.js +44 -21
- 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.d.ts.map +1 -1
- package/dist/src/formats/gexf/index.js +1 -1
- package/dist/src/formats/gexf/index.js.map +1 -1
- package/dist/src/formats/gexf/schema.d.ts +2 -0
- package/dist/src/formats/gexf/schema.d.ts.map +1 -1
- package/dist/src/formats/gexf/schema.js +18 -0
- package/dist/src/formats/gexf/schema.js.map +1 -1
- package/dist/src/formats/gml/exporter.d.ts.map +1 -1
- package/dist/src/formats/gml/exporter.js +1 -0
- package/dist/src/formats/gml/exporter.js.map +1 -1
- package/dist/src/formats/gml/importer.d.ts +7 -4
- package/dist/src/formats/gml/importer.d.ts.map +1 -1
- package/dist/src/formats/gml/importer.js +32 -19
- package/dist/src/formats/gml/importer.js.map +1 -1
- package/dist/src/formats/gml/index.d.ts +3 -1
- package/dist/src/formats/gml/index.d.ts.map +1 -1
- package/dist/src/formats/gml/index.js +4 -2
- package/dist/src/formats/gml/index.js.map +1 -1
- package/dist/src/formats/graphml/constants.d.ts +2 -0
- package/dist/src/formats/graphml/constants.d.ts.map +1 -1
- package/dist/src/formats/graphml/constants.js +2 -0
- package/dist/src/formats/graphml/constants.js.map +1 -1
- package/dist/src/formats/graphml/exporter.d.ts.map +1 -1
- package/dist/src/formats/graphml/exporter.js +14 -2
- package/dist/src/formats/graphml/exporter.js.map +1 -1
- package/dist/src/formats/graphml/importer.d.ts +2 -1
- package/dist/src/formats/graphml/importer.d.ts.map +1 -1
- package/dist/src/formats/graphml/importer.js +91 -27
- package/dist/src/formats/graphml/importer.js.map +1 -1
- package/dist/src/formats/graphml/yfiles.d.ts +62 -0
- package/dist/src/formats/graphml/yfiles.d.ts.map +1 -0
- package/dist/src/formats/graphml/yfiles.js +269 -0
- package/dist/src/formats/graphml/yfiles.js.map +1 -0
- package/dist/src/formats/json/exporter.d.ts.map +1 -1
- package/dist/src/formats/json/exporter.js +9 -1
- package/dist/src/formats/json/exporter.js.map +1 -1
- package/dist/src/formats/json/importer.d.ts +14 -0
- package/dist/src/formats/json/importer.d.ts.map +1 -1
- package/dist/src/formats/json/importer.js +165 -4
- package/dist/src/formats/json/importer.js.map +1 -1
- package/dist/src/formats/neo4j/exporter.d.ts.map +1 -1
- package/dist/src/formats/neo4j/exporter.js +1 -0
- package/dist/src/formats/neo4j/exporter.js.map +1 -1
- package/dist/src/formats/pajek/exporter.d.ts.map +1 -1
- package/dist/src/formats/pajek/exporter.js +3 -2
- package/dist/src/formats/pajek/exporter.js.map +1 -1
- package/package.json +2 -2
- package/src/common/export.ts +1 -1
- package/src/formats/csv/exporter.ts +140 -10
- package/src/formats/csv/importer.ts +207 -18
- package/src/formats/csv/records.ts +41 -6
- package/src/formats/dot/exporter.ts +2 -0
- package/src/formats/gexf/exporter.ts +40 -11
- package/src/formats/gexf/importer.ts +47 -25
- package/src/formats/gexf/index.ts +1 -1
- package/src/formats/gexf/schema.ts +18 -0
- package/src/formats/gml/exporter.ts +1 -0
- package/src/formats/gml/importer.ts +47 -24
- package/src/formats/gml/index.ts +4 -1
- package/src/formats/graphml/constants.ts +2 -0
- package/src/formats/graphml/exporter.ts +21 -2
- package/src/formats/graphml/importer.ts +99 -28
- package/src/formats/graphml/yfiles.ts +292 -0
- package/src/formats/json/exporter.ts +9 -1
- package/src/formats/json/importer.ts +202 -4
- package/src/formats/neo4j/exporter.ts +1 -0
- package/src/formats/pajek/exporter.ts +3 -1
- package/dist/chunks/importer-BOxwmef_.js.map +0 -1
- package/dist/chunks/importer-BddBW3sf.js.map +0 -1
- package/dist/chunks/importer-BtHFICnf.js.map +0 -1
- package/dist/chunks/importer-DfI8POXb.js.map +0 -1
- package/dist/chunks/records-BKSMowhR.js.map +0 -1
|
@@ -114,6 +114,20 @@ export interface JsonImportOptions {
|
|
|
114
114
|
indexLinks?: boolean | "auto" | undefined;
|
|
115
115
|
/** jgf: which graph of a `graphs` array to read; 0 by default. */
|
|
116
116
|
graphIndex?: number | undefined;
|
|
117
|
+
/**
|
|
118
|
+
* node-link / d3 / vis / graphology: where the node array is, as a dotted path of object keys
|
|
119
|
+
* from the document root (`"data.nodes"`); the object holding it is read as the graph record
|
|
120
|
+
* (its `directed`, `multigraph`, `graph` and edge keys). "nodes" by default. A path that names
|
|
121
|
+
* nothing is an E_MISSING_SECTION issue and the graph has no node records.
|
|
122
|
+
*/
|
|
123
|
+
nodesPath?: string | undefined;
|
|
124
|
+
/**
|
|
125
|
+
* node-link / d3 / vis / graphology: where the edge array is, as a dotted path of object keys
|
|
126
|
+
* from the document root (`"data.links"`); by default the edges or links key of the object
|
|
127
|
+
* holding the nodes. A path that names nothing is an E_MISSING_SECTION issue and the graph has
|
|
128
|
+
* no edge records.
|
|
129
|
+
*/
|
|
130
|
+
edgesPath?: string | undefined;
|
|
117
131
|
}
|
|
118
132
|
|
|
119
133
|
/**
|
|
@@ -254,6 +268,14 @@ interface EdgeIdColumn {
|
|
|
254
268
|
readonly seen: Set<string> | null;
|
|
255
269
|
}
|
|
256
270
|
|
|
271
|
+
/** The dialects whose node and edge arrays nodesPath and edgesPath can point at. */
|
|
272
|
+
const PATH_DIALECTS: ReadonlySet<JsonImportDialect> = new Set<JsonImportDialect>([
|
|
273
|
+
"node-link",
|
|
274
|
+
"d3",
|
|
275
|
+
"vis",
|
|
276
|
+
"graphology",
|
|
277
|
+
]);
|
|
278
|
+
|
|
257
279
|
/** The resolved format-specific options. */
|
|
258
280
|
interface ResolvedJsonOptions {
|
|
259
281
|
readonly dialect: JsonImportDialect | "auto";
|
|
@@ -263,6 +285,10 @@ interface ResolvedJsonOptions {
|
|
|
263
285
|
readonly targetKey: string | null;
|
|
264
286
|
readonly indexLinks: boolean | "auto";
|
|
265
287
|
readonly graphIndex: number;
|
|
288
|
+
/** The dotted path segments of the node array, or null for the root's own nodes key. */
|
|
289
|
+
readonly nodesPath: readonly string[] | null;
|
|
290
|
+
/** The dotted path segments of the edge array, or null for the edges / links key beside the nodes. */
|
|
291
|
+
readonly edgesPath: readonly string[] | null;
|
|
266
292
|
/** Set by importAll(): every graph of a `graphs` array is read, so none is reported as skipped. */
|
|
267
293
|
readonly all?: boolean;
|
|
268
294
|
}
|
|
@@ -286,6 +312,11 @@ function resolveJsonOptions(options: (JsonImportOptions & CommonImportOptions) |
|
|
|
286
312
|
if (!Number.isInteger(graphIndex) || graphIndex < 0) {
|
|
287
313
|
throw unsupportedOption("graphIndex", graphIndex, ["a non-negative integer"]);
|
|
288
314
|
}
|
|
315
|
+
const nodesPath = pathOption("nodesPath", o.nodesPath);
|
|
316
|
+
const edgesPath = pathOption("edgesPath", o.edgesPath);
|
|
317
|
+
if ((nodesPath !== null || edgesPath !== null) && dialect !== "auto" && !PATH_DIALECTS.has(dialect)) {
|
|
318
|
+
throw unsupportedOption(nodesPath === null ? "edgesPath" : "nodesPath", dialect, [...PATH_DIALECTS]);
|
|
319
|
+
}
|
|
289
320
|
return {
|
|
290
321
|
dialect,
|
|
291
322
|
nodeIdKey: keyOption("nodeIdKey", o.nodeIdKey),
|
|
@@ -294,7 +325,176 @@ function resolveJsonOptions(options: (JsonImportOptions & CommonImportOptions) |
|
|
|
294
325
|
targetKey: keyOption("targetKey", o.targetKey),
|
|
295
326
|
indexLinks,
|
|
296
327
|
graphIndex,
|
|
328
|
+
nodesPath,
|
|
329
|
+
edgesPath,
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
/**
|
|
334
|
+
* Check a dotted path option: object keys joined by dots, none of them empty.
|
|
335
|
+
* @param name - the option name
|
|
336
|
+
* @param value - the caller's value
|
|
337
|
+
* @returns the segments, or null when absent
|
|
338
|
+
*/
|
|
339
|
+
function pathOption(name: string, value: unknown): readonly string[] | null {
|
|
340
|
+
if (value === undefined) {
|
|
341
|
+
return null;
|
|
342
|
+
}
|
|
343
|
+
const segments = typeof value === "string" ? value.split(".") : [];
|
|
344
|
+
if (segments.length === 0 || segments.some((segment) => segment.length === 0)) {
|
|
345
|
+
throw unsupportedOption(name, value, ["a dotted path of non-empty keys"]);
|
|
346
|
+
}
|
|
347
|
+
return segments;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
* The value at a path of object keys, or undefined when a step is missing or not an object.
|
|
352
|
+
* @param root - the document
|
|
353
|
+
* @param segments - the keys
|
|
354
|
+
* @returns the value
|
|
355
|
+
*/
|
|
356
|
+
function valueAt(root: unknown, segments: readonly string[]): unknown {
|
|
357
|
+
let value = root;
|
|
358
|
+
for (const segment of segments) {
|
|
359
|
+
if (!isJsonObject(value) || !hasKey(value, segment)) {
|
|
360
|
+
return undefined;
|
|
361
|
+
}
|
|
362
|
+
value = value[segment];
|
|
363
|
+
}
|
|
364
|
+
return value;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
/**
|
|
368
|
+
* The graph record nodesPath and edgesPath describe: the object holding the node array (the
|
|
369
|
+
* document itself by default) with its nodes key and its edges / links key replaced by the arrays
|
|
370
|
+
* the paths name. A path that names nothing is recorded as E_MISSING_SECTION and stands for an
|
|
371
|
+
* empty array, so the import goes on.
|
|
372
|
+
* @param root - the parsed document
|
|
373
|
+
* @param json - the resolved options
|
|
374
|
+
* @param report - the report
|
|
375
|
+
* @returns the document unchanged when no path is given, else the graph record
|
|
376
|
+
*/
|
|
377
|
+
function applyPaths(root: unknown, json: ResolvedJsonOptions, report: ImportReportBuilder): unknown {
|
|
378
|
+
const { nodesPath, edgesPath } = json;
|
|
379
|
+
if (nodesPath === null && edgesPath === null) {
|
|
380
|
+
return root;
|
|
381
|
+
}
|
|
382
|
+
const lookup = (option: string, segments: readonly string[]): unknown => {
|
|
383
|
+
const value = valueAt(root, segments);
|
|
384
|
+
if (value === undefined) {
|
|
385
|
+
const path = segments.join(".");
|
|
386
|
+
report.error(
|
|
387
|
+
"missing-value",
|
|
388
|
+
JSON_ISSUE.MISSING_SECTION,
|
|
389
|
+
`${option} ${JSON.stringify(path)} names nothing in the document`,
|
|
390
|
+
{ element: path },
|
|
391
|
+
);
|
|
392
|
+
return [];
|
|
393
|
+
}
|
|
394
|
+
return value;
|
|
297
395
|
};
|
|
396
|
+
const holderPath = nodesPath === null ? [] : nodesPath.slice(0, -1);
|
|
397
|
+
const holder = valueAt(root, holderPath);
|
|
398
|
+
// the keys the paths replace: the nodes key, and every edge key when edgesPath names the edges
|
|
399
|
+
const replaced = new Set<string>();
|
|
400
|
+
if (nodesPath !== null) {
|
|
401
|
+
replaced.add(nodesPath[nodesPath.length - 1]);
|
|
402
|
+
}
|
|
403
|
+
if (edgesPath !== null) {
|
|
404
|
+
replaced.add("edges");
|
|
405
|
+
replaced.add("links");
|
|
406
|
+
}
|
|
407
|
+
let record: JsonRecord = Object.fromEntries(
|
|
408
|
+
Object.entries(isJsonObject(holder) ? holder : {}).filter(([key]) => !replaced.has(key)),
|
|
409
|
+
);
|
|
410
|
+
// edges inside the holder (`data.graph.links` under `data`) leave the holder, and only they do:
|
|
411
|
+
// the rest of the key they sit in (the `graph` attributes) is still read
|
|
412
|
+
if (edgesPath !== null && edgesPath.length > holderPath.length && holderPath.every((k, i) => edgesPath[i] === k)) {
|
|
413
|
+
const rest = withoutPath(record, edgesPath.slice(holderPath.length));
|
|
414
|
+
record = isJsonObject(rest) ? rest : {};
|
|
415
|
+
}
|
|
416
|
+
if (nodesPath !== null) {
|
|
417
|
+
record.nodes = lookup("nodesPath", nodesPath);
|
|
418
|
+
}
|
|
419
|
+
if (edgesPath !== null) {
|
|
420
|
+
record[pathEdgesKey(json, edgesPath)] = lookup("edgesPath", edgesPath);
|
|
421
|
+
}
|
|
422
|
+
return record;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
/**
|
|
426
|
+
* A value with the entry at a path of object keys removed; undefined when the path is empty (the
|
|
427
|
+
* value itself goes) or nothing but that entry is left.
|
|
428
|
+
* @param value - the value
|
|
429
|
+
* @param segments - the keys down to the entry
|
|
430
|
+
* @returns the value without the entry
|
|
431
|
+
*/
|
|
432
|
+
function withoutPath(value: unknown, segments: readonly string[]): unknown {
|
|
433
|
+
if (segments.length === 0) {
|
|
434
|
+
return undefined;
|
|
435
|
+
}
|
|
436
|
+
const [head, ...tail] = segments;
|
|
437
|
+
if (!isJsonObject(value) || !hasKey(value, head)) {
|
|
438
|
+
return value;
|
|
439
|
+
}
|
|
440
|
+
// a parsed JSON value is never undefined, so undefined marks the entries to drop
|
|
441
|
+
const entries = Object.entries(value)
|
|
442
|
+
.map(([key, v]) => [key, key === head ? withoutPath(v, tail) : v] as const)
|
|
443
|
+
.filter(([, v]) => v !== undefined);
|
|
444
|
+
return entries.length === 0 ? undefined : Object.fromEntries(entries);
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
/**
|
|
448
|
+
* The key applyPaths() stores the edge array under: the caller's edgesKey, else "links" when
|
|
449
|
+
* edgesPath ends in links (so the d3 sniff still sees it), else "edges".
|
|
450
|
+
* @param json - the resolved options
|
|
451
|
+
* @param edgesPath - the edgesPath segments
|
|
452
|
+
* @returns the key
|
|
453
|
+
*/
|
|
454
|
+
function pathEdgesKey(json: ResolvedJsonOptions, edgesPath: readonly string[]): string {
|
|
455
|
+
return json.edgesKey ?? (edgesPath[edgesPath.length - 1] === "links" ? "links" : "edges");
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
/**
|
|
459
|
+
* The dialect of a graph record built from nodesPath / edgesPath: the forced one, else the shape
|
|
460
|
+
* rule over the record, else node-link.
|
|
461
|
+
* @param record - the graph record
|
|
462
|
+
* @param forced - the caller's dialect option
|
|
463
|
+
* @returns the dialect
|
|
464
|
+
*/
|
|
465
|
+
function pathDialect(record: unknown, forced: JsonImportDialect | "auto"): JsonImportDialect {
|
|
466
|
+
if (forced !== "auto") {
|
|
467
|
+
return forced;
|
|
468
|
+
}
|
|
469
|
+
const sniffed = sniffJsonDialect(record);
|
|
470
|
+
return sniffed !== null && PATH_DIALECTS.has(sniffed) ? sniffed : "node-link";
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
/**
|
|
474
|
+
* The document to read and its dialect: the graph record of nodesPath / edgesPath when either is
|
|
475
|
+
* given, the document itself otherwise.
|
|
476
|
+
* @param parsed - the parsed document
|
|
477
|
+
* @param json - the resolved options
|
|
478
|
+
* @param report - the report
|
|
479
|
+
* @returns the root and its dialect
|
|
480
|
+
*/
|
|
481
|
+
function documentOf(
|
|
482
|
+
parsed: unknown,
|
|
483
|
+
json: ResolvedJsonOptions,
|
|
484
|
+
report: ImportReportBuilder,
|
|
485
|
+
): { readonly root: unknown; readonly dialect: JsonImportDialect } {
|
|
486
|
+
if (json.nodesPath === null && json.edgesPath === null) {
|
|
487
|
+
return { root: parsed, dialect: detectDialect(parsed, json.dialect, report) };
|
|
488
|
+
}
|
|
489
|
+
const root = applyPaths(parsed, json, report);
|
|
490
|
+
const dialect = pathDialect(root, json.dialect);
|
|
491
|
+
// vis and graphology read their edges from the edges key only
|
|
492
|
+
if (json.edgesPath !== null && (dialect === "vis" || dialect === "graphology") && isJsonObject(root)) {
|
|
493
|
+
const key = pathEdgesKey(json, json.edgesPath);
|
|
494
|
+
const renamed = Object.fromEntries(Object.entries(root).map(([k, v]) => [k === key ? "edges" : k, v]));
|
|
495
|
+
return { root: renamed, dialect };
|
|
496
|
+
}
|
|
497
|
+
return { root, dialect };
|
|
298
498
|
}
|
|
299
499
|
|
|
300
500
|
/**
|
|
@@ -2641,8 +2841,7 @@ export const jsonImporter: GraphImporter<JsonImportOptions> = Object.freeze({
|
|
|
2641
2841
|
const json = resolveJsonOptions(options);
|
|
2642
2842
|
const report = new ImportReportBuilder("json", resolved.errorLimit);
|
|
2643
2843
|
const text = await readText(input, report, resolved);
|
|
2644
|
-
const root = parseDocument(text, report);
|
|
2645
|
-
const dialect = detectDialect(root, json.dialect, report);
|
|
2844
|
+
const { root, dialect } = documentOf(parseDocument(text, report), json, report);
|
|
2646
2845
|
readGraph(root, dialect, sink, report, resolved, json, options);
|
|
2647
2846
|
return report.finish();
|
|
2648
2847
|
},
|
|
@@ -2664,8 +2863,7 @@ export const jsonImporter: GraphImporter<JsonImportOptions> = Object.freeze({
|
|
|
2664
2863
|
const json = resolveJsonOptions(options);
|
|
2665
2864
|
const first = new ImportReportBuilder("json", resolved.errorLimit);
|
|
2666
2865
|
const text = await readText(input, first, resolved);
|
|
2667
|
-
const root = parseDocument(text, first);
|
|
2668
|
-
const dialect = detectDialect(root, json.dialect, first);
|
|
2866
|
+
const { root, dialect } = documentOf(parseDocument(text, first), json, first);
|
|
2669
2867
|
const graphs =
|
|
2670
2868
|
dialect === "jgf" && isJsonObject(root) && !isJsonObject(root.graph) && Array.isArray(root.graphs)
|
|
2671
2869
|
? root.graphs.length
|
|
@@ -30,6 +30,7 @@ import {
|
|
|
30
30
|
isParameterKey,
|
|
31
31
|
LABEL_COLUMN,
|
|
32
32
|
ORIGINAL_ID_KEY,
|
|
33
|
+
POSITION_COLUMN,
|
|
33
34
|
RELATION_COLUMN,
|
|
34
35
|
SHAPE_COLUMN,
|
|
35
36
|
SHAPES,
|
|
@@ -84,7 +85,7 @@ export const PAJEK_LOSS = Object.freeze({
|
|
|
84
85
|
const SLOT_ROLES: ReadonlySet<string> = new Set(["label"]);
|
|
85
86
|
|
|
86
87
|
/** The names the importer gives the slot columns, for the name-change notes. */
|
|
87
|
-
const ROLE_NAMES: Readonly<Record<string, string>> = Object.freeze({ label: "label" });
|
|
88
|
+
const ROLE_NAMES: Readonly<Record<string, string>> = Object.freeze({ label: "label", position: POSITION_COLUMN });
|
|
88
89
|
|
|
89
90
|
/** The roles the exporter handles structurally rather than as parameters. */
|
|
90
91
|
const STRUCTURAL_ROLES: ReadonlySet<string> = new Set([
|
|
@@ -105,6 +106,7 @@ const CHECKED_ROLES: ReadonlySet<string> = new Set([
|
|
|
105
106
|
"parent",
|
|
106
107
|
"parents",
|
|
107
108
|
"open",
|
|
109
|
+
"spellsOpen",
|
|
108
110
|
]);
|
|
109
111
|
|
|
110
112
|
/** Roles the generic checker lets through under temporal "spells" that Pajek cannot write. */
|