@graphty/graph-io 0.3.17 → 0.3.18
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/LICENSE +1 -1
- package/README.md +29 -3
- package/dist/chunks/{escape-scjHxjpr.js → escape-D-gZWO26.js} +3 -2
- package/dist/chunks/{escape-scjHxjpr.js.map → escape-D-gZWO26.js.map} +1 -1
- package/dist/chunks/{importer-Xg07gk7p.js → importer-Br_QeAeE.js} +4 -3
- package/dist/chunks/{importer-Xg07gk7p.js.map → importer-Br_QeAeE.js.map} +1 -1
- package/dist/chunks/{importer-ruMWWvVs.js → importer-DHagxvDD.js} +4 -3
- package/dist/chunks/{importer-ruMWWvVs.js.map → importer-DHagxvDD.js.map} +1 -1
- package/dist/chunks/{importer-B6rKRxzv.js → importer-Du5crN9l.js} +509 -25
- package/dist/chunks/importer-Du5crN9l.js.map +1 -0
- package/dist/chunks/importer-aNJfe0qu.js +1614 -0
- package/dist/chunks/importer-aNJfe0qu.js.map +1 -0
- package/dist/chunks/{importer-BmOl9gLW.js → importer-d0uQxFp6.js} +4 -3
- package/dist/chunks/{importer-BmOl9gLW.js.map → importer-d0uQxFp6.js.map} +1 -1
- package/dist/chunks/ontology-BnrJ4I98.js +113 -0
- package/dist/chunks/ontology-BnrJ4I98.js.map +1 -0
- package/dist/chunks/{records-DSpbTE5s.js → records-Bk9jgodz.js} +2 -2
- package/dist/chunks/{records-DSpbTE5s.js.map → records-Bk9jgodz.js.map} +1 -1
- package/dist/chunks/{writer-DHHfHn11.js → report-BOk0p5y8.js} +97 -919
- package/dist/chunks/report-BOk0p5y8.js.map +1 -0
- package/dist/chunks/writer-GAdltGmC.js +827 -0
- package/dist/chunks/writer-GAdltGmC.js.map +1 -0
- package/dist/csv.js +4 -3
- package/dist/csv.js.map +1 -1
- package/dist/dot.js +1 -1
- package/dist/gexf.js +3 -2
- package/dist/gexf.js.map +1 -1
- package/dist/gml.js +3 -2
- package/dist/gml.js.map +1 -1
- package/dist/graph-io.js +160 -141
- package/dist/graph-io.js.map +1 -1
- package/dist/graphml.js +1 -1
- package/dist/json.js +1 -1
- package/dist/neo4j.js +4 -3
- package/dist/neo4j.js.map +1 -1
- package/dist/obo.d.ts +1 -0
- package/dist/obo.js +6 -0
- package/dist/obo.js.map +1 -0
- package/dist/pajek.js +1 -1
- package/dist/src/common/ontology.d.ts +59 -0
- package/dist/src/common/ontology.d.ts.map +1 -0
- package/dist/src/common/ontology.js +147 -0
- package/dist/src/common/ontology.js.map +1 -0
- package/dist/src/formats/json/dialect.d.ts +8 -6
- package/dist/src/formats/json/dialect.d.ts.map +1 -1
- package/dist/src/formats/json/dialect.js +26 -3
- package/dist/src/formats/json/dialect.js.map +1 -1
- package/dist/src/formats/json/importer.d.ts +324 -7
- package/dist/src/formats/json/importer.d.ts.map +1 -1
- package/dist/src/formats/json/importer.js +153 -22
- package/dist/src/formats/json/importer.js.map +1 -1
- package/dist/src/formats/json/obographs.d.ts +21 -0
- package/dist/src/formats/json/obographs.d.ts.map +1 -0
- package/dist/src/formats/json/obographs.js +476 -0
- package/dist/src/formats/json/obographs.js.map +1 -0
- package/dist/src/formats/obo/importer.d.ts +90 -0
- package/dist/src/formats/obo/importer.d.ts.map +1 -0
- package/dist/src/formats/obo/importer.js +1248 -0
- package/dist/src/formats/obo/importer.js.map +1 -0
- package/dist/src/formats/obo/index.d.ts +7 -0
- package/dist/src/formats/obo/index.d.ts.map +1 -0
- package/dist/src/formats/obo/index.js +7 -0
- package/dist/src/formats/obo/index.js.map +1 -0
- package/dist/src/formats/obo/syntax.d.ts +121 -0
- package/dist/src/formats/obo/syntax.d.ts.map +1 -0
- package/dist/src/formats/obo/syntax.js +424 -0
- package/dist/src/formats/obo/syntax.js.map +1 -0
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +1 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/registry.d.ts.map +1 -1
- package/dist/src/registry.js +3 -1
- 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 +23 -3
- package/dist/src/sniff.js.map +1 -1
- package/package.json +6 -1
- package/src/common/ontology.ts +169 -0
- package/src/formats/json/dialect.ts +37 -7
- package/src/formats/json/importer.ts +204 -27
- package/src/formats/json/obographs.ts +563 -0
- package/src/formats/obo/importer.ts +1695 -0
- package/src/formats/obo/index.ts +7 -0
- package/src/formats/obo/syntax.ts +466 -0
- package/src/index.ts +1 -0
- package/src/registry.ts +3 -1
- package/src/sniff.ts +35 -5
- package/dist/chunks/importer-B6rKRxzv.js.map +0 -1
- package/dist/chunks/writer-DHHfHn11.js.map +0 -1
|
@@ -30,10 +30,19 @@
|
|
|
30
30
|
* endpoint, a declared field of the wrong type, an unknown Cytoscape parent, an id the coercion rule
|
|
31
31
|
* rejects.
|
|
32
32
|
*/
|
|
33
|
-
import { type
|
|
34
|
-
import { type
|
|
35
|
-
|
|
36
|
-
|
|
33
|
+
import { type ColumnDecl, type ColumnHandle, type GraphMetaPatch, type GraphSink, type NodeId } from "@graphty/graph-format";
|
|
34
|
+
import { DirectionResolver, type EdgeKind } from "../../common/direction.js";
|
|
35
|
+
import { IdCoercer } from "../../common/ids.js";
|
|
36
|
+
import { type ResolvedImportOptions } from "../../common/options.js";
|
|
37
|
+
import { ImportReportBuilder } from "../../common/report.js";
|
|
38
|
+
import { type GraphChoiceOptions, type GraphImporter } from "../../types.js";
|
|
39
|
+
import { type JsonImportDialect, type JsonShapeMeta } from "./dialect.js";
|
|
40
|
+
/**
|
|
41
|
+
* The format-specific options of the JSON importer. `graphIndex` / `graphName` choose one graph of
|
|
42
|
+
* a JGF or OBO Graphs `graphs` array (the first by default); a graph's name is its `id`, else its
|
|
43
|
+
* label.
|
|
44
|
+
*/
|
|
45
|
+
export interface JsonImportOptions extends GraphChoiceOptions {
|
|
37
46
|
/** The dialect to read; "auto" (default) sniffs the parsed document. */
|
|
38
47
|
dialect?: JsonImportDialect | "auto" | undefined;
|
|
39
48
|
/**
|
|
@@ -52,8 +61,18 @@ export interface JsonImportOptions {
|
|
|
52
61
|
* every endpoint is an integer below the node count and no node id is a number.
|
|
53
62
|
*/
|
|
54
63
|
indexLinks?: boolean | "auto" | undefined;
|
|
55
|
-
/**
|
|
56
|
-
|
|
64
|
+
/**
|
|
65
|
+
* obographs: "curie" (default) reads `http://purl.obolibrary.org/obo/GO_0008150` as `GO:0008150`
|
|
66
|
+
* and `.../obo/go#regulates` as `regulates`, the identifiers the `.obo` file of the same ontology
|
|
67
|
+
* writes; "iri" keeps every IRI as written.
|
|
68
|
+
*/
|
|
69
|
+
oboIds?: "curie" | "iri" | undefined;
|
|
70
|
+
/**
|
|
71
|
+
* obographs: "metadata" (default) keeps PROPERTY nodes and their subPropertyOf / inverseOf edges
|
|
72
|
+
* in `meta.extra.obographs`, as the OBO importer keeps `[Typedef]` frames; "nodes" makes them
|
|
73
|
+
* nodes and edges.
|
|
74
|
+
*/
|
|
75
|
+
typedefs?: "metadata" | "nodes" | undefined;
|
|
57
76
|
/**
|
|
58
77
|
* node-link / d3 / vis / graphology: where the node array is, as a dotted path of object keys
|
|
59
78
|
* from the document root (`"data.nodes"`); the object holding it is read as the graph record
|
|
@@ -109,8 +128,18 @@ export declare const JSON_ISSUE: Readonly<{
|
|
|
109
128
|
ID_MERGED: "W_ID_MERGED";
|
|
110
129
|
/** Edge ids of mixed JSON types were stored as text. */
|
|
111
130
|
EDGE_ID_STRINGIFIED: "W_EDGE_ID_STRINGIFIED";
|
|
112
|
-
/** A JGF `graphs` array holds more than one graph; only
|
|
131
|
+
/** A JGF or OBO Graphs `graphs` array holds more than one graph; only the chosen one is read. */
|
|
113
132
|
MULTIPLE_GRAPHS: "W_MULTIPLE_GRAPHS";
|
|
133
|
+
/** `graphIndex` is beyond the `graphs` array, or `graphName` names none of its graphs (fatal). */
|
|
134
|
+
GRAPH_NOT_FOUND: "E_GRAPH_NOT_FOUND";
|
|
135
|
+
/** `graphName` names more than one graph of the `graphs` array (fatal). */
|
|
136
|
+
AMBIGUOUS_GRAPH_NAME: "E_AMBIGUOUS_GRAPH_NAME";
|
|
137
|
+
/** obographs: an edge uses the outdated `subj` key of the OBO Graphs README; it is read as `sub`. */
|
|
138
|
+
OBOGRAPHS_SUBJ: "W_JSON_OBOGRAPHS_SUBJ";
|
|
139
|
+
/** obographs: an edge endpoint missing from `nodes` (a placeholder node is made, or the edge dropped under addMissingNodes false). */
|
|
140
|
+
DANGLING_REFERENCE: "W_DANGLING_REFERENCE";
|
|
141
|
+
/** The document is longer than one JavaScript string can hold (fatal; category unsupported). */
|
|
142
|
+
TOO_LARGE: "E_TOO_LARGE";
|
|
114
143
|
/** JGF hyperedges under the "error" policy. */
|
|
115
144
|
HYPEREDGE: "E_HYPEREDGE";
|
|
116
145
|
/** JGF hyperedges skipped under the default "skip" policy. */
|
|
@@ -138,8 +167,296 @@ export declare const JSON_ISSUE: Readonly<{
|
|
|
138
167
|
/** A declared encoding the platform cannot decode was ignored. */
|
|
139
168
|
UNKNOWN_ENCODING: "W_UNKNOWN_ENCODING";
|
|
140
169
|
}>;
|
|
170
|
+
export type JsonRecord = Record<string, unknown>;
|
|
171
|
+
/** An edge id column declared from a scan of the file's edge ids. */
|
|
172
|
+
interface EdgeIdColumn {
|
|
173
|
+
readonly handle: ColumnHandle;
|
|
174
|
+
/** Whether numeric ids are stored as text (the file mixes numbers and strings). */
|
|
175
|
+
readonly stringify: boolean;
|
|
176
|
+
/** The id texts seen so far when the dialect requires unique ids, else null. */
|
|
177
|
+
readonly seen: Set<string> | null;
|
|
178
|
+
}
|
|
179
|
+
/** The resolved format-specific options. */
|
|
180
|
+
interface ResolvedJsonOptions {
|
|
181
|
+
readonly dialect: JsonImportDialect | "auto";
|
|
182
|
+
readonly nodeIdKey: string | null;
|
|
183
|
+
readonly edgesKey: string | null;
|
|
184
|
+
readonly sourceKey: string | null;
|
|
185
|
+
readonly targetKey: string | null;
|
|
186
|
+
readonly indexLinks: boolean | "auto";
|
|
187
|
+
readonly graphIndex: number;
|
|
188
|
+
/** The caller's graphIndex / graphName, as given, for chooseGraph(). */
|
|
189
|
+
readonly choice: GraphChoiceOptions;
|
|
190
|
+
/** obographs: CURIE or IRI ids. */
|
|
191
|
+
readonly oboIds: "curie" | "iri";
|
|
192
|
+
/** obographs: PROPERTY nodes as metadata or as nodes. */
|
|
193
|
+
readonly typedefs: "metadata" | "nodes";
|
|
194
|
+
/** The dotted path segments of the node array, or null for the root's own nodes key. */
|
|
195
|
+
readonly nodesPath: readonly string[] | null;
|
|
196
|
+
/** The dotted path segments of the edge array, or null for the edges / links key beside the nodes. */
|
|
197
|
+
readonly edgesPath: readonly string[] | null;
|
|
198
|
+
/** Set by importAll(): every graph of a `graphs` array is read, so none is reported as skipped. */
|
|
199
|
+
readonly all?: boolean;
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Writes inferred attribute cells for one table, caching the handle of every column after its
|
|
203
|
+
* first write so the hot loop never looks a column up by name twice. Names that collide with a
|
|
204
|
+
* structural column declared up front are suffixed deterministically (design section 5.6).
|
|
205
|
+
*/
|
|
206
|
+
declare class AttributeWriter {
|
|
207
|
+
private readonly sink;
|
|
208
|
+
private readonly domain;
|
|
209
|
+
private readonly handles;
|
|
210
|
+
private readonly reservedNames;
|
|
211
|
+
/**
|
|
212
|
+
* Create a writer.
|
|
213
|
+
* @param sink - the sink
|
|
214
|
+
* @param domain - node or edge
|
|
215
|
+
*/
|
|
216
|
+
constructor(sink: GraphSink, domain: "node" | "edge");
|
|
217
|
+
/**
|
|
218
|
+
* Declare a structural column up front; attribute keys with its name are suffixed from now on.
|
|
219
|
+
* @param decl - the declaration
|
|
220
|
+
* @returns the handle
|
|
221
|
+
*/
|
|
222
|
+
declare(decl: ColumnDecl): ColumnHandle;
|
|
223
|
+
/**
|
|
224
|
+
* Declare a structural column only when the file uses it.
|
|
225
|
+
* @param decl - the declaration
|
|
226
|
+
* @param present - whether any element carries the field
|
|
227
|
+
* @returns the handle, or INVALID_INDEX when not declared
|
|
228
|
+
*/
|
|
229
|
+
declareIf(decl: ColumnDecl, present: boolean): ColumnHandle;
|
|
230
|
+
/**
|
|
231
|
+
* Whether a name is taken in the sink's table (for the deterministic rename rule).
|
|
232
|
+
* @param name - the column name
|
|
233
|
+
* @returns true when a column of that name exists
|
|
234
|
+
*/
|
|
235
|
+
taken(name: string): boolean;
|
|
236
|
+
/**
|
|
237
|
+
* Write one attribute cell by its source key; null and undefined leave the row unset.
|
|
238
|
+
* @param row - the node or edge index
|
|
239
|
+
* @param key - the source key
|
|
240
|
+
* @param value - the JSON value
|
|
241
|
+
* @param suffix - the suffix applied when the key collides with a structural column
|
|
242
|
+
*/
|
|
243
|
+
write(row: number, key: string, value: unknown, suffix: string): void;
|
|
244
|
+
/**
|
|
245
|
+
* Write through a handle or a name.
|
|
246
|
+
* @param column - the handle or name
|
|
247
|
+
* @param row - the row
|
|
248
|
+
* @param value - the value
|
|
249
|
+
*/
|
|
250
|
+
set(column: ColumnHandle | string, row: number, value: unknown): void;
|
|
251
|
+
/**
|
|
252
|
+
* Look a column up by name.
|
|
253
|
+
* @param name - the column name
|
|
254
|
+
* @returns the handle, or INVALID_INDEX
|
|
255
|
+
*/
|
|
256
|
+
private lookup;
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Everything one import call shares between the dialect readers.
|
|
260
|
+
*/
|
|
261
|
+
export declare class ImportContext {
|
|
262
|
+
readonly sink: GraphSink;
|
|
263
|
+
readonly report: ImportReportBuilder;
|
|
264
|
+
readonly options: ResolvedImportOptions;
|
|
265
|
+
readonly json: ResolvedJsonOptions;
|
|
266
|
+
readonly ids: IdCoercer;
|
|
267
|
+
readonly direction: DirectionResolver;
|
|
268
|
+
readonly nodes: AttributeWriter;
|
|
269
|
+
readonly edges: AttributeWriter;
|
|
270
|
+
/** Whether the caller passed `defaultDirected` explicitly (then it beats the dialect's convention). */
|
|
271
|
+
readonly explicitDefaultDirected: boolean;
|
|
272
|
+
/** Nodes and edges pushed since the signal was last checked. */
|
|
273
|
+
private elementsSinceCheck;
|
|
274
|
+
/**
|
|
275
|
+
* Create the context.
|
|
276
|
+
* @param sink - the sink
|
|
277
|
+
* @param report - the report
|
|
278
|
+
* @param options - the resolved common options
|
|
279
|
+
* @param json - the resolved format options
|
|
280
|
+
* @param explicitDefaultDirected - whether the caller passed defaultDirected
|
|
281
|
+
*/
|
|
282
|
+
constructor(sink: GraphSink, report: ImportReportBuilder, options: ResolvedImportOptions, json: ResolvedJsonOptions, explicitDefaultDirected: boolean);
|
|
283
|
+
/**
|
|
284
|
+
* Report a `nodeIdFrom` other than "id" for a dialect whose ids are unambiguous.
|
|
285
|
+
* @param dialect - the dialect
|
|
286
|
+
* @param idField - where the dialect's ids come from, for the message
|
|
287
|
+
*/
|
|
288
|
+
reportNodeIdFrom(dialect: JsonImportDialect, idField: string): void;
|
|
289
|
+
/**
|
|
290
|
+
* The direction assumed when the file declares none: the caller's `defaultDirected` when given,
|
|
291
|
+
* else the dialect's convention.
|
|
292
|
+
* @param dialect - the dialect
|
|
293
|
+
* @returns the direction
|
|
294
|
+
*/
|
|
295
|
+
defaultDirected(dialect: JsonImportDialect): boolean;
|
|
296
|
+
/** The direction the file declares (or the default), set by setHeader(). */
|
|
297
|
+
private fileDirected;
|
|
298
|
+
/**
|
|
299
|
+
* Rule 1 of design section 8.4: set the sink's direction from the file's header (or the
|
|
300
|
+
* dialect's default) before the first edge, remembering the file's direction for uniformKind().
|
|
301
|
+
* @param directed - the file's direction
|
|
302
|
+
*/
|
|
303
|
+
setHeader(directed: boolean): void;
|
|
304
|
+
/**
|
|
305
|
+
* The edge kind every edge of a dialect without per-edge direction has: the file's direction
|
|
306
|
+
* (the resolver expands it when the sink's direction differs).
|
|
307
|
+
* @returns the kind
|
|
308
|
+
*/
|
|
309
|
+
uniformKind(): EdgeKind;
|
|
310
|
+
/**
|
|
311
|
+
* Coerce a node id value per the `ids` option, reporting what cannot be an id. A JSON boolean or
|
|
312
|
+
* null is `unsupported` unless `ids` is "string" (design section 8.5); anything the rule rejects
|
|
313
|
+
* is recorded through the per-element catch.
|
|
314
|
+
* @param raw - the JSON value; undefined when the record has no id key
|
|
315
|
+
* @param element - the element name for the issue
|
|
316
|
+
* @returns the id, or null when the value was reported and the element must be skipped
|
|
317
|
+
*/
|
|
318
|
+
coerceId(raw: unknown, element: string): NodeId | null;
|
|
319
|
+
/**
|
|
320
|
+
* Coerce an id that must be valid for the caller to proceed (hyperedge members): the rejections
|
|
321
|
+
* of coerceId() are thrown instead of recorded.
|
|
322
|
+
* @param raw - the JSON value
|
|
323
|
+
* @param element - the element name
|
|
324
|
+
* @returns the id
|
|
325
|
+
*/
|
|
326
|
+
requireId(raw: unknown, element: string): NodeId;
|
|
327
|
+
/**
|
|
328
|
+
* Add a node, counting it or recording the failure.
|
|
329
|
+
* @param id - the node id
|
|
330
|
+
* @param element - the element name
|
|
331
|
+
* @returns the node index, or -1 when the sink refused the node
|
|
332
|
+
*/
|
|
333
|
+
pushNode(id: NodeId, element: string): number;
|
|
334
|
+
/**
|
|
335
|
+
* Push one edge through the direction resolver, counting every logical edge the sink gained
|
|
336
|
+
* (both halves of an expanded edge, and the mirrors of an in-place expansion).
|
|
337
|
+
* @param source - the source id
|
|
338
|
+
* @param target - the target id
|
|
339
|
+
* @param kind - the edge's direction in the file
|
|
340
|
+
* @param weight - the weight, or undefined
|
|
341
|
+
* @param element - the element name for issues
|
|
342
|
+
* @returns the primary edge index
|
|
343
|
+
*/
|
|
344
|
+
pushEdge(source: NodeId, target: NodeId, kind: EdgeKind, weight: number | undefined, element: string): number;
|
|
345
|
+
/**
|
|
346
|
+
* Check the cancellation signal every ABORT_CHECK_INTERVAL pushed elements, so an abort raised
|
|
347
|
+
* while the whole in-memory document is being walked rejects promptly.
|
|
348
|
+
*/
|
|
349
|
+
checkAbort(): void;
|
|
350
|
+
/**
|
|
351
|
+
* Record a per-element failure and count the skipped element.
|
|
352
|
+
* @param err - the thrown value
|
|
353
|
+
* @param domain - which counter to bump
|
|
354
|
+
* @param element - the element name
|
|
355
|
+
*/
|
|
356
|
+
skip(err: unknown, domain: "node" | "edge", element: string): void;
|
|
357
|
+
/**
|
|
358
|
+
* Report an element that is not an object and count it as skipped.
|
|
359
|
+
* @param domain - node or edge
|
|
360
|
+
* @param element - the element name
|
|
361
|
+
* @param what - what was expected
|
|
362
|
+
*/
|
|
363
|
+
badElement(domain: "node" | "edge", element: string, what?: string): void;
|
|
364
|
+
/**
|
|
365
|
+
* Count a skipped element whose issue was already recorded.
|
|
366
|
+
* @param domain - node or edge
|
|
367
|
+
*/
|
|
368
|
+
countSkipped(domain: "node" | "edge"): void;
|
|
369
|
+
/**
|
|
370
|
+
* Report an edge record without an endpoint and count it as skipped.
|
|
371
|
+
* @param element - the element name
|
|
372
|
+
* @param field - the missing field
|
|
373
|
+
*/
|
|
374
|
+
missingEndpoint(element: string, field: string): void;
|
|
375
|
+
/**
|
|
376
|
+
* Record the shape metadata, the source format and further metadata fields in one setMeta()
|
|
377
|
+
* call (the sink replaces `extra` as a whole).
|
|
378
|
+
* @param shape - the shape record
|
|
379
|
+
* @param patch - further metadata fields
|
|
380
|
+
*/
|
|
381
|
+
setMeta(shape: JsonShapeMeta, patch?: GraphMetaPatch): void;
|
|
382
|
+
/**
|
|
383
|
+
* Record which source field the weight came from, so the exporter writes it back under the same
|
|
384
|
+
* key (design section 3.7, `meta.weightOrigin`).
|
|
385
|
+
* @returns the metadata patch, empty for an unweighted import
|
|
386
|
+
*/
|
|
387
|
+
weightOriginPatch(): GraphMetaPatch;
|
|
388
|
+
/**
|
|
389
|
+
* Write the graph-level attributes of a dict (NetworkX `graph`, JGF `metadata`, graphology
|
|
390
|
+
* `attributes`, Cytoscape `data`), one column per key.
|
|
391
|
+
* @param dict - the dict, or anything else (then reported)
|
|
392
|
+
* @param what - the dict's name for the issue
|
|
393
|
+
*/
|
|
394
|
+
writeGraphDict(dict: unknown, what: string): void;
|
|
395
|
+
/**
|
|
396
|
+
* Read the weight field of an edge record.
|
|
397
|
+
* @param record - the record holding the attributes
|
|
398
|
+
* @returns the weight, or undefined when absent or null; E_INVALID_WEIGHT otherwise
|
|
399
|
+
*/
|
|
400
|
+
weightOf(record: JsonRecord): number | undefined;
|
|
401
|
+
/**
|
|
402
|
+
* Write the attributes of a nested dict plus the element-level keys the dialect does not
|
|
403
|
+
* define (kept with the `#element` suffix).
|
|
404
|
+
* @param writer - the table writer
|
|
405
|
+
* @param row - the row
|
|
406
|
+
* @param record - the element record
|
|
407
|
+
* @param dict - the nested attribute dict
|
|
408
|
+
* @param structural - the element keys that are not attributes
|
|
409
|
+
* @param weightFrom - the weight key to skip in the dict, or null
|
|
410
|
+
*/
|
|
411
|
+
writeNested(writer: AttributeWriter, row: number, record: JsonRecord, dict: JsonRecord, structural: ReadonlySet<string>, weightFrom: string | null): void;
|
|
412
|
+
/**
|
|
413
|
+
* Write a spec-typed string field (JGF label / relation), reporting a value of another type.
|
|
414
|
+
* @param writer - the table writer
|
|
415
|
+
* @param column - the declared column, or INVALID_INDEX when the file has no such field
|
|
416
|
+
* @param row - the row
|
|
417
|
+
* @param value - the value
|
|
418
|
+
* @param field - the field name
|
|
419
|
+
* @param element - the element name
|
|
420
|
+
*/
|
|
421
|
+
writeStringField(writer: AttributeWriter, column: ColumnHandle, row: number, value: unknown, field: string, element: string): void;
|
|
422
|
+
/**
|
|
423
|
+
* Declare an edge id column with role "id" from a scan of the file's edge ids: f64 when every
|
|
424
|
+
* id is a number, string otherwise (numbers are then stored as their text and reported once).
|
|
425
|
+
* @param edges - the edge records
|
|
426
|
+
* @param read - how to read an edge's raw id
|
|
427
|
+
* @param name - the column name
|
|
428
|
+
* @param unique - whether uniqueness is enforced at freeze
|
|
429
|
+
* @returns the column, or null when no edge has an id
|
|
430
|
+
*/
|
|
431
|
+
declareEdgeIds(edges: readonly unknown[], read: (edge: JsonRecord) => unknown, name: string, unique: boolean): EdgeIdColumn | null;
|
|
432
|
+
/**
|
|
433
|
+
* The value an edge id column stores for a raw id, checked BEFORE the edge is pushed so a bad
|
|
434
|
+
* id skips the edge without touching the sink (design section 11.1).
|
|
435
|
+
* @param column - the column, or null when the file has no edge ids
|
|
436
|
+
* @param raw - the raw id value
|
|
437
|
+
* @returns the value to store, or null when there is nothing to store
|
|
438
|
+
*/
|
|
439
|
+
edgeIdValue(column: EdgeIdColumn | null, raw: unknown): string | number | null;
|
|
440
|
+
/**
|
|
441
|
+
* Write an edge id value from edgeIdValue().
|
|
442
|
+
* @param column - the column, or null
|
|
443
|
+
* @param edge - the edge index
|
|
444
|
+
* @param value - the value, or null for none
|
|
445
|
+
*/
|
|
446
|
+
setEdgeId(column: EdgeIdColumn | null, edge: number, value: string | number | null): void;
|
|
447
|
+
}
|
|
448
|
+
/**
|
|
449
|
+
* The graph of a `graphs` array (JGF, OBO Graphs) that graphIndex / graphName choose, with
|
|
450
|
+
* W_MULTIPLE_GRAPHS when the others are skipped; importAll() reads graphs[graphIndex].
|
|
451
|
+
* @param ctx - the context
|
|
452
|
+
* @param root - the document
|
|
453
|
+
* @param what - the dialect's name, for the messages
|
|
454
|
+
* @returns the graph object; the import fails when there is none
|
|
455
|
+
*/
|
|
456
|
+
export declare function chosenGraph(ctx: ImportContext, root: JsonRecord, what: string): JsonRecord;
|
|
141
457
|
/**
|
|
142
458
|
* The JSON importer plugin (design section 8.4).
|
|
143
459
|
*/
|
|
144
460
|
export declare const jsonImporter: GraphImporter<JsonImportOptions>;
|
|
461
|
+
export {};
|
|
145
462
|
//# sourceMappingURL=importer.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"importer.d.ts","sourceRoot":"","sources":["../../../../src/formats/json/importer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;
|
|
1
|
+
{"version":3,"file":"importer.d.ts","sourceRoot":"","sources":["../../../../src/formats/json/importer.ts"],"names":[],"mappings":"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"}
|
|
@@ -32,14 +32,15 @@
|
|
|
32
32
|
*/
|
|
33
33
|
import { GraphFormatError, INVALID_INDEX, } from "@graphty/graph-format";
|
|
34
34
|
import { uniqueColumnName } from "../../common/attributes.js";
|
|
35
|
-
import { BAD_VALUE_CODE, DUPLICATE_EDGE_ID_CODE, DUPLICATE_NODE_CODE, EMPTY_INPUT_CODE, ENCODING_FALLBACK_CODE, HYPEREDGE_CODE, INVALID_ENCODING_CODE, INVALID_UTF8_CODE, MISSING_ENDPOINT_CODE, MISSING_ID_CODE, MULTIPLE_GRAPHS_CODE, OPTION_IGNORED_CODE, SYNTAX_CODE, UNKNOWN_ENCODING_CODE, UNKNOWN_PARENT_CODE, } from "../../common/codes.js";
|
|
35
|
+
import { AMBIGUOUS_GRAPH_NAME_CODE, BAD_VALUE_CODE, DANGLING_REFERENCE_CODE, DUPLICATE_EDGE_ID_CODE, DUPLICATE_NODE_CODE, EMPTY_INPUT_CODE, ENCODING_FALLBACK_CODE, GRAPH_NOT_FOUND_CODE, HYPEREDGE_CODE, INVALID_ENCODING_CODE, INVALID_UTF8_CODE, MISSING_ENDPOINT_CODE, MISSING_ID_CODE, MULTIPLE_GRAPHS_CODE, OPTION_IGNORED_CODE, SYNTAX_CODE, TOO_LARGE_CODE, UNKNOWN_ENCODING_CODE, UNKNOWN_PARENT_CODE, } from "../../common/codes.js";
|
|
36
36
|
import { DirectionResolver } from "../../common/direction.js";
|
|
37
37
|
import { ID_MERGED_CODE, IdCoercer } from "../../common/ids.js";
|
|
38
|
-
import { readText, throwIfAborted } from "../../common/input.js";
|
|
39
|
-
import { reportSinkOptions, reportUnusedOptions, resolveImportOptions, SINK_OPTION_CODE, } from "../../common/options.js";
|
|
38
|
+
import { readText, textChunks, throwIfAborted } from "../../common/input.js";
|
|
39
|
+
import { chooseGraph, reportSinkOptions, reportUnusedOptions, resolveImportOptions, SINK_OPTION_CODE, } from "../../common/options.js";
|
|
40
40
|
import { ImportReportBuilder } from "../../common/report.js";
|
|
41
41
|
import { weightFromValue } from "../../common/weights.js";
|
|
42
42
|
import { CLASSES_COLUMN, CYTOSCAPE_ELEMENT_KEYS, CYTOSCAPE_STRUCTURAL_KEYS, DIALECT_DEFAULT_DIRECTED, hasKey, isJsonImportDialect, isJsonObject, JSON_IMPORT_DIALECTS, META_KEY, NODE_LINK_SOURCE_KEYS, NODE_LINK_TARGET_KEYS, PARENT_COLUMN, POSITION_COLUMN, sniffJsonDialect, SUFFIX, } from "./dialect.js";
|
|
43
|
+
import { importObographs } from "./obographs.js";
|
|
43
44
|
/**
|
|
44
45
|
* The issue codes the JSON importer records (design section 8.6), by name: the codes shared with
|
|
45
46
|
* the other importers (src/common/codes.ts) and the JSON-specific ones. A key is the code without
|
|
@@ -80,8 +81,18 @@ export const JSON_ISSUE = Object.freeze({
|
|
|
80
81
|
ID_MERGED: ID_MERGED_CODE,
|
|
81
82
|
/** Edge ids of mixed JSON types were stored as text. */
|
|
82
83
|
EDGE_ID_STRINGIFIED: "W_EDGE_ID_STRINGIFIED",
|
|
83
|
-
/** A JGF `graphs` array holds more than one graph; only
|
|
84
|
+
/** A JGF or OBO Graphs `graphs` array holds more than one graph; only the chosen one is read. */
|
|
84
85
|
MULTIPLE_GRAPHS: MULTIPLE_GRAPHS_CODE,
|
|
86
|
+
/** `graphIndex` is beyond the `graphs` array, or `graphName` names none of its graphs (fatal). */
|
|
87
|
+
GRAPH_NOT_FOUND: GRAPH_NOT_FOUND_CODE,
|
|
88
|
+
/** `graphName` names more than one graph of the `graphs` array (fatal). */
|
|
89
|
+
AMBIGUOUS_GRAPH_NAME: AMBIGUOUS_GRAPH_NAME_CODE,
|
|
90
|
+
/** obographs: an edge uses the outdated `subj` key of the OBO Graphs README; it is read as `sub`. */
|
|
91
|
+
OBOGRAPHS_SUBJ: "W_JSON_OBOGRAPHS_SUBJ",
|
|
92
|
+
/** obographs: an edge endpoint missing from `nodes` (a placeholder node is made, or the edge dropped under addMissingNodes false). */
|
|
93
|
+
DANGLING_REFERENCE: DANGLING_REFERENCE_CODE,
|
|
94
|
+
/** The document is longer than one JavaScript string can hold (fatal; category unsupported). */
|
|
95
|
+
TOO_LARGE: TOO_LARGE_CODE,
|
|
85
96
|
/** JGF hyperedges under the "error" policy. */
|
|
86
97
|
HYPEREDGE: HYPEREDGE_CODE,
|
|
87
98
|
/** JGF hyperedges skipped under the default "skip" policy. */
|
|
@@ -180,6 +191,14 @@ function resolveJsonOptions(options) {
|
|
|
180
191
|
if (!Number.isInteger(graphIndex) || graphIndex < 0) {
|
|
181
192
|
throw unsupportedOption("graphIndex", graphIndex, ["a non-negative integer"]);
|
|
182
193
|
}
|
|
194
|
+
const oboIds = o.oboIds ?? "curie";
|
|
195
|
+
if (oboIds !== "curie" && oboIds !== "iri") {
|
|
196
|
+
throw unsupportedOption("oboIds", oboIds, ["curie", "iri"]);
|
|
197
|
+
}
|
|
198
|
+
const typedefs = o.typedefs ?? "metadata";
|
|
199
|
+
if (typedefs !== "metadata" && typedefs !== "nodes") {
|
|
200
|
+
throw unsupportedOption("typedefs", typedefs, ["metadata", "nodes"]);
|
|
201
|
+
}
|
|
183
202
|
const nodesPath = pathOption("nodesPath", o.nodesPath);
|
|
184
203
|
const edgesPath = pathOption("edgesPath", o.edgesPath);
|
|
185
204
|
if ((nodesPath !== null || edgesPath !== null) && dialect !== "auto" && !PATH_DIALECTS.has(dialect)) {
|
|
@@ -193,6 +212,9 @@ function resolveJsonOptions(options) {
|
|
|
193
212
|
targetKey: keyOption("targetKey", o.targetKey),
|
|
194
213
|
indexLinks,
|
|
195
214
|
graphIndex,
|
|
215
|
+
choice: { graphIndex: o.graphIndex, graphName: o.graphName },
|
|
216
|
+
oboIds,
|
|
217
|
+
typedefs,
|
|
196
218
|
nodesPath,
|
|
197
219
|
edgesPath,
|
|
198
220
|
};
|
|
@@ -493,7 +515,7 @@ class AttributeWriter {
|
|
|
493
515
|
/**
|
|
494
516
|
* Everything one import call shares between the dialect readers.
|
|
495
517
|
*/
|
|
496
|
-
class ImportContext {
|
|
518
|
+
export class ImportContext {
|
|
497
519
|
/**
|
|
498
520
|
* Create the context.
|
|
499
521
|
* @param sink - the sink
|
|
@@ -1906,32 +1928,123 @@ function importJgf(ctx, root) {
|
|
|
1906
1928
|
ctx.setMeta(shape, { name: label, ...ctx.weightOriginPatch() });
|
|
1907
1929
|
}
|
|
1908
1930
|
/**
|
|
1909
|
-
* The graph object of a JGF document: `graph`, or `graphs
|
|
1931
|
+
* The graph object of a JGF document: `graph`, or the graph of `graphs` that graphIndex /
|
|
1932
|
+
* graphName choose (chooseGraph()).
|
|
1910
1933
|
* @param ctx - the context
|
|
1911
1934
|
* @param root - the document
|
|
1912
1935
|
* @returns the graph object; the import fails when there is none
|
|
1913
1936
|
*/
|
|
1914
1937
|
function jgfGraphOf(ctx, root) {
|
|
1938
|
+
return isJsonObject(root.graph) ? root.graph : chosenGraph(ctx, root, "JGF");
|
|
1939
|
+
}
|
|
1940
|
+
/**
|
|
1941
|
+
* The graph of a `graphs` array (JGF, OBO Graphs) that graphIndex / graphName choose, with
|
|
1942
|
+
* W_MULTIPLE_GRAPHS when the others are skipped; importAll() reads graphs[graphIndex].
|
|
1943
|
+
* @param ctx - the context
|
|
1944
|
+
* @param root - the document
|
|
1945
|
+
* @param what - the dialect's name, for the messages
|
|
1946
|
+
* @returns the graph object; the import fails when there is none
|
|
1947
|
+
*/
|
|
1948
|
+
export function chosenGraph(ctx, root, what) {
|
|
1915
1949
|
const { report } = ctx;
|
|
1916
|
-
if (isJsonObject(root.graph)) {
|
|
1917
|
-
return root.graph;
|
|
1918
|
-
}
|
|
1919
1950
|
const graphs = arraySection(root.graphs, "graphs", report) ?? [];
|
|
1920
1951
|
if (graphs.length === 0) {
|
|
1921
|
-
report.fail(JSON_ISSUE.SHAPE,
|
|
1952
|
+
report.fail(JSON_ISSUE.SHAPE, `a ${what} document needs a graph object or a non-empty graphs array`);
|
|
1922
1953
|
}
|
|
1954
|
+
const index = ctx.json.all === true ? ctx.json.graphIndex : chooseGraph(graphs.map(graphNameOf), ctx.json.choice, report);
|
|
1923
1955
|
if (graphs.length > 1 && ctx.json.all !== true) {
|
|
1924
|
-
report.warning("unsupported", JSON_ISSUE.MULTIPLE_GRAPHS, `the document holds ${graphs.length} graphs; only graphs[${
|
|
1956
|
+
report.warning("unsupported", JSON_ISSUE.MULTIPLE_GRAPHS, `the document holds ${graphs.length} graphs; only graphs[${index}] is read (${graphs.length - 1} skipped), importAll() reads every one`, { element: "graphs" });
|
|
1925
1957
|
}
|
|
1926
|
-
|
|
1927
|
-
report.fail(JSON_ISSUE.SHAPE, `graphIndex ${ctx.json.graphIndex} is beyond the ${graphs.length} graph(s)`);
|
|
1928
|
-
}
|
|
1929
|
-
const graph = graphs[ctx.json.graphIndex];
|
|
1958
|
+
const graph = graphs[index];
|
|
1930
1959
|
if (!isJsonObject(graph)) {
|
|
1931
|
-
return report.fail(JSON_ISSUE.SHAPE, `graphs[${
|
|
1960
|
+
return report.fail(JSON_ISSUE.SHAPE, `graphs[${index}] is not an object`);
|
|
1932
1961
|
}
|
|
1933
1962
|
return graph;
|
|
1934
1963
|
}
|
|
1964
|
+
/**
|
|
1965
|
+
* The name a graph of a `graphs` array is listed and chosen by: its `id`, else its `label` (JGF)
|
|
1966
|
+
* or `lbl` (OBO Graphs).
|
|
1967
|
+
* @param graph - the graph
|
|
1968
|
+
* @returns the name, or null
|
|
1969
|
+
*/
|
|
1970
|
+
function graphNameOf(graph) {
|
|
1971
|
+
if (!isJsonObject(graph)) {
|
|
1972
|
+
return null;
|
|
1973
|
+
}
|
|
1974
|
+
for (const key of ["id", "label", "lbl"]) {
|
|
1975
|
+
if (typeof graph[key] === "string") {
|
|
1976
|
+
return graph[key];
|
|
1977
|
+
}
|
|
1978
|
+
}
|
|
1979
|
+
return null;
|
|
1980
|
+
}
|
|
1981
|
+
/**
|
|
1982
|
+
* How many elements a nodes or edges section holds: an array's length, an object's key count, 0
|
|
1983
|
+
* when absent, null for anything else.
|
|
1984
|
+
* @param section - the section
|
|
1985
|
+
* @returns the count, or null
|
|
1986
|
+
*/
|
|
1987
|
+
function countOf(section) {
|
|
1988
|
+
if (section === undefined || section === null) {
|
|
1989
|
+
return 0;
|
|
1990
|
+
}
|
|
1991
|
+
if (Array.isArray(section)) {
|
|
1992
|
+
return section.length;
|
|
1993
|
+
}
|
|
1994
|
+
return isJsonObject(section) ? Object.keys(section).length : null;
|
|
1995
|
+
}
|
|
1996
|
+
/**
|
|
1997
|
+
* The graphs of a parsed document, for listGraphs(): each entry of a JGF or OBO Graphs `graphs`
|
|
1998
|
+
* array with its name and counts; any other document holds one graph.
|
|
1999
|
+
* @param root - the parsed document
|
|
2000
|
+
* @param dialect - its dialect
|
|
2001
|
+
* @returns the listings
|
|
2002
|
+
*/
|
|
2003
|
+
function listingsOf(root, dialect) {
|
|
2004
|
+
if ((dialect === "jgf" || dialect === "obographs") && isJsonObject(root)) {
|
|
2005
|
+
if (Array.isArray(root.graphs) && !isJsonObject(root.graph)) {
|
|
2006
|
+
return root.graphs.map((graph, index) => ({
|
|
2007
|
+
index,
|
|
2008
|
+
name: graphNameOf(graph),
|
|
2009
|
+
nodes: isJsonObject(graph) ? countOf(graph.nodes) : null,
|
|
2010
|
+
edges: isJsonObject(graph) ? countOf(graph.edges) : null,
|
|
2011
|
+
}));
|
|
2012
|
+
}
|
|
2013
|
+
if (isJsonObject(root.graph)) {
|
|
2014
|
+
const { graph } = root;
|
|
2015
|
+
return [{ index: 0, name: graphNameOf(graph), nodes: countOf(graph.nodes), edges: countOf(graph.edges) }];
|
|
2016
|
+
}
|
|
2017
|
+
}
|
|
2018
|
+
return [{ index: 0, name: null, nodes: null, edges: null }];
|
|
2019
|
+
}
|
|
2020
|
+
/** The longest string V8 makes (2^29 - 24 UTF-16 code units); a longer document cannot be one JSON.parse input. */
|
|
2021
|
+
const MAX_TEXT_LENGTH = 2 ** 29 - 24;
|
|
2022
|
+
/**
|
|
2023
|
+
* Read the whole input as one string, failing with E_TOO_LARGE (category unsupported) before the
|
|
2024
|
+
* join when it is longer than one JavaScript string can hold (OBO Graphs files such as
|
|
2025
|
+
* ncbitaxon.json are; design 7.1 defers streaming the JSON reader).
|
|
2026
|
+
* @param input - the input
|
|
2027
|
+
* @param report - the report
|
|
2028
|
+
* @param options - cancellation, progress and encoding
|
|
2029
|
+
* @returns the text
|
|
2030
|
+
*/
|
|
2031
|
+
async function readJsonText(input, report, options) {
|
|
2032
|
+
if (typeof input === "string") {
|
|
2033
|
+
return readText(input, report, options);
|
|
2034
|
+
}
|
|
2035
|
+
const parts = [];
|
|
2036
|
+
let length = 0;
|
|
2037
|
+
for await (const chunk of textChunks(input, report, options)) {
|
|
2038
|
+
length += chunk.length;
|
|
2039
|
+
if (length > MAX_TEXT_LENGTH) {
|
|
2040
|
+
const message = `the document is longer than ${MAX_TEXT_LENGTH} characters, the most one JavaScript string holds`;
|
|
2041
|
+
report.error("unsupported", JSON_ISSUE.TOO_LARGE, message);
|
|
2042
|
+
throw report.abort(message, { code: JSON_ISSUE.TOO_LARGE });
|
|
2043
|
+
}
|
|
2044
|
+
parts.push(chunk);
|
|
2045
|
+
}
|
|
2046
|
+
return parts.length === 1 ? parts[0] : parts.join("");
|
|
2047
|
+
}
|
|
1935
2048
|
/**
|
|
1936
2049
|
* Push a JGF node: `label` into the declared column, `metadata` as attributes.
|
|
1937
2050
|
* @param ctx - the context
|
|
@@ -2321,11 +2434,27 @@ export const jsonImporter = Object.freeze({
|
|
|
2321
2434
|
const resolved = resolveImportOptions(options, FORMAT_DEFAULTS);
|
|
2322
2435
|
const json = resolveJsonOptions(options);
|
|
2323
2436
|
const report = new ImportReportBuilder("json", resolved.errorLimit);
|
|
2324
|
-
const text = await
|
|
2437
|
+
const text = await readJsonText(input, report, resolved);
|
|
2325
2438
|
const { root, dialect } = documentOf(parseDocument(text, report), json, report);
|
|
2326
2439
|
readGraph(root, dialect, sink, report, resolved, json, options);
|
|
2327
2440
|
return report.finish();
|
|
2328
2441
|
},
|
|
2442
|
+
/**
|
|
2443
|
+
* List the graphs of a JSON document without importing them: each entry of a JGF or OBO
|
|
2444
|
+
* Graphs `graphs` array with its name (`id`, else its label) and node and edge counts; any
|
|
2445
|
+
* other document holds one graph.
|
|
2446
|
+
* @param input - the text, bytes or stream
|
|
2447
|
+
* @param options - format-specific and common options
|
|
2448
|
+
* @returns one listing per graph
|
|
2449
|
+
*/
|
|
2450
|
+
async listGraphs(input, options) {
|
|
2451
|
+
const resolved = resolveImportOptions(options, FORMAT_DEFAULTS);
|
|
2452
|
+
const json = resolveJsonOptions(options);
|
|
2453
|
+
const report = new ImportReportBuilder("json", resolved.errorLimit);
|
|
2454
|
+
const text = await readJsonText(input, report, resolved);
|
|
2455
|
+
const { root, dialect } = documentOf(parseDocument(text, report), json, report);
|
|
2456
|
+
return listingsOf(root, dialect);
|
|
2457
|
+
},
|
|
2329
2458
|
/**
|
|
2330
2459
|
* Read every graph of a JSON document: each entry of a JGF `graphs` array into its own sink;
|
|
2331
2460
|
* any other document holds one graph.
|
|
@@ -2338,11 +2467,9 @@ export const jsonImporter = Object.freeze({
|
|
|
2338
2467
|
const resolved = resolveImportOptions(options, FORMAT_DEFAULTS);
|
|
2339
2468
|
const json = resolveJsonOptions(options);
|
|
2340
2469
|
const first = new ImportReportBuilder("json", resolved.errorLimit);
|
|
2341
|
-
const text = await
|
|
2470
|
+
const text = await readJsonText(input, first, resolved);
|
|
2342
2471
|
const { root, dialect } = documentOf(parseDocument(text, first), json, first);
|
|
2343
|
-
const graphs =
|
|
2344
|
-
? root.graphs.length
|
|
2345
|
-
: 1;
|
|
2472
|
+
const graphs = listingsOf(root, dialect).length;
|
|
2346
2473
|
const reports = [];
|
|
2347
2474
|
for (let i = 0; i < Math.max(graphs, 1); i++) {
|
|
2348
2475
|
const report = i === 0 ? first : new ImportReportBuilder("json", resolved.errorLimit);
|
|
@@ -2364,7 +2491,8 @@ export const jsonImporter = Object.freeze({
|
|
|
2364
2491
|
*/
|
|
2365
2492
|
function readGraph(root, dialect, sink, report, resolved, json, options) {
|
|
2366
2493
|
const ctx = new ImportContext(sink, report, resolved, json, options?.defaultDirected !== undefined);
|
|
2367
|
-
|
|
2494
|
+
// the obographs reader refuses missing endpoints itself, so addMissingNodes false holds on any sink
|
|
2495
|
+
reportSinkOptions(sink, options, report, dialect === "obographs");
|
|
2368
2496
|
reportUnusedOptions(options, report, USED_OPTIONS);
|
|
2369
2497
|
if (dialect === "cytoscape") {
|
|
2370
2498
|
importCytoscape(ctx, root);
|
|
@@ -2394,6 +2522,9 @@ function readGraph(root, dialect, sink, report, resolved, json, options) {
|
|
|
2394
2522
|
case "tree":
|
|
2395
2523
|
importTree(ctx, doc);
|
|
2396
2524
|
break;
|
|
2525
|
+
case "obographs":
|
|
2526
|
+
importObographs(ctx, doc);
|
|
2527
|
+
break;
|
|
2397
2528
|
default: {
|
|
2398
2529
|
const name = dialect;
|
|
2399
2530
|
throw new GraphFormatError("E_UNSUPPORTED", `unknown dialect ${name}`, {
|