@graphty/graph-io 0.0.0 → 0.2.1
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 +21 -0
- package/README.md +250 -28
- package/dist/chunks/children-CL3Cy0ez.js +238 -0
- package/dist/chunks/children-CL3Cy0ez.js.map +1 -0
- package/dist/chunks/escape-DyI8JofU.js +938 -0
- package/dist/chunks/escape-DyI8JofU.js.map +1 -0
- package/dist/chunks/importer-CQnJuWJw.js +2987 -0
- package/dist/chunks/importer-CQnJuWJw.js.map +1 -0
- package/dist/chunks/importer-CpCpfbxr.js +2015 -0
- package/dist/chunks/importer-CpCpfbxr.js.map +1 -0
- package/dist/chunks/importer-DbnGYr3_.js +2342 -0
- package/dist/chunks/importer-DbnGYr3_.js.map +1 -0
- package/dist/chunks/importer-GozH8DkN.js +3050 -0
- package/dist/chunks/importer-GozH8DkN.js.map +1 -0
- package/dist/chunks/records-CGpxszm1.js +605 -0
- package/dist/chunks/records-CGpxszm1.js.map +1 -0
- package/dist/chunks/text-CajMdVFy.js +189 -0
- package/dist/chunks/text-CajMdVFy.js.map +1 -0
- package/dist/chunks/writer-DxSKC7TL.js +2842 -0
- package/dist/chunks/writer-DxSKC7TL.js.map +1 -0
- package/dist/csv.d.ts +1 -0
- package/dist/csv.js +1702 -0
- package/dist/csv.js.map +1 -0
- package/dist/dot.d.ts +1 -0
- package/dist/dot.js +8 -0
- package/dist/dot.js.map +1 -0
- package/dist/gexf.d.ts +1 -0
- package/dist/gexf.js +3466 -0
- package/dist/gexf.js.map +1 -0
- package/dist/gml.d.ts +1 -0
- package/dist/gml.js +2647 -0
- package/dist/gml.js.map +1 -0
- package/dist/graph-io.d.ts +1 -0
- package/dist/graph-io.js +790 -0
- package/dist/graph-io.js.map +1 -0
- package/dist/graphml.d.ts +1 -0
- package/dist/graphml.js +8 -0
- package/dist/graphml.js.map +1 -0
- package/dist/json.d.ts +1 -0
- package/dist/json.js +11 -0
- package/dist/json.js.map +1 -0
- package/dist/neo4j.d.ts +1 -0
- package/dist/neo4j.js +2046 -0
- package/dist/neo4j.js.map +1 -0
- package/dist/pajek.d.ts +1 -0
- package/dist/pajek.js +8 -0
- package/dist/pajek.js.map +1 -0
- package/dist/src/children.d.ts +134 -0
- package/dist/src/children.d.ts.map +1 -0
- package/dist/src/children.js +274 -0
- package/dist/src/children.js.map +1 -0
- package/dist/src/common/attributes.d.ts +229 -0
- package/dist/src/common/attributes.d.ts.map +1 -0
- package/dist/src/common/attributes.js +368 -0
- package/dist/src/common/attributes.js.map +1 -0
- package/dist/src/common/codes.d.ts +105 -0
- package/dist/src/common/codes.d.ts.map +1 -0
- package/dist/src/common/codes.js +107 -0
- package/dist/src/common/codes.js.map +1 -0
- package/dist/src/common/declared-types.d.ts +84 -0
- package/dist/src/common/declared-types.d.ts.map +1 -0
- package/dist/src/common/declared-types.js +326 -0
- package/dist/src/common/declared-types.js.map +1 -0
- package/dist/src/common/direction.d.ts +206 -0
- package/dist/src/common/direction.d.ts.map +1 -0
- package/dist/src/common/direction.js +370 -0
- package/dist/src/common/direction.js.map +1 -0
- package/dist/src/common/escape.d.ts +92 -0
- package/dist/src/common/escape.d.ts.map +1 -0
- package/dist/src/common/escape.js +212 -0
- package/dist/src/common/escape.js.map +1 -0
- package/dist/src/common/export.d.ts +249 -0
- package/dist/src/common/export.d.ts.map +1 -0
- package/dist/src/common/export.js +594 -0
- package/dist/src/common/export.js.map +1 -0
- package/dist/src/common/format.d.ts +59 -0
- package/dist/src/common/format.d.ts.map +1 -0
- package/dist/src/common/format.js +106 -0
- package/dist/src/common/format.js.map +1 -0
- package/dist/src/common/ids.d.ts +83 -0
- package/dist/src/common/ids.d.ts.map +1 -0
- package/dist/src/common/ids.js +158 -0
- package/dist/src/common/ids.js.map +1 -0
- package/dist/src/common/input.d.ts +100 -0
- package/dist/src/common/input.d.ts.map +1 -0
- package/dist/src/common/input.js +335 -0
- package/dist/src/common/input.js.map +1 -0
- package/dist/src/common/lists.d.ts +34 -0
- package/dist/src/common/lists.d.ts.map +1 -0
- package/dist/src/common/lists.js +185 -0
- package/dist/src/common/lists.js.map +1 -0
- package/dist/src/common/options.d.ts +108 -0
- package/dist/src/common/options.d.ts.map +1 -0
- package/dist/src/common/options.js +265 -0
- package/dist/src/common/options.js.map +1 -0
- package/dist/src/common/report.d.ts +187 -0
- package/dist/src/common/report.d.ts.map +1 -0
- package/dist/src/common/report.js +274 -0
- package/dist/src/common/report.js.map +1 -0
- package/dist/src/common/temporal.d.ts +71 -0
- package/dist/src/common/temporal.d.ts.map +1 -0
- package/dist/src/common/temporal.js +266 -0
- package/dist/src/common/temporal.js.map +1 -0
- package/dist/src/common/text.d.ts +104 -0
- package/dist/src/common/text.d.ts.map +1 -0
- package/dist/src/common/text.js +255 -0
- package/dist/src/common/text.js.map +1 -0
- package/dist/src/common/weights.d.ts +77 -0
- package/dist/src/common/weights.d.ts.map +1 -0
- package/dist/src/common/weights.js +156 -0
- package/dist/src/common/weights.js.map +1 -0
- package/dist/src/common/writer.d.ts +51 -0
- package/dist/src/common/writer.d.ts.map +1 -0
- package/dist/src/common/writer.js +108 -0
- package/dist/src/common/writer.js.map +1 -0
- package/dist/src/common/xml.d.ts +245 -0
- package/dist/src/common/xml.d.ts.map +1 -0
- package/dist/src/common/xml.js +942 -0
- package/dist/src/common/xml.js.map +1 -0
- package/dist/src/formats/csv/exporter.d.ts +70 -0
- package/dist/src/formats/csv/exporter.d.ts.map +1 -0
- package/dist/src/formats/csv/exporter.js +682 -0
- package/dist/src/formats/csv/exporter.js.map +1 -0
- package/dist/src/formats/csv/header.d.ts +66 -0
- package/dist/src/formats/csv/header.d.ts.map +1 -0
- package/dist/src/formats/csv/header.js +152 -0
- package/dist/src/formats/csv/header.js.map +1 -0
- package/dist/src/formats/csv/importer.d.ts +82 -0
- package/dist/src/formats/csv/importer.d.ts.map +1 -0
- package/dist/src/formats/csv/importer.js +849 -0
- package/dist/src/formats/csv/importer.js.map +1 -0
- package/dist/src/formats/csv/index.d.ts +60 -0
- package/dist/src/formats/csv/index.d.ts.map +1 -0
- package/dist/src/formats/csv/index.js +63 -0
- package/dist/src/formats/csv/index.js.map +1 -0
- package/dist/src/formats/csv/records.d.ts +188 -0
- package/dist/src/formats/csv/records.d.ts.map +1 -0
- package/dist/src/formats/csv/records.js +702 -0
- package/dist/src/formats/csv/records.js.map +1 -0
- package/dist/src/formats/csv/values.d.ts +105 -0
- package/dist/src/formats/csv/values.d.ts.map +1 -0
- package/dist/src/formats/csv/values.js +192 -0
- package/dist/src/formats/csv/values.js.map +1 -0
- package/dist/src/formats/dot/exporter.d.ts +52 -0
- package/dist/src/formats/dot/exporter.d.ts.map +1 -0
- package/dist/src/formats/dot/exporter.js +836 -0
- package/dist/src/formats/dot/exporter.js.map +1 -0
- package/dist/src/formats/dot/importer.d.ts +102 -0
- package/dist/src/formats/dot/importer.d.ts.map +1 -0
- package/dist/src/formats/dot/importer.js +1291 -0
- package/dist/src/formats/dot/importer.js.map +1 -0
- package/dist/src/formats/dot/index.d.ts +7 -0
- package/dist/src/formats/dot/index.d.ts.map +1 -0
- package/dist/src/formats/dot/index.js +7 -0
- package/dist/src/formats/dot/index.js.map +1 -0
- package/dist/src/formats/dot/names.d.ts +29 -0
- package/dist/src/formats/dot/names.d.ts.map +1 -0
- package/dist/src/formats/dot/names.js +28 -0
- package/dist/src/formats/dot/names.js.map +1 -0
- package/dist/src/formats/dot/tokenizer.d.ts +114 -0
- package/dist/src/formats/dot/tokenizer.d.ts.map +1 -0
- package/dist/src/formats/dot/tokenizer.js +341 -0
- package/dist/src/formats/dot/tokenizer.js.map +1 -0
- package/dist/src/formats/gexf/exporter.d.ts +56 -0
- package/dist/src/formats/gexf/exporter.d.ts.map +1 -0
- package/dist/src/formats/gexf/exporter.js +1395 -0
- package/dist/src/formats/gexf/exporter.js.map +1 -0
- package/dist/src/formats/gexf/importer.d.ts +73 -0
- package/dist/src/formats/gexf/importer.d.ts.map +1 -0
- package/dist/src/formats/gexf/importer.js +1880 -0
- package/dist/src/formats/gexf/importer.js.map +1 -0
- package/dist/src/formats/gexf/index.d.ts +96 -0
- package/dist/src/formats/gexf/index.d.ts.map +1 -0
- package/dist/src/formats/gexf/index.js +97 -0
- package/dist/src/formats/gexf/index.js.map +1 -0
- package/dist/src/formats/gexf/schema.d.ts +135 -0
- package/dist/src/formats/gexf/schema.d.ts.map +1 -0
- package/dist/src/formats/gexf/schema.js +323 -0
- package/dist/src/formats/gexf/schema.js.map +1 -0
- package/dist/src/formats/gml/exporter.d.ts +69 -0
- package/dist/src/formats/gml/exporter.d.ts.map +1 -0
- package/dist/src/formats/gml/exporter.js +1093 -0
- package/dist/src/formats/gml/exporter.js.map +1 -0
- package/dist/src/formats/gml/importer.d.ts +66 -0
- package/dist/src/formats/gml/importer.d.ts.map +1 -0
- package/dist/src/formats/gml/importer.js +1331 -0
- package/dist/src/formats/gml/importer.js.map +1 -0
- package/dist/src/formats/gml/index.d.ts +85 -0
- package/dist/src/formats/gml/index.d.ts.map +1 -0
- package/dist/src/formats/gml/index.js +88 -0
- package/dist/src/formats/gml/index.js.map +1 -0
- package/dist/src/formats/gml/syntax.d.ts +186 -0
- package/dist/src/formats/gml/syntax.d.ts.map +1 -0
- package/dist/src/formats/gml/syntax.js +467 -0
- package/dist/src/formats/gml/syntax.js.map +1 -0
- package/dist/src/formats/graphml/constants.d.ts +169 -0
- package/dist/src/formats/graphml/constants.d.ts.map +1 -0
- package/dist/src/formats/graphml/constants.js +165 -0
- package/dist/src/formats/graphml/constants.js.map +1 -0
- package/dist/src/formats/graphml/exporter.d.ts +34 -0
- package/dist/src/formats/graphml/exporter.d.ts.map +1 -0
- package/dist/src/formats/graphml/exporter.js +1176 -0
- package/dist/src/formats/graphml/exporter.js.map +1 -0
- package/dist/src/formats/graphml/importer.d.ts +31 -0
- package/dist/src/formats/graphml/importer.d.ts.map +1 -0
- package/dist/src/formats/graphml/importer.js +1607 -0
- package/dist/src/formats/graphml/importer.js.map +1 -0
- package/dist/src/formats/graphml/index.d.ts +8 -0
- package/dist/src/formats/graphml/index.d.ts.map +1 -0
- package/dist/src/formats/graphml/index.js +8 -0
- package/dist/src/formats/graphml/index.js.map +1 -0
- package/dist/src/formats/graphml/tree.d.ts +72 -0
- package/dist/src/formats/graphml/tree.d.ts.map +1 -0
- package/dist/src/formats/graphml/tree.js +290 -0
- package/dist/src/formats/graphml/tree.js.map +1 -0
- package/dist/src/formats/json/dialect.d.ts +125 -0
- package/dist/src/formats/json/dialect.d.ts.map +1 -0
- package/dist/src/formats/json/dialect.js +262 -0
- package/dist/src/formats/json/dialect.js.map +1 -0
- package/dist/src/formats/json/exporter.d.ts +89 -0
- package/dist/src/formats/json/exporter.d.ts.map +1 -0
- package/dist/src/formats/json/exporter.js +1358 -0
- package/dist/src/formats/json/exporter.js.map +1 -0
- package/dist/src/formats/json/importer.d.ts +108 -0
- package/dist/src/formats/json/importer.d.ts.map +1 -0
- package/dist/src/formats/json/importer.js +1838 -0
- package/dist/src/formats/json/importer.js.map +1 -0
- package/dist/src/formats/json/index.d.ts +8 -0
- package/dist/src/formats/json/index.d.ts.map +1 -0
- package/dist/src/formats/json/index.js +8 -0
- package/dist/src/formats/json/index.js.map +1 -0
- package/dist/src/formats/neo4j/exporter.d.ts +68 -0
- package/dist/src/formats/neo4j/exporter.d.ts.map +1 -0
- package/dist/src/formats/neo4j/exporter.js +1055 -0
- package/dist/src/formats/neo4j/exporter.js.map +1 -0
- package/dist/src/formats/neo4j/header.d.ts +52 -0
- package/dist/src/formats/neo4j/header.d.ts.map +1 -0
- package/dist/src/formats/neo4j/header.js +131 -0
- package/dist/src/formats/neo4j/header.js.map +1 -0
- package/dist/src/formats/neo4j/importer.d.ts +73 -0
- package/dist/src/formats/neo4j/importer.d.ts.map +1 -0
- package/dist/src/formats/neo4j/importer.js +932 -0
- package/dist/src/formats/neo4j/importer.js.map +1 -0
- package/dist/src/formats/neo4j/index.d.ts +79 -0
- package/dist/src/formats/neo4j/index.d.ts.map +1 -0
- package/dist/src/formats/neo4j/index.js +83 -0
- package/dist/src/formats/neo4j/index.js.map +1 -0
- package/dist/src/formats/pajek/exporter.d.ts +58 -0
- package/dist/src/formats/pajek/exporter.d.ts.map +1 -0
- package/dist/src/formats/pajek/exporter.js +825 -0
- package/dist/src/formats/pajek/exporter.js.map +1 -0
- package/dist/src/formats/pajek/importer.d.ts +88 -0
- package/dist/src/formats/pajek/importer.d.ts.map +1 -0
- package/dist/src/formats/pajek/importer.js +1047 -0
- package/dist/src/formats/pajek/importer.js.map +1 -0
- package/dist/src/formats/pajek/index.d.ts +7 -0
- package/dist/src/formats/pajek/index.d.ts.map +1 -0
- package/dist/src/formats/pajek/index.js +7 -0
- package/dist/src/formats/pajek/index.js.map +1 -0
- package/dist/src/formats/pajek/syntax.d.ts +112 -0
- package/dist/src/formats/pajek/syntax.d.ts.map +1 -0
- package/dist/src/formats/pajek/syntax.js +269 -0
- package/dist/src/formats/pajek/syntax.js.map +1 -0
- package/dist/src/index.d.ts +35 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +39 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/registry.d.ts +207 -0
- package/dist/src/registry.d.ts.map +1 -0
- package/dist/src/registry.js +481 -0
- package/dist/src/registry.js.map +1 -0
- package/dist/src/sniff.d.ts +104 -0
- package/dist/src/sniff.d.ts.map +1 -0
- package/dist/src/sniff.js +357 -0
- package/dist/src/sniff.js.map +1 -0
- package/dist/src/types.d.ts +238 -0
- package/dist/src/types.d.ts.map +1 -0
- package/dist/src/types.js +29 -0
- package/dist/src/types.js.map +1 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -0
- package/package.json +122 -7
- package/src/children.ts +335 -0
- package/src/common/attributes.ts +520 -0
- package/src/common/codes.ts +153 -0
- package/src/common/declared-types.ts +374 -0
- package/src/common/direction.ts +518 -0
- package/src/common/escape.ts +231 -0
- package/src/common/export.ts +817 -0
- package/src/common/format.ts +111 -0
- package/src/common/ids.ts +176 -0
- package/src/common/input.ts +378 -0
- package/src/common/lists.ts +196 -0
- package/src/common/options.ts +377 -0
- package/src/common/report.ts +352 -0
- package/src/common/temporal.ts +302 -0
- package/src/common/text.ts +294 -0
- package/src/common/weights.ts +202 -0
- package/src/common/writer.ts +123 -0
- package/src/common/xml.ts +1053 -0
- package/src/formats/csv/exporter.ts +894 -0
- package/src/formats/csv/header.ts +172 -0
- package/src/formats/csv/importer.ts +1104 -0
- package/src/formats/csv/index.ts +88 -0
- package/src/formats/csv/records.ts +813 -0
- package/src/formats/csv/values.ts +224 -0
- package/src/formats/dot/exporter.ts +1014 -0
- package/src/formats/dot/importer.ts +1549 -0
- package/src/formats/dot/index.ts +7 -0
- package/src/formats/dot/names.ts +40 -0
- package/src/formats/dot/tokenizer.ts +384 -0
- package/src/formats/gexf/exporter.ts +1696 -0
- package/src/formats/gexf/importer.ts +2333 -0
- package/src/formats/gexf/index.ts +142 -0
- package/src/formats/gexf/schema.ts +361 -0
- package/src/formats/gml/exporter.ts +1404 -0
- package/src/formats/gml/importer.ts +1591 -0
- package/src/formats/gml/index.ts +128 -0
- package/src/formats/gml/syntax.ts +545 -0
- package/src/formats/graphml/constants.ts +225 -0
- package/src/formats/graphml/exporter.ts +1458 -0
- package/src/formats/graphml/importer.ts +2027 -0
- package/src/formats/graphml/index.ts +8 -0
- package/src/formats/graphml/tree.ts +318 -0
- package/src/formats/json/dialect.ts +317 -0
- package/src/formats/json/exporter.ts +1616 -0
- package/src/formats/json/importer.ts +2271 -0
- package/src/formats/json/index.ts +8 -0
- package/src/formats/neo4j/exporter.ts +1287 -0
- package/src/formats/neo4j/header.ts +156 -0
- package/src/formats/neo4j/importer.ts +1220 -0
- package/src/formats/neo4j/index.ts +116 -0
- package/src/formats/pajek/exporter.ts +1000 -0
- package/src/formats/pajek/importer.ts +1311 -0
- package/src/formats/pajek/index.ts +7 -0
- package/src/formats/pajek/syntax.ts +307 -0
- package/src/index.ts +244 -0
- package/src/registry.ts +617 -0
- package/src/sniff.ts +397 -0
- package/src/types.ts +262 -0
|
@@ -0,0 +1,374 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The declared-type table of design section 5.1: what the type text of a GEXF `<attribute>`, a
|
|
3
|
+
* GraphML `<key>`, a GML value class or a Neo4j CSV header maps to, and how a value's text is
|
|
4
|
+
* parsed once the column dtype is known.
|
|
5
|
+
*
|
|
6
|
+
* Declared types map exactly: `double` and `long` -> f64, `float` -> f32, `int` / `integer` /
|
|
7
|
+
* `short` / `byte` -> i32, `boolean` -> bool, `string` / `anyURI` / `char` -> string, `bigdecimal`
|
|
8
|
+
* / `biginteger` -> string, `date` / `dateTime` and the Neo4j temporal types -> f64 (epoch or
|
|
9
|
+
* time-of-day milliseconds, design section 5.1), `list*` and `[]` -> list of the item type, GML
|
|
10
|
+
* `record` and Neo4j `point` -> json. A declared `long` is stored as f64 with a precision flag
|
|
11
|
+
* (values beyond 2^53 are a `precision` issue) unless the importer option `long: "string"` keeps the
|
|
12
|
+
* whole column as text. Neo4j `duration` has no epoch and is kept as text. The declared type text is
|
|
13
|
+
* recorded in `origin.type` in every case so the exporter can restore the declaration.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { type Dtype, GraphFormatError, type ScalarDtype } from "@graphty/graph-format";
|
|
17
|
+
|
|
18
|
+
import { parseTemporal, type TemporalKind } from "./temporal.js";
|
|
19
|
+
|
|
20
|
+
/** The formats whose declarations this table covers. */
|
|
21
|
+
export type DeclaringFormat = "gexf" | "graphml" | "gml" | "neo4j";
|
|
22
|
+
|
|
23
|
+
/** How the text of one scalar value (or one list item) is parsed. */
|
|
24
|
+
type ValueKind =
|
|
25
|
+
"boolean" | "integer" | "long" | "float" | "double" | "string" | "temporal" | "duration" | "point" | "json";
|
|
26
|
+
|
|
27
|
+
/** The resolved storage of a declared type. */
|
|
28
|
+
export interface DeclaredTypeSpec {
|
|
29
|
+
/** The declared type text as given by the file (origin.type). */
|
|
30
|
+
readonly declared: string;
|
|
31
|
+
/** The column dtype. */
|
|
32
|
+
readonly dtype: Dtype;
|
|
33
|
+
/** The item dtype of a list column, null otherwise. */
|
|
34
|
+
readonly itemDtype: ScalarDtype | null;
|
|
35
|
+
/** How each scalar value or list item text is parsed. */
|
|
36
|
+
readonly kind: ValueKind;
|
|
37
|
+
/** Whether the column is a list. */
|
|
38
|
+
readonly list: boolean;
|
|
39
|
+
/** The temporal kind of a temporal value, null otherwise. */
|
|
40
|
+
readonly temporal: TemporalKind | null;
|
|
41
|
+
/** Whether values may exceed 2^53 (a long stored as f64), so the importer checks Number.isSafeInteger. */
|
|
42
|
+
readonly precision: boolean;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** A scalar entry of the table before the list flag and the long mode are applied. */
|
|
46
|
+
interface ScalarEntry {
|
|
47
|
+
readonly dtype: ScalarDtype;
|
|
48
|
+
readonly kind: ValueKind;
|
|
49
|
+
readonly temporal?: TemporalKind;
|
|
50
|
+
readonly precision?: boolean;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const BOOLEAN: ScalarEntry = { dtype: "bool", kind: "boolean" };
|
|
54
|
+
const INTEGER: ScalarEntry = { dtype: "i32", kind: "integer" };
|
|
55
|
+
const LONG: ScalarEntry = { dtype: "f64", kind: "long", precision: true };
|
|
56
|
+
const FLOAT: ScalarEntry = { dtype: "f32", kind: "float" };
|
|
57
|
+
const DOUBLE: ScalarEntry = { dtype: "f64", kind: "double" };
|
|
58
|
+
const STRING: ScalarEntry = { dtype: "string", kind: "string" };
|
|
59
|
+
const DATE: ScalarEntry = { dtype: "f64", kind: "temporal", temporal: "date" };
|
|
60
|
+
const DATE_TIME: ScalarEntry = { dtype: "f64", kind: "temporal", temporal: "dateTime" };
|
|
61
|
+
const LOCAL_DATE_TIME: ScalarEntry = { dtype: "f64", kind: "temporal", temporal: "localDateTime" };
|
|
62
|
+
const TIME: ScalarEntry = { dtype: "f64", kind: "temporal", temporal: "time" };
|
|
63
|
+
const LOCAL_TIME: ScalarEntry = { dtype: "f64", kind: "temporal", temporal: "localTime" };
|
|
64
|
+
const DURATION: ScalarEntry = { dtype: "string", kind: "duration" };
|
|
65
|
+
const POINT: ScalarEntry = { dtype: "json", kind: "point" };
|
|
66
|
+
const RECORD: ScalarEntry = { dtype: "json", kind: "json" };
|
|
67
|
+
|
|
68
|
+
/** GEXF 1.2 / 1.3 scalar types (the `list*` variants are derived). */
|
|
69
|
+
const GEXF_SCALARS: Readonly<Record<string, ScalarEntry>> = {
|
|
70
|
+
integer: INTEGER,
|
|
71
|
+
long: LONG,
|
|
72
|
+
double: DOUBLE,
|
|
73
|
+
float: FLOAT,
|
|
74
|
+
boolean: BOOLEAN,
|
|
75
|
+
string: STRING,
|
|
76
|
+
anyuri: STRING,
|
|
77
|
+
char: STRING,
|
|
78
|
+
byte: INTEGER,
|
|
79
|
+
short: INTEGER,
|
|
80
|
+
bigdecimal: STRING,
|
|
81
|
+
biginteger: STRING,
|
|
82
|
+
date: DATE,
|
|
83
|
+
datetime: DATE_TIME,
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
/** GraphML `attr.type` values. */
|
|
87
|
+
const GRAPHML_SCALARS: Readonly<Record<string, ScalarEntry>> = {
|
|
88
|
+
boolean: BOOLEAN,
|
|
89
|
+
int: INTEGER,
|
|
90
|
+
long: LONG,
|
|
91
|
+
float: FLOAT,
|
|
92
|
+
double: DOUBLE,
|
|
93
|
+
string: STRING,
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
/** GML value classes (per value in the file; the GML importer names them per column). */
|
|
97
|
+
const GML_SCALARS: Readonly<Record<string, ScalarEntry>> = {
|
|
98
|
+
int: INTEGER,
|
|
99
|
+
real: DOUBLE,
|
|
100
|
+
string: STRING,
|
|
101
|
+
record: RECORD,
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
/** Neo4j CSV header types and Cypher property type names. */
|
|
105
|
+
const NEO4J_SCALARS: Readonly<Record<string, ScalarEntry>> = {
|
|
106
|
+
int: INTEGER,
|
|
107
|
+
integer: LONG,
|
|
108
|
+
long: LONG,
|
|
109
|
+
float: FLOAT,
|
|
110
|
+
double: DOUBLE,
|
|
111
|
+
boolean: BOOLEAN,
|
|
112
|
+
byte: INTEGER,
|
|
113
|
+
short: INTEGER,
|
|
114
|
+
char: STRING,
|
|
115
|
+
string: STRING,
|
|
116
|
+
point: POINT,
|
|
117
|
+
date: DATE,
|
|
118
|
+
localtime: LOCAL_TIME,
|
|
119
|
+
time: TIME,
|
|
120
|
+
localdatetime: LOCAL_DATE_TIME,
|
|
121
|
+
datetime: DATE_TIME,
|
|
122
|
+
duration: DURATION,
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
const TABLES: Readonly<Record<DeclaringFormat, Readonly<Record<string, ScalarEntry>>>> = {
|
|
126
|
+
gexf: GEXF_SCALARS,
|
|
127
|
+
graphml: GRAPHML_SCALARS,
|
|
128
|
+
gml: GML_SCALARS,
|
|
129
|
+
neo4j: NEO4J_SCALARS,
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
const INTEGER_TEXT = /^[+-]?[0-9]+$/;
|
|
133
|
+
const DECIMAL_TEXT = /^[+-]?([0-9]+(\.[0-9]*)?|\.[0-9]+)([eE][+-]?[0-9]+)?$/;
|
|
134
|
+
const I32_MIN = -2147483648;
|
|
135
|
+
const I32_MAX = 2147483647;
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Resolve a declared type text of one format to its storage.
|
|
139
|
+
* @param format - the declaring format
|
|
140
|
+
* @param type - the type text as written (matched case-insensitively; GEXF `list*` and Neo4j `[]` denote lists)
|
|
141
|
+
* @param long - how declared long / integer-64 columns are stored (the importer option)
|
|
142
|
+
* @returns the spec, or null when the format does not define the type (the importer reports it and keeps the text)
|
|
143
|
+
*/
|
|
144
|
+
export function mapDeclaredType(
|
|
145
|
+
format: DeclaringFormat,
|
|
146
|
+
type: string,
|
|
147
|
+
long: "f64" | "string",
|
|
148
|
+
): DeclaredTypeSpec | null {
|
|
149
|
+
const table = TABLES[format];
|
|
150
|
+
let key = type.trim().toLowerCase();
|
|
151
|
+
let list = false;
|
|
152
|
+
if (format === "gexf" && key.startsWith("list") && key.length > 4) {
|
|
153
|
+
list = true;
|
|
154
|
+
key = key.slice(4);
|
|
155
|
+
} else if (format === "neo4j" && key.endsWith("[]")) {
|
|
156
|
+
list = true;
|
|
157
|
+
key = key.slice(0, -2);
|
|
158
|
+
} else if (format === "gml" && key === "list") {
|
|
159
|
+
return {
|
|
160
|
+
declared: type,
|
|
161
|
+
dtype: "list",
|
|
162
|
+
itemDtype: "json",
|
|
163
|
+
kind: "json",
|
|
164
|
+
list: true,
|
|
165
|
+
temporal: null,
|
|
166
|
+
precision: false,
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
let entry = table[key];
|
|
170
|
+
if (entry === undefined) {
|
|
171
|
+
return null;
|
|
172
|
+
}
|
|
173
|
+
if (entry.kind === "long" && long === "string") {
|
|
174
|
+
entry = STRING;
|
|
175
|
+
}
|
|
176
|
+
return {
|
|
177
|
+
declared: type,
|
|
178
|
+
dtype: list ? "list" : entry.dtype,
|
|
179
|
+
itemDtype: list ? entry.dtype : null,
|
|
180
|
+
kind: entry.kind,
|
|
181
|
+
list,
|
|
182
|
+
temporal: entry.temporal ?? null,
|
|
183
|
+
precision: entry.precision ?? false,
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* The spec of an untyped attribute: a string column with the given (or absent) type text.
|
|
189
|
+
* @param declared - the type text to record in origin.type, or null
|
|
190
|
+
* @returns a string spec
|
|
191
|
+
*/
|
|
192
|
+
export function stringSpec(declared: string | null): DeclaredTypeSpec {
|
|
193
|
+
return {
|
|
194
|
+
declared: declared ?? "",
|
|
195
|
+
dtype: "string",
|
|
196
|
+
itemDtype: null,
|
|
197
|
+
kind: "string",
|
|
198
|
+
list: false,
|
|
199
|
+
temporal: null,
|
|
200
|
+
precision: false,
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Parse the text of one scalar value (or list item) by its kind. Numeric and boolean kinds trim
|
|
206
|
+
* surrounding whitespace (pretty-printed XML puts newlines around `<data>` text); string kinds keep
|
|
207
|
+
* the text exactly.
|
|
208
|
+
* @param text - the value text
|
|
209
|
+
* @param kind - the value kind
|
|
210
|
+
* @param temporal - the temporal kind when `kind` is "temporal"
|
|
211
|
+
* @returns a boolean, a number, a string or (point / json) a JSON value; E_COLUMN_TYPE when the text is not of the kind
|
|
212
|
+
*/
|
|
213
|
+
export function parseScalarText(text: string, kind: ValueKind, temporal: TemporalKind | null = null): unknown {
|
|
214
|
+
switch (kind) {
|
|
215
|
+
case "boolean": {
|
|
216
|
+
const value = parseBooleanText(text);
|
|
217
|
+
if (value === null) {
|
|
218
|
+
throw typeError(text, kind);
|
|
219
|
+
}
|
|
220
|
+
return value;
|
|
221
|
+
}
|
|
222
|
+
case "integer": {
|
|
223
|
+
const trimmed = text.trim();
|
|
224
|
+
if (!INTEGER_TEXT.test(trimmed)) {
|
|
225
|
+
throw typeError(text, kind);
|
|
226
|
+
}
|
|
227
|
+
const value = Number(trimmed);
|
|
228
|
+
if (value < I32_MIN || value > I32_MAX) {
|
|
229
|
+
throw new GraphFormatError("E_COLUMN_TYPE", `"${trimmed}" is outside the 32-bit integer range`, {
|
|
230
|
+
value: trimmed,
|
|
231
|
+
kind,
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
return value;
|
|
235
|
+
}
|
|
236
|
+
case "long": {
|
|
237
|
+
const trimmed = text.trim();
|
|
238
|
+
if (!INTEGER_TEXT.test(trimmed)) {
|
|
239
|
+
throw typeError(text, kind);
|
|
240
|
+
}
|
|
241
|
+
return Number(trimmed);
|
|
242
|
+
}
|
|
243
|
+
case "float":
|
|
244
|
+
case "double":
|
|
245
|
+
return parseDecimalText(text, kind);
|
|
246
|
+
case "string":
|
|
247
|
+
case "duration":
|
|
248
|
+
return text;
|
|
249
|
+
case "temporal": {
|
|
250
|
+
if (temporal === null) {
|
|
251
|
+
throw new GraphFormatError("E_COLUMN_TYPE", "a temporal value needs its temporal kind", { kind });
|
|
252
|
+
}
|
|
253
|
+
return parseTemporal(text.trim(), temporal).value;
|
|
254
|
+
}
|
|
255
|
+
case "point":
|
|
256
|
+
return parsePointText(text);
|
|
257
|
+
case "json":
|
|
258
|
+
return parseJsonText(text);
|
|
259
|
+
default: {
|
|
260
|
+
const name: string = kind;
|
|
261
|
+
throw new GraphFormatError("E_COLUMN_TYPE", `unknown value kind ${name}`, { kind: name });
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Parse a boolean text the way the formats write it: `true` / `false` in any case, or `1` / `0`.
|
|
268
|
+
* @param text - the value text
|
|
269
|
+
* @returns the boolean, or null when the text is neither
|
|
270
|
+
*/
|
|
271
|
+
export function parseBooleanText(text: string): boolean | null {
|
|
272
|
+
switch (text.trim().toLowerCase()) {
|
|
273
|
+
case "true":
|
|
274
|
+
case "1":
|
|
275
|
+
return true;
|
|
276
|
+
case "false":
|
|
277
|
+
case "0":
|
|
278
|
+
return false;
|
|
279
|
+
default:
|
|
280
|
+
return null;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Parse a float / double text: a decimal or exponent literal, or the XSD / JSON spellings of the
|
|
286
|
+
* non-finite values (`INF`, `-INF`, `Infinity`, `-Infinity`, `NaN`).
|
|
287
|
+
* @param text - the value text
|
|
288
|
+
* @param kind - float or double, for the error
|
|
289
|
+
* @returns the number
|
|
290
|
+
*/
|
|
291
|
+
export function parseDecimalText(text: string, kind: ValueKind = "double"): number {
|
|
292
|
+
const trimmed = text.trim();
|
|
293
|
+
if (DECIMAL_TEXT.test(trimmed)) {
|
|
294
|
+
return Number(trimmed);
|
|
295
|
+
}
|
|
296
|
+
switch (trimmed) {
|
|
297
|
+
case "INF":
|
|
298
|
+
case "+INF":
|
|
299
|
+
case "Infinity":
|
|
300
|
+
case "+Infinity":
|
|
301
|
+
return Infinity;
|
|
302
|
+
case "-INF":
|
|
303
|
+
case "-Infinity":
|
|
304
|
+
return -Infinity;
|
|
305
|
+
case "NaN":
|
|
306
|
+
return NaN;
|
|
307
|
+
default:
|
|
308
|
+
throw typeError(text, kind);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* Parse a Neo4j point literal `{x:1.0, y:2.0, crs:'cartesian'}` (also `latitude` / `longitude` /
|
|
314
|
+
* `height` / `z` / `srid`) into a JSON object; a JSON object text is accepted as well.
|
|
315
|
+
* @param text - the value text
|
|
316
|
+
* @returns an object with numeric coordinates and string crs
|
|
317
|
+
*/
|
|
318
|
+
export function parsePointText(text: string): Readonly<Record<string, number | string>> {
|
|
319
|
+
const trimmed = text.trim();
|
|
320
|
+
if (!trimmed.startsWith("{") || !trimmed.endsWith("}")) {
|
|
321
|
+
throw typeError(text, "point");
|
|
322
|
+
}
|
|
323
|
+
const out: Record<string, number | string> = {};
|
|
324
|
+
const inner = trimmed.slice(1, -1).trim();
|
|
325
|
+
if (inner.length === 0) {
|
|
326
|
+
return out;
|
|
327
|
+
}
|
|
328
|
+
for (const part of inner.split(",")) {
|
|
329
|
+
const colon = part.indexOf(":");
|
|
330
|
+
if (colon < 0) {
|
|
331
|
+
throw typeError(text, "point");
|
|
332
|
+
}
|
|
333
|
+
const key = part
|
|
334
|
+
.slice(0, colon)
|
|
335
|
+
.trim()
|
|
336
|
+
.replace(/^["']|["']$/g, "");
|
|
337
|
+
const raw = part.slice(colon + 1).trim();
|
|
338
|
+
if (key.length === 0) {
|
|
339
|
+
throw typeError(text, "point");
|
|
340
|
+
}
|
|
341
|
+
if (DECIMAL_TEXT.test(raw)) {
|
|
342
|
+
out[key] = Number(raw);
|
|
343
|
+
} else if ((raw.startsWith("'") && raw.endsWith("'")) || (raw.startsWith('"') && raw.endsWith('"'))) {
|
|
344
|
+
out[key] = raw.slice(1, -1);
|
|
345
|
+
} else {
|
|
346
|
+
throw typeError(text, "point");
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
return out;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
/**
|
|
353
|
+
* Parse JSON text into a value.
|
|
354
|
+
* @param text - the JSON text
|
|
355
|
+
* @returns the parsed value
|
|
356
|
+
*/
|
|
357
|
+
function parseJsonText(text: string): unknown {
|
|
358
|
+
try {
|
|
359
|
+
return JSON.parse(text) as unknown;
|
|
360
|
+
} catch {
|
|
361
|
+
throw typeError(text, "json");
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
/**
|
|
366
|
+
* The E_COLUMN_TYPE error of a text that is not of a kind.
|
|
367
|
+
* @param text - the text
|
|
368
|
+
* @param kind - the kind
|
|
369
|
+
* @returns the error
|
|
370
|
+
*/
|
|
371
|
+
function typeError(text: string, kind: ValueKind): GraphFormatError {
|
|
372
|
+
const shown = text.length > 40 ? `${text.slice(0, 40)}...` : text;
|
|
373
|
+
return new GraphFormatError("E_COLUMN_TYPE", `"${shown}" is not a ${kind}`, { value: text, kind });
|
|
374
|
+
}
|