@graphty/graph-io 0.3.15 → 0.3.17
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/dist/chunks/{escape-D1f9-cwf.js → escape-scjHxjpr.js} +2 -2
- package/dist/chunks/{escape-D1f9-cwf.js.map → escape-scjHxjpr.js.map} +1 -1
- package/dist/chunks/{importer-C7mnGdr_.js → importer-B6rKRxzv.js} +3 -3
- package/dist/chunks/importer-B6rKRxzv.js.map +1 -0
- package/dist/chunks/{importer-B8lsjFWx.js → importer-BmOl9gLW.js} +3 -3
- package/dist/chunks/{importer-B8lsjFWx.js.map → importer-BmOl9gLW.js.map} +1 -1
- package/dist/chunks/{importer-D7ZcGCeb.js → importer-Xg07gk7p.js} +3 -3
- package/dist/chunks/{importer-D7ZcGCeb.js.map → importer-Xg07gk7p.js.map} +1 -1
- package/dist/chunks/{importer-CXEiicAN.js → importer-ruMWWvVs.js} +3 -3
- package/dist/chunks/{importer-CXEiicAN.js.map → importer-ruMWWvVs.js.map} +1 -1
- package/dist/chunks/{records-IHsCfv7s.js → records-DSpbTE5s.js} +2 -2
- package/dist/chunks/{records-IHsCfv7s.js.map → records-DSpbTE5s.js.map} +1 -1
- package/dist/chunks/{writer-BtWpUaiH.js → writer-DHHfHn11.js} +206 -115
- package/dist/chunks/writer-DHHfHn11.js.map +1 -0
- package/dist/csv.js +3 -3
- package/dist/dot.js +1 -1
- package/dist/gexf.js +2 -2
- package/dist/gml.js +2 -2
- package/dist/graph-io.js +141 -103
- package/dist/graph-io.js.map +1 -1
- package/dist/graphml.js +1 -1
- package/dist/json.js +1 -1
- package/dist/neo4j.js +3 -3
- package/dist/pajek.js +1 -1
- package/dist/src/common/codes.d.ts +43 -0
- package/dist/src/common/codes.d.ts.map +1 -1
- package/dist/src/common/codes.js +43 -0
- package/dist/src/common/codes.js.map +1 -1
- package/dist/src/common/input.d.ts +9 -0
- package/dist/src/common/input.d.ts.map +1 -1
- package/dist/src/common/input.js +16 -0
- package/dist/src/common/input.js.map +1 -1
- package/dist/src/common/options.d.ts +12 -1
- package/dist/src/common/options.d.ts.map +1 -1
- package/dist/src/common/options.js +51 -1
- package/dist/src/common/options.js.map +1 -1
- package/dist/src/formats/json/importer.d.ts.map +1 -1
- package/dist/src/formats/json/importer.js +2 -2
- package/dist/src/formats/json/importer.js.map +1 -1
- package/dist/src/index.d.ts +4 -4
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +3 -3
- package/dist/src/index.js.map +1 -1
- package/dist/src/registry.d.ts +21 -3
- package/dist/src/registry.d.ts.map +1 -1
- package/dist/src/registry.js +29 -0
- package/dist/src/registry.js.map +1 -1
- package/dist/src/types.d.ts +31 -0
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/types.js.map +1 -1
- package/package.json +2 -2
- package/src/common/codes.ts +58 -0
- package/src/common/input.ts +16 -0
- package/src/common/options.ts +78 -2
- package/src/formats/json/importer.ts +2 -1
- package/src/index.ts +5 -0
- package/src/registry.ts +35 -2
- package/src/types.ts +40 -1
- package/dist/chunks/importer-C7mnGdr_.js.map +0 -1
- package/dist/chunks/writer-BtWpUaiH.js.map +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { GraphFormatError } from "@graphty/graph-format";
|
|
2
|
-
import { t as textChunks } from "./writer-
|
|
2
|
+
import { t as textChunks } from "./writer-DHHfHn11.js";
|
|
3
3
|
const UNCLOSED_QUOTE_CODE = "E_CSV_UNCLOSED_QUOTE";
|
|
4
4
|
const BAD_QUOTE_CODE = "E_CSV_QUOTE";
|
|
5
5
|
const DELIMITER_CANDIDATES = Object.freeze([",", " ", ";", "|", " "]);
|
|
@@ -615,4 +615,4 @@ export {
|
|
|
615
615
|
checkRecordSyntax as c,
|
|
616
616
|
sniffNewline as s
|
|
617
617
|
};
|
|
618
|
-
//# sourceMappingURL=records-
|
|
618
|
+
//# sourceMappingURL=records-DSpbTE5s.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"records-IHsCfv7s.js","sources":["../../src/formats/csv/records.ts"],"sourcesContent":["/**\n * The one streaming CSV record reader of the package (design sections 8.2 and 8.4: hand-written\n * tokenisers per format; CSV and Neo4j CSV are line-oriented over a byte stream): RFC 4180 records\n * with a configurable single-character delimiter and quote, a doubled quote inside a quoted field,\n * quoted fields spanning lines, LF / CRLF / lone-CR terminators, read from the common text reader\n * one chunk at a time as a character state machine. Only the open field is ever held, so a field\n * spanning many chunks costs its length once and a multi-gigabyte file is never buffered.\n *\n * `RecordReader` (used by the Neo4j importer) keeps one reusable cell array and one reusable\n * \"was quoted\" array: a quoted empty field (`\"\"`) is an empty string while an unquoted empty field\n * means \"not set\", and only the tokeniser can tell the two apart. `CsvRecordReader` (the CSV\n * importer) wraps it with delimiter sniffing over a bounded preview and yields a fresh cell array\n * per row. A malformed quoted field is fatal for both: an unterminated quote swallows the rest of\n * the file, and text after a closing quote makes every later cell boundary unreliable.\n */\n\nimport { GraphFormatError } from \"@graphty/graph-format\";\n\nimport { type ReadOptions, textChunks } from \"../../common/input.js\";\nimport { type ImportReportBuilder } from \"../../common/report.js\";\nimport { type ImportInput } from \"../../types.js\";\n\n/** Issue code: a quoted field is never closed; the import aborts (everything after it would be one cell). */\nexport const UNCLOSED_QUOTE_CODE = \"E_CSV_UNCLOSED_QUOTE\";\n\n/** Issue code: a closing quote is followed by text other than a delimiter or a line break; the import aborts. */\nexport const BAD_QUOTE_CODE = \"E_CSV_QUOTE\";\n\n/** The delimiters tried, in priority order, when none is given. */\nexport const DELIMITER_CANDIDATES: readonly string[] = Object.freeze([\",\", \"\\t\", \";\", \"|\", \" \"]);\n\n/** Rows the delimiter sniff looks at. */\nconst PREVIEW_ROWS = 10;\n\n/** Characters buffered for the sniff when the input has fewer than PREVIEW_ROWS line breaks. */\nconst PREVIEW_CHARS = 64 * 1024;\n\nconst LF = 10;\nconst CR = 13;\n\n/** Tokeniser state: at the start of a field. */\nconst START = 0;\n/** Tokeniser state: inside an unquoted field. */\nconst UNQUOTED = 1;\n/** Tokeniser state: inside a quoted field. */\nconst QUOTED = 2;\n/** Tokeniser state: just after a quote inside a quoted field (a second quote is a literal, anything else ends the field). */\nconst CLOSING = 3;\n/** Tokeniser state: after a closed quoted field, before the delimiter (text here is malformed). */\nconst AFTER_QUOTED = 4;\n/** Inside a leading comment line (skipped up to its line break). */\nconst COMMENT = 5;\n\ntype State = typeof START | typeof UNQUOTED | typeof QUOTED | typeof CLOSING | typeof AFTER_QUOTED | typeof COMMENT;\n\n/** The delimiter and quote of a reader. */\nexport interface RecordSyntax {\n /** The field delimiter, one character; null sniffs it from the first rows. */\n readonly delimiter: string | null;\n /** The quote character, one character. */\n readonly quote: string;\n /** The delimiters tried when `delimiter` is null; DELIMITER_CANDIDATES by default. */\n readonly candidates?: readonly string[] | undefined;\n /**\n * Characters that open a comment line while no record has been read yet (SNAP `#`, KONECT\n * `%`): such leading lines are skipped, kept in `leadingComments` and left out of the delimiter\n * sniff. A later line starting with one of them is an ordinary record. Default: none.\n */\n readonly comments?: readonly string[] | undefined;\n /**\n * Whether the delimiter sniff skips a candidate under which a closing quote is followed by\n * other text (see sniffDelimiter). False by default: that text then aborts the read.\n */\n readonly skipQuoteErrors?: boolean | undefined;\n}\n\n/**\n * Check a delimiter or quote option: exactly one character that is not a line break, and the two\n * must differ.\n * @param syntax - the delimiter (or null for sniffing) and quote\n * @returns the syntax unchanged; E_UNSUPPORTED when invalid\n */\nexport function checkRecordSyntax(syntax: RecordSyntax): RecordSyntax {\n for (const [option, value] of [\n [\"delimiter\", syntax.delimiter],\n [\"quote\", syntax.quote],\n ] as const) {\n if (value === null) {\n continue;\n }\n if (value.length !== 1 || value === \"\\n\" || value === \"\\r\") {\n throw new GraphFormatError(\n \"E_UNSUPPORTED\",\n `option ${option}: ${JSON.stringify(value)} is not a single non-line-break character`,\n { option, found: value },\n );\n }\n }\n if (syntax.delimiter !== null && syntax.delimiter === syntax.quote) {\n throw new GraphFormatError(\"E_UNSUPPORTED\", \"options delimiter and quote must differ\", {\n option: \"delimiter\",\n found: syntax.delimiter,\n });\n }\n return syntax;\n}\n\n/**\n * Sniff the line terminator of a text: a lone `\\r` only when the text has `\\r` and no `\\n` at all\n * (classic Mac files); `\\n` otherwise.\n * @param text - the preview text\n * @returns \"\\n\" or \"\\r\"\n */\nexport function sniffNewline(text: string): \"\\n\" | \"\\r\" {\n return !text.includes(\"\\n\") && text.includes(\"\\r\") ? \"\\r\" : \"\\n\";\n}\n\n/**\n * Split a text into records synchronously (the first `maxRows` of them), honouring quotes; for\n * the delimiter sniff and the registry's head sniff, where the input is a bounded preview.\n * @param text - the text\n * @param delimiter - the delimiter\n * @param quote - the quote character\n * @param maxRows - the most rows to return\n * @param strictQuotes - return null when a closing quote is followed by text other than the\n * delimiter or a line break (the import would abort under this delimiter)\n * @returns the rows as cell arrays (blank lines skipped), or null (see strictQuotes)\n */\nfunction splitRecords(\n text: string,\n delimiter: string,\n quote: string,\n maxRows: number,\n strictQuotes = false,\n): string[][] | null {\n const rows: string[][] = [];\n const delimiterCode = delimiter.charCodeAt(0);\n const quoteCode = quote.charCodeAt(0);\n let cells: string[] = [];\n let state: State = START;\n let segment = 0;\n let field = \"\";\n const n = text.length;\n for (let i = 0; i < n && rows.length < maxRows; i++) {\n const c = text.charCodeAt(i);\n if (state === QUOTED) {\n if (c === quoteCode) {\n field += text.slice(segment, i);\n state = CLOSING;\n }\n continue;\n }\n if (state === CLOSING) {\n if (c === quoteCode) {\n field += quote;\n segment = i + 1;\n state = QUOTED;\n continue;\n }\n if (strictQuotes && c !== delimiterCode && c !== LF && c !== CR) {\n return null;\n }\n state = AFTER_QUOTED;\n segment = i;\n }\n if (c === delimiterCode || c === LF || c === CR) {\n if (state === UNQUOTED || state === AFTER_QUOTED) {\n field += text.slice(segment, i);\n }\n if (c === delimiterCode) {\n cells.push(field);\n field = \"\";\n state = START;\n } else {\n if (state !== START || cells.length > 0) {\n cells.push(field);\n rows.push(cells);\n cells = [];\n field = \"\";\n }\n state = START;\n if (c === CR && text.charCodeAt(i + 1) === LF) {\n i++;\n }\n }\n segment = i + 1;\n continue;\n }\n if (state === START) {\n if (c === quoteCode) {\n state = QUOTED;\n segment = i + 1;\n } else {\n state = UNQUOTED;\n segment = i;\n }\n }\n }\n if (rows.length < maxRows && (state !== START || cells.length > 0)) {\n if (state === UNQUOTED || state === AFTER_QUOTED || state === QUOTED) {\n field += text.slice(segment, n);\n }\n cells.push(field);\n rows.push(cells);\n }\n return rows;\n}\n\n/**\n * The preview text without its leading comment lines (those starting with one of the comment\n * characters), so the sniff sees the records only.\n * @param text - the preview text\n * @param comments - the comment characters\n * @returns the text from the first non-comment line on\n */\nfunction stripLeadingComments(text: string, comments: readonly string[]): string {\n if (comments.length === 0) {\n return text;\n }\n let at = 0;\n while (at < text.length && comments.includes(text[at])) {\n const lf = text.indexOf(\"\\n\", at);\n const cr = text.indexOf(\"\\r\", at);\n const end = Math.min(lf < 0 ? Infinity : lf, cr < 0 ? Infinity : cr);\n if (end === Infinity) {\n return \"\";\n }\n at = end + 1;\n if (text[at - 1] === \"\\r\" && text[at] === \"\\n\") {\n at++;\n }\n }\n return at === 0 ? text : text.slice(at);\n}\n\n/**\n * Sniff the delimiter of a text: every candidate is tried over the first rows and the one whose\n * field count is most consistent across rows wins (ties broken by the higher field count); a\n * candidate that yields fewer than two fields per row on average is never chosen. `null` when no\n * candidate qualifies (a single-column file).\n * @param text - the preview text\n * @param newline - the sniffed line terminator (unused by the splitter, which reads every kind;\n * kept for callers that sniffed it)\n * @param candidates - the delimiters to try, in priority order\n * @param quote - the quote character\n * @param skipQuoteErrors - also never choose a candidate under which a closing quote is followed\n * by other text. Only for inputs whose field counts say nothing (an adjacency table's rows vary in\n * width): elsewhere a stray character after a quote would make a worse candidate win silently\n * instead of aborting the read\n * @returns the delimiter, or null\n */\nexport function sniffDelimiter(\n text: string,\n newline: \"\\n\" | \"\\r\" = \"\\n\",\n candidates: readonly string[] = DELIMITER_CANDIDATES,\n quote = '\"',\n skipQuoteErrors = false,\n): string | null {\n let best: string | null = null;\n let bestDelta = Infinity;\n let bestAverage = 0;\n const terminated = text.endsWith(\"\\n\") || text.endsWith(\"\\r\");\n for (const delimiter of candidates) {\n if (delimiter === quote || delimiter === newline) {\n continue;\n }\n const split = splitRecords(text, delimiter, quote, PREVIEW_ROWS, skipQuoteErrors);\n if (split === null) {\n // a quoted cell this delimiter does not close: it is not the file's delimiter\n continue;\n }\n let rows = split.filter((row) => !isBlankRow(row));\n if (rows.length > 1 && !terminated) {\n // the preview is a prefix of the file: its last row may be cut short\n rows = rows.slice(0, -1);\n }\n if (rows.length === 0) {\n continue;\n }\n let total = 0;\n let delta = 0;\n for (let i = 0; i < rows.length; i++) {\n const count = rows[i].length;\n total += count;\n if (i > 0) {\n delta += Math.abs(count - rows[i - 1].length);\n }\n }\n const average = total / rows.length;\n if (average > 1.99 && (delta < bestDelta || (delta === bestDelta && average > bestAverage))) {\n best = delimiter;\n bestDelta = delta;\n bestAverage = average;\n }\n }\n return best;\n}\n\n/**\n * Whether a parsed row is a blank line: one cell holding only whitespace.\n * @param row - the row\n * @returns true for a blank line\n */\nfunction isBlankRow(row: readonly string[]): boolean {\n return row.length === 1 && row[0].trim().length === 0;\n}\n\n/**\n * Reads the records of one input. Iterate with `for await (const count of reader)`: each\n * iteration fills `reader.cells[0..count)` and `reader.quoted[0..count)` and sets `reader.line`\n * to the 1-based line the record started on. Blank lines (an empty unquoted record of one field)\n * are skipped. The arrays are reused between records. When the syntax gives no delimiter, the\n * first rows (PREVIEW_ROWS, or PREVIEW_CHARS characters) are buffered and the delimiter sniffed\n * from them before the first record is yielded.\n */\nexport class RecordReader implements AsyncIterable<number> {\n /** The cells of the record most recently yielded; only the first `count` entries are valid. */\n readonly cells: string[] = [];\n\n /** Whether each cell of the record most recently yielded was quoted. */\n readonly quoted: boolean[] = [];\n\n /** The leading comment lines (without their line breaks), in order; empty without `syntax.comments`. */\n readonly leadingComments: string[] = [];\n\n private readonly input: ImportInput;\n\n private readonly report: ImportReportBuilder;\n\n private readonly readOptions: ReadOptions;\n\n /** The delimiter (null while unsniffed), quote and comment characters. */\n readonly syntax: RecordSyntax;\n\n private delimiterText: string | null;\n\n private recordLine = 0;\n\n /**\n * Create a reader; nothing is read until iteration starts.\n * @param input - the input (or an async iterable of already decoded text chunks)\n * @param report - the report decode and quoting errors are recorded in\n * @param syntax - the delimiter (null to sniff) and quote (already checked)\n * @param readOptions - cancellation and progress\n */\n constructor(input: ImportInput, report: ImportReportBuilder, syntax: RecordSyntax, readOptions: ReadOptions) {\n this.input = input;\n this.report = report;\n this.readOptions = readOptions;\n this.syntax = syntax;\n this.delimiterText = syntax.delimiter;\n }\n\n /**\n * The 1-based line the most recently yielded record started on.\n * @returns the line number; 0 before the first record\n */\n get line(): number {\n return this.recordLine;\n }\n\n /**\n * The delimiter in use.\n * @returns the given or sniffed delimiter; null before the sniff ran\n */\n get delimiter(): string | null {\n return this.delimiterText;\n }\n\n /**\n * Iterate the records.\n * @yields the number of cells of each record\n * @returns nothing\n */\n async *[Symbol.asyncIterator](): AsyncGenerator<number, void, undefined> {\n const scanner = new RecordScanner(this);\n for await (const chunk of this.chunks()) {\n // the first chunk arrives after the sniff (or with the given delimiter)\n scanner.setDelimiter((this.delimiterText ?? \",\").charCodeAt(0));\n let i = 0;\n while (i < chunk.length) {\n i = scanner.scan(chunk, i);\n if (scanner.ready) {\n scanner.ready = false;\n this.recordLine = scanner.recordLine;\n yield scanner.count;\n scanner.count = 0;\n }\n }\n scanner.endChunk(chunk);\n }\n if (scanner.finish()) {\n this.recordLine = scanner.recordLine;\n yield scanner.count;\n }\n }\n\n /**\n * Record a text-after-quote error (fatal).\n * @param line - the line the field started on\n * @returns never\n */\n badQuote(line: number): never {\n return this.report.fail(BAD_QUOTE_CODE, `line ${line}: text after the closing quote of a quoted field`, {\n line,\n });\n }\n\n /**\n * Record an unclosed-quote error (fatal).\n * @param line - the line the field started on\n * @returns never\n */\n unclosedQuote(line: number): never {\n return this.report.fail(UNCLOSED_QUOTE_CODE, `a quoted field starting on line ${line} is never closed`, {\n line,\n });\n }\n\n /**\n * The decoded text chunks of the input; when the delimiter is to be sniffed, the first rows\n * are buffered (bounded by PREVIEW_ROWS line breaks or PREVIEW_CHARS characters), the sniff\n * runs, and the buffered text is yielded as one chunk before the rest streams through.\n * @yields the text chunks\n * @returns nothing\n */\n private async *chunks(): AsyncGenerator<string, void, undefined> {\n const source = textChunks(this.input, this.report, this.readOptions);\n if (this.delimiterText !== null) {\n yield* source;\n return;\n }\n const pieces: string[] = [];\n let length = 0;\n let breaks = 0;\n let lastWasCr = false;\n let sniffed = false;\n for await (const chunk of source) {\n if (sniffed) {\n yield chunk;\n continue;\n }\n pieces.push(chunk);\n length += chunk.length;\n for (let i = 0; i < chunk.length && breaks < PREVIEW_ROWS; i++) {\n const c = chunk.charCodeAt(i);\n if (c === LF) {\n if (!lastWasCr) {\n breaks++;\n }\n } else if (c === CR) {\n breaks++;\n }\n lastWasCr = c === CR;\n }\n if (breaks < PREVIEW_ROWS && length < PREVIEW_CHARS) {\n continue;\n }\n const text = pieces.join(\"\");\n pieces.length = 0;\n this.sniff(text);\n sniffed = true;\n yield text;\n }\n if (!sniffed) {\n const text = pieces.join(\"\");\n if (text.length > 0) {\n this.sniff(text);\n yield text;\n }\n }\n }\n\n /**\n * Sniff the delimiter from the preview text and record it.\n * @param text - the preview\n */\n private sniff(text: string): void {\n const candidates = this.syntax.candidates ?? DELIMITER_CANDIDATES;\n // the sniff is a heuristic over the first rows: a single chunk holding a huge quoted cell\n // is capped so the candidate scans stay bounded\n const body = stripLeadingComments(text.slice(0, PREVIEW_CHARS), this.syntax.comments ?? []);\n this.delimiterText =\n sniffDelimiter(body, sniffNewline(body), candidates, this.syntax.quote, this.syntax.skipQuoteErrors) ??\n candidates[0];\n }\n}\n\n/**\n * The record state machine of RecordReader, resumable at every record end so the reader can\n * yield a record before the next one overwrites the shared cell arrays. Every state lives on the\n * instance; `scan()` runs the per-character loop over one chunk from a position and returns where\n * it stopped (after the character that completed a record, with `ready` set, or the chunk end).\n */\nclass RecordScanner {\n /** Whether a record just completed. */\n ready = false;\n\n /** The cell count of the record in progress (the completed one while `ready`). */\n count = 0;\n\n /** The line the completed record started on (valid while `ready`, and after finish()). */\n recordLine = 1;\n\n /** The line the record in progress started on. */\n private startLine = 1;\n\n private readonly reader: RecordReader;\n\n private readonly quoteCode: number;\n\n private readonly quoteText: string;\n\n private readonly commentCodes: readonly number[];\n\n private delimiterCode = -1;\n\n private state: State = START;\n\n private field = \"\";\n\n private fieldQuoted = false;\n\n private line = 1;\n\n private lastWasCr = false;\n\n /** Whether no record has started yet (comment lines are recognised until one does). */\n private leading: boolean;\n\n private comment = \"\";\n\n /** The start of the unconsumed run of the current chunk that belongs to the field or comment. */\n private segment = 0;\n\n /**\n * Create a scanner over a reader's cell arrays.\n * @param reader - the reader\n */\n constructor(reader: RecordReader) {\n this.reader = reader;\n this.quoteCode = reader.syntax.quote.charCodeAt(0);\n this.quoteText = reader.syntax.quote;\n this.commentCodes = (reader.syntax.comments ?? []).map((c) => c.charCodeAt(0));\n this.leading = this.commentCodes.length > 0;\n }\n\n /**\n * Set the delimiter once it is known (before the first chunk is scanned).\n * @param code - the delimiter's character code\n */\n setDelimiter(code: number): void {\n if (this.delimiterCode < 0) {\n this.delimiterCode = code;\n }\n }\n\n /**\n * Scan one chunk from a position until a record completes or the chunk ends.\n * @param chunk - the chunk\n * @param from - where to start\n * @returns the position after the last character consumed\n */\n scan(chunk: string, from: number): number {\n const { quoteCode, delimiterCode } = this;\n const n = chunk.length;\n let i = from;\n this.segment = from;\n while (i < n) {\n const c = chunk.charCodeAt(i);\n if (this.state === COMMENT) {\n if (c === LF || c === CR) {\n this.comment += chunk.slice(this.segment, i);\n this.reader.leadingComments.push(this.comment);\n this.comment = \"\";\n this.state = START;\n this.endLine(c);\n this.segment = i + 1;\n }\n i++;\n continue;\n }\n if (this.state === QUOTED) {\n // jump to the next quote; the run in between is field text whose line breaks are counted\n const q = chunk.indexOf(this.quoteText, i);\n const end = q < 0 ? n : q;\n if (end > i) {\n this.countLineBreaks(chunk, i, end);\n }\n if (q < 0) {\n i = n;\n break;\n }\n this.field += chunk.slice(this.segment, q);\n this.state = CLOSING;\n this.lastWasCr = false;\n i = q + 1;\n continue;\n }\n if (this.state === CLOSING) {\n if (c === quoteCode) {\n this.field += this.quoteText;\n this.segment = i + 1;\n this.state = QUOTED;\n this.lastWasCr = false;\n i++;\n continue;\n }\n if (c !== delimiterCode && c !== LF && c !== CR) {\n this.reader.badQuote(this.startLine);\n }\n this.state = AFTER_QUOTED;\n this.segment = i;\n // fall through to the delimiter / line-end handling below without consuming c\n }\n if (c === delimiterCode || c === LF || c === CR) {\n if (c === LF && this.lastWasCr) {\n // the second half of a CRLF already ended the record\n this.lastWasCr = false;\n this.segment = i + 1;\n i++;\n continue;\n }\n if (this.state === UNQUOTED) {\n this.field += chunk.slice(this.segment, i);\n }\n if (c === delimiterCode) {\n this.push();\n this.state = START;\n this.lastWasCr = false;\n this.segment = i + 1;\n i++;\n continue;\n }\n const blank = this.state === START && this.count === 0;\n if (!blank) {\n this.push();\n this.ready = true;\n this.recordLine = this.startLine;\n }\n this.state = START;\n this.endLine(c);\n this.segment = i + 1;\n i++;\n if (this.ready) {\n return i;\n }\n continue;\n }\n this.lastWasCr = false;\n if (this.state === START) {\n if (this.leading && this.count === 0 && this.commentCodes.includes(c)) {\n this.state = COMMENT;\n this.segment = i;\n i++;\n continue;\n }\n this.leading = false;\n if (c === quoteCode) {\n this.state = QUOTED;\n this.fieldQuoted = true;\n this.segment = i + 1;\n } else {\n this.state = UNQUOTED;\n this.segment = i;\n }\n }\n i++;\n }\n return i;\n }\n\n /**\n * Keep the tail of a chunk that belongs to an open field or comment.\n * @param chunk - the chunk just scanned to its end\n */\n endChunk(chunk: string): void {\n const n = chunk.length;\n if (this.segment >= n) {\n return;\n }\n if (this.state === COMMENT) {\n this.comment += chunk.slice(this.segment, n);\n } else if (this.state === QUOTED || this.state === UNQUOTED) {\n this.field += chunk.slice(this.segment, n);\n }\n this.segment = n;\n }\n\n /**\n * The end of the input: an open comment is kept, an open quote is fatal, an open record\n * (no trailing line break) is completed.\n * @returns true when a last record is ready\n */\n finish(): boolean {\n const { state } = this;\n if (state === COMMENT) {\n this.reader.leadingComments.push(this.comment);\n return false;\n }\n if (state === QUOTED) {\n this.reader.unclosedQuote(this.startLine);\n }\n if (state !== START || this.count > 0) {\n this.push();\n this.recordLine = this.startLine;\n return true;\n }\n return false;\n }\n\n /**\n * Count the line breaks of a run of quoted text (a CRLF counts once, like the record loop).\n * @param chunk - the chunk\n * @param from - the first index of the run\n * @param to - the index after the run\n */\n private countLineBreaks(chunk: string, from: number, to: number): void {\n let { line, lastWasCr } = this;\n for (let i = from; i < to; i++) {\n const c = chunk.charCodeAt(i);\n if (c === LF) {\n if (!lastWasCr) {\n line++;\n }\n lastWasCr = false;\n } else if (c === CR) {\n line++;\n lastWasCr = true;\n } else {\n lastWasCr = false;\n }\n }\n this.line = line;\n this.lastWasCr = lastWasCr;\n }\n\n /** Store the field in progress as the next cell. */\n private push(): void {\n const { reader, count } = this;\n reader.cells[count] = this.field;\n reader.quoted[count] = this.fieldQuoted;\n this.count = count + 1;\n this.field = \"\";\n this.fieldQuoted = false;\n }\n\n /**\n * Count a line break that ends a record or a comment line.\n * @param c - the LF or CR\n */\n private endLine(c: number): void {\n if (!(c === LF && this.lastWasCr)) {\n this.line++;\n }\n this.startLine = this.line;\n this.lastWasCr = c === CR;\n }\n}\n\n/** What the CSV importer's reader needs besides the input. */\nexport interface CsvReaderOptions extends ReadOptions {\n /** The delimiter; null or undefined sniffs it from the preview. */\n readonly delimiter?: string | null | undefined;\n /** The characters opening a leading comment line (RecordSyntax.comments); none by default. */\n readonly comments?: readonly string[] | undefined;\n /** RecordSyntax.skipQuoteErrors; false by default. */\n readonly skipQuoteErrors?: boolean | undefined;\n}\n\n/**\n * Records of a CSV input, one string array per row, streamed: iterate with\n * `for await (const row of reader)` and read `reader.line` for the 1-based line the row starts\n * on. The delimiter is known after the first row (`reader.delimiter`). Rows come out as fresh\n * arrays of cell texts exactly as written (no trimming, no typing); `reader.quoted` tells, for\n * the row just yielded, which cells were quoted (a quoted empty cell is the empty string, an\n * unquoted one is \"not set\"). Blank lines and whitespace-only single-cell lines are skipped.\n */\nexport class CsvRecordReader implements AsyncIterable<string[]> {\n private readonly inner: RecordReader;\n\n /**\n * Create a reader; nothing is read until iteration starts.\n * @param input - the input\n * @param report - the report parse errors are recorded in\n * @param options - the delimiter, cancellation and progress\n */\n constructor(input: ImportInput, report: ImportReportBuilder, options: CsvReaderOptions = {}) {\n this.inner = new RecordReader(\n input,\n report,\n {\n delimiter: options.delimiter ?? null,\n quote: '\"',\n comments: options.comments,\n skipQuoteErrors: options.skipQuoteErrors,\n },\n { signal: options.signal, onProgress: options.onProgress, encoding: options.encoding },\n );\n }\n\n /**\n * The leading comment lines the reader skipped (SNAP `#` lines, the KONECT `%` header), in order.\n * @returns the lines without their line breaks\n */\n get leadingComments(): readonly string[] {\n return this.inner.leadingComments;\n }\n\n /**\n * The 1-based line the most recently yielded row starts on.\n * @returns the line; 0 before the first row\n */\n get line(): number {\n return this.inner.line;\n }\n\n /**\n * The delimiter in use.\n * @returns the given or sniffed delimiter; null before the sniff ran\n */\n get delimiter(): string | null {\n return this.inner.delimiter;\n }\n\n /**\n * Whether each cell of the row most recently yielded was quoted.\n * @returns the flags (valid for the first `row.length` entries)\n */\n get quoted(): readonly boolean[] {\n return this.inner.quoted;\n }\n\n /**\n * Iterate the rows.\n * @yields one row at a time as its cell texts\n * @returns nothing\n */\n async *[Symbol.asyncIterator](): AsyncGenerator<string[], void, undefined> {\n const { inner } = this;\n for await (const count of inner) {\n if (count === 1 && !inner.quoted[0] && inner.cells[0].trim().length === 0) {\n continue;\n }\n yield inner.cells.slice(0, count);\n }\n }\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"records-DSpbTE5s.js","sources":["../../src/formats/csv/records.ts"],"sourcesContent":["/**\n * The one streaming CSV record reader of the package (design sections 8.2 and 8.4: hand-written\n * tokenisers per format; CSV and Neo4j CSV are line-oriented over a byte stream): RFC 4180 records\n * with a configurable single-character delimiter and quote, a doubled quote inside a quoted field,\n * quoted fields spanning lines, LF / CRLF / lone-CR terminators, read from the common text reader\n * one chunk at a time as a character state machine. Only the open field is ever held, so a field\n * spanning many chunks costs its length once and a multi-gigabyte file is never buffered.\n *\n * `RecordReader` (used by the Neo4j importer) keeps one reusable cell array and one reusable\n * \"was quoted\" array: a quoted empty field (`\"\"`) is an empty string while an unquoted empty field\n * means \"not set\", and only the tokeniser can tell the two apart. `CsvRecordReader` (the CSV\n * importer) wraps it with delimiter sniffing over a bounded preview and yields a fresh cell array\n * per row. A malformed quoted field is fatal for both: an unterminated quote swallows the rest of\n * the file, and text after a closing quote makes every later cell boundary unreliable.\n */\n\nimport { GraphFormatError } from \"@graphty/graph-format\";\n\nimport { type ReadOptions, textChunks } from \"../../common/input.js\";\nimport { type ImportReportBuilder } from \"../../common/report.js\";\nimport { type ImportInput } from \"../../types.js\";\n\n/** Issue code: a quoted field is never closed; the import aborts (everything after it would be one cell). */\nexport const UNCLOSED_QUOTE_CODE = \"E_CSV_UNCLOSED_QUOTE\";\n\n/** Issue code: a closing quote is followed by text other than a delimiter or a line break; the import aborts. */\nexport const BAD_QUOTE_CODE = \"E_CSV_QUOTE\";\n\n/** The delimiters tried, in priority order, when none is given. */\nexport const DELIMITER_CANDIDATES: readonly string[] = Object.freeze([\",\", \"\\t\", \";\", \"|\", \" \"]);\n\n/** Rows the delimiter sniff looks at. */\nconst PREVIEW_ROWS = 10;\n\n/** Characters buffered for the sniff when the input has fewer than PREVIEW_ROWS line breaks. */\nconst PREVIEW_CHARS = 64 * 1024;\n\nconst LF = 10;\nconst CR = 13;\n\n/** Tokeniser state: at the start of a field. */\nconst START = 0;\n/** Tokeniser state: inside an unquoted field. */\nconst UNQUOTED = 1;\n/** Tokeniser state: inside a quoted field. */\nconst QUOTED = 2;\n/** Tokeniser state: just after a quote inside a quoted field (a second quote is a literal, anything else ends the field). */\nconst CLOSING = 3;\n/** Tokeniser state: after a closed quoted field, before the delimiter (text here is malformed). */\nconst AFTER_QUOTED = 4;\n/** Inside a leading comment line (skipped up to its line break). */\nconst COMMENT = 5;\n\ntype State = typeof START | typeof UNQUOTED | typeof QUOTED | typeof CLOSING | typeof AFTER_QUOTED | typeof COMMENT;\n\n/** The delimiter and quote of a reader. */\nexport interface RecordSyntax {\n /** The field delimiter, one character; null sniffs it from the first rows. */\n readonly delimiter: string | null;\n /** The quote character, one character. */\n readonly quote: string;\n /** The delimiters tried when `delimiter` is null; DELIMITER_CANDIDATES by default. */\n readonly candidates?: readonly string[] | undefined;\n /**\n * Characters that open a comment line while no record has been read yet (SNAP `#`, KONECT\n * `%`): such leading lines are skipped, kept in `leadingComments` and left out of the delimiter\n * sniff. A later line starting with one of them is an ordinary record. Default: none.\n */\n readonly comments?: readonly string[] | undefined;\n /**\n * Whether the delimiter sniff skips a candidate under which a closing quote is followed by\n * other text (see sniffDelimiter). False by default: that text then aborts the read.\n */\n readonly skipQuoteErrors?: boolean | undefined;\n}\n\n/**\n * Check a delimiter or quote option: exactly one character that is not a line break, and the two\n * must differ.\n * @param syntax - the delimiter (or null for sniffing) and quote\n * @returns the syntax unchanged; E_UNSUPPORTED when invalid\n */\nexport function checkRecordSyntax(syntax: RecordSyntax): RecordSyntax {\n for (const [option, value] of [\n [\"delimiter\", syntax.delimiter],\n [\"quote\", syntax.quote],\n ] as const) {\n if (value === null) {\n continue;\n }\n if (value.length !== 1 || value === \"\\n\" || value === \"\\r\") {\n throw new GraphFormatError(\n \"E_UNSUPPORTED\",\n `option ${option}: ${JSON.stringify(value)} is not a single non-line-break character`,\n { option, found: value },\n );\n }\n }\n if (syntax.delimiter !== null && syntax.delimiter === syntax.quote) {\n throw new GraphFormatError(\"E_UNSUPPORTED\", \"options delimiter and quote must differ\", {\n option: \"delimiter\",\n found: syntax.delimiter,\n });\n }\n return syntax;\n}\n\n/**\n * Sniff the line terminator of a text: a lone `\\r` only when the text has `\\r` and no `\\n` at all\n * (classic Mac files); `\\n` otherwise.\n * @param text - the preview text\n * @returns \"\\n\" or \"\\r\"\n */\nexport function sniffNewline(text: string): \"\\n\" | \"\\r\" {\n return !text.includes(\"\\n\") && text.includes(\"\\r\") ? \"\\r\" : \"\\n\";\n}\n\n/**\n * Split a text into records synchronously (the first `maxRows` of them), honouring quotes; for\n * the delimiter sniff and the registry's head sniff, where the input is a bounded preview.\n * @param text - the text\n * @param delimiter - the delimiter\n * @param quote - the quote character\n * @param maxRows - the most rows to return\n * @param strictQuotes - return null when a closing quote is followed by text other than the\n * delimiter or a line break (the import would abort under this delimiter)\n * @returns the rows as cell arrays (blank lines skipped), or null (see strictQuotes)\n */\nfunction splitRecords(\n text: string,\n delimiter: string,\n quote: string,\n maxRows: number,\n strictQuotes = false,\n): string[][] | null {\n const rows: string[][] = [];\n const delimiterCode = delimiter.charCodeAt(0);\n const quoteCode = quote.charCodeAt(0);\n let cells: string[] = [];\n let state: State = START;\n let segment = 0;\n let field = \"\";\n const n = text.length;\n for (let i = 0; i < n && rows.length < maxRows; i++) {\n const c = text.charCodeAt(i);\n if (state === QUOTED) {\n if (c === quoteCode) {\n field += text.slice(segment, i);\n state = CLOSING;\n }\n continue;\n }\n if (state === CLOSING) {\n if (c === quoteCode) {\n field += quote;\n segment = i + 1;\n state = QUOTED;\n continue;\n }\n if (strictQuotes && c !== delimiterCode && c !== LF && c !== CR) {\n return null;\n }\n state = AFTER_QUOTED;\n segment = i;\n }\n if (c === delimiterCode || c === LF || c === CR) {\n if (state === UNQUOTED || state === AFTER_QUOTED) {\n field += text.slice(segment, i);\n }\n if (c === delimiterCode) {\n cells.push(field);\n field = \"\";\n state = START;\n } else {\n if (state !== START || cells.length > 0) {\n cells.push(field);\n rows.push(cells);\n cells = [];\n field = \"\";\n }\n state = START;\n if (c === CR && text.charCodeAt(i + 1) === LF) {\n i++;\n }\n }\n segment = i + 1;\n continue;\n }\n if (state === START) {\n if (c === quoteCode) {\n state = QUOTED;\n segment = i + 1;\n } else {\n state = UNQUOTED;\n segment = i;\n }\n }\n }\n if (rows.length < maxRows && (state !== START || cells.length > 0)) {\n if (state === UNQUOTED || state === AFTER_QUOTED || state === QUOTED) {\n field += text.slice(segment, n);\n }\n cells.push(field);\n rows.push(cells);\n }\n return rows;\n}\n\n/**\n * The preview text without its leading comment lines (those starting with one of the comment\n * characters), so the sniff sees the records only.\n * @param text - the preview text\n * @param comments - the comment characters\n * @returns the text from the first non-comment line on\n */\nfunction stripLeadingComments(text: string, comments: readonly string[]): string {\n if (comments.length === 0) {\n return text;\n }\n let at = 0;\n while (at < text.length && comments.includes(text[at])) {\n const lf = text.indexOf(\"\\n\", at);\n const cr = text.indexOf(\"\\r\", at);\n const end = Math.min(lf < 0 ? Infinity : lf, cr < 0 ? Infinity : cr);\n if (end === Infinity) {\n return \"\";\n }\n at = end + 1;\n if (text[at - 1] === \"\\r\" && text[at] === \"\\n\") {\n at++;\n }\n }\n return at === 0 ? text : text.slice(at);\n}\n\n/**\n * Sniff the delimiter of a text: every candidate is tried over the first rows and the one whose\n * field count is most consistent across rows wins (ties broken by the higher field count); a\n * candidate that yields fewer than two fields per row on average is never chosen. `null` when no\n * candidate qualifies (a single-column file).\n * @param text - the preview text\n * @param newline - the sniffed line terminator (unused by the splitter, which reads every kind;\n * kept for callers that sniffed it)\n * @param candidates - the delimiters to try, in priority order\n * @param quote - the quote character\n * @param skipQuoteErrors - also never choose a candidate under which a closing quote is followed\n * by other text. Only for inputs whose field counts say nothing (an adjacency table's rows vary in\n * width): elsewhere a stray character after a quote would make a worse candidate win silently\n * instead of aborting the read\n * @returns the delimiter, or null\n */\nexport function sniffDelimiter(\n text: string,\n newline: \"\\n\" | \"\\r\" = \"\\n\",\n candidates: readonly string[] = DELIMITER_CANDIDATES,\n quote = '\"',\n skipQuoteErrors = false,\n): string | null {\n let best: string | null = null;\n let bestDelta = Infinity;\n let bestAverage = 0;\n const terminated = text.endsWith(\"\\n\") || text.endsWith(\"\\r\");\n for (const delimiter of candidates) {\n if (delimiter === quote || delimiter === newline) {\n continue;\n }\n const split = splitRecords(text, delimiter, quote, PREVIEW_ROWS, skipQuoteErrors);\n if (split === null) {\n // a quoted cell this delimiter does not close: it is not the file's delimiter\n continue;\n }\n let rows = split.filter((row) => !isBlankRow(row));\n if (rows.length > 1 && !terminated) {\n // the preview is a prefix of the file: its last row may be cut short\n rows = rows.slice(0, -1);\n }\n if (rows.length === 0) {\n continue;\n }\n let total = 0;\n let delta = 0;\n for (let i = 0; i < rows.length; i++) {\n const count = rows[i].length;\n total += count;\n if (i > 0) {\n delta += Math.abs(count - rows[i - 1].length);\n }\n }\n const average = total / rows.length;\n if (average > 1.99 && (delta < bestDelta || (delta === bestDelta && average > bestAverage))) {\n best = delimiter;\n bestDelta = delta;\n bestAverage = average;\n }\n }\n return best;\n}\n\n/**\n * Whether a parsed row is a blank line: one cell holding only whitespace.\n * @param row - the row\n * @returns true for a blank line\n */\nfunction isBlankRow(row: readonly string[]): boolean {\n return row.length === 1 && row[0].trim().length === 0;\n}\n\n/**\n * Reads the records of one input. Iterate with `for await (const count of reader)`: each\n * iteration fills `reader.cells[0..count)` and `reader.quoted[0..count)` and sets `reader.line`\n * to the 1-based line the record started on. Blank lines (an empty unquoted record of one field)\n * are skipped. The arrays are reused between records. When the syntax gives no delimiter, the\n * first rows (PREVIEW_ROWS, or PREVIEW_CHARS characters) are buffered and the delimiter sniffed\n * from them before the first record is yielded.\n */\nexport class RecordReader implements AsyncIterable<number> {\n /** The cells of the record most recently yielded; only the first `count` entries are valid. */\n readonly cells: string[] = [];\n\n /** Whether each cell of the record most recently yielded was quoted. */\n readonly quoted: boolean[] = [];\n\n /** The leading comment lines (without their line breaks), in order; empty without `syntax.comments`. */\n readonly leadingComments: string[] = [];\n\n private readonly input: ImportInput;\n\n private readonly report: ImportReportBuilder;\n\n private readonly readOptions: ReadOptions;\n\n /** The delimiter (null while unsniffed), quote and comment characters. */\n readonly syntax: RecordSyntax;\n\n private delimiterText: string | null;\n\n private recordLine = 0;\n\n /**\n * Create a reader; nothing is read until iteration starts.\n * @param input - the input (or an async iterable of already decoded text chunks)\n * @param report - the report decode and quoting errors are recorded in\n * @param syntax - the delimiter (null to sniff) and quote (already checked)\n * @param readOptions - cancellation and progress\n */\n constructor(input: ImportInput, report: ImportReportBuilder, syntax: RecordSyntax, readOptions: ReadOptions) {\n this.input = input;\n this.report = report;\n this.readOptions = readOptions;\n this.syntax = syntax;\n this.delimiterText = syntax.delimiter;\n }\n\n /**\n * The 1-based line the most recently yielded record started on.\n * @returns the line number; 0 before the first record\n */\n get line(): number {\n return this.recordLine;\n }\n\n /**\n * The delimiter in use.\n * @returns the given or sniffed delimiter; null before the sniff ran\n */\n get delimiter(): string | null {\n return this.delimiterText;\n }\n\n /**\n * Iterate the records.\n * @yields the number of cells of each record\n * @returns nothing\n */\n async *[Symbol.asyncIterator](): AsyncGenerator<number, void, undefined> {\n const scanner = new RecordScanner(this);\n for await (const chunk of this.chunks()) {\n // the first chunk arrives after the sniff (or with the given delimiter)\n scanner.setDelimiter((this.delimiterText ?? \",\").charCodeAt(0));\n let i = 0;\n while (i < chunk.length) {\n i = scanner.scan(chunk, i);\n if (scanner.ready) {\n scanner.ready = false;\n this.recordLine = scanner.recordLine;\n yield scanner.count;\n scanner.count = 0;\n }\n }\n scanner.endChunk(chunk);\n }\n if (scanner.finish()) {\n this.recordLine = scanner.recordLine;\n yield scanner.count;\n }\n }\n\n /**\n * Record a text-after-quote error (fatal).\n * @param line - the line the field started on\n * @returns never\n */\n badQuote(line: number): never {\n return this.report.fail(BAD_QUOTE_CODE, `line ${line}: text after the closing quote of a quoted field`, {\n line,\n });\n }\n\n /**\n * Record an unclosed-quote error (fatal).\n * @param line - the line the field started on\n * @returns never\n */\n unclosedQuote(line: number): never {\n return this.report.fail(UNCLOSED_QUOTE_CODE, `a quoted field starting on line ${line} is never closed`, {\n line,\n });\n }\n\n /**\n * The decoded text chunks of the input; when the delimiter is to be sniffed, the first rows\n * are buffered (bounded by PREVIEW_ROWS line breaks or PREVIEW_CHARS characters), the sniff\n * runs, and the buffered text is yielded as one chunk before the rest streams through.\n * @yields the text chunks\n * @returns nothing\n */\n private async *chunks(): AsyncGenerator<string, void, undefined> {\n const source = textChunks(this.input, this.report, this.readOptions);\n if (this.delimiterText !== null) {\n yield* source;\n return;\n }\n const pieces: string[] = [];\n let length = 0;\n let breaks = 0;\n let lastWasCr = false;\n let sniffed = false;\n for await (const chunk of source) {\n if (sniffed) {\n yield chunk;\n continue;\n }\n pieces.push(chunk);\n length += chunk.length;\n for (let i = 0; i < chunk.length && breaks < PREVIEW_ROWS; i++) {\n const c = chunk.charCodeAt(i);\n if (c === LF) {\n if (!lastWasCr) {\n breaks++;\n }\n } else if (c === CR) {\n breaks++;\n }\n lastWasCr = c === CR;\n }\n if (breaks < PREVIEW_ROWS && length < PREVIEW_CHARS) {\n continue;\n }\n const text = pieces.join(\"\");\n pieces.length = 0;\n this.sniff(text);\n sniffed = true;\n yield text;\n }\n if (!sniffed) {\n const text = pieces.join(\"\");\n if (text.length > 0) {\n this.sniff(text);\n yield text;\n }\n }\n }\n\n /**\n * Sniff the delimiter from the preview text and record it.\n * @param text - the preview\n */\n private sniff(text: string): void {\n const candidates = this.syntax.candidates ?? DELIMITER_CANDIDATES;\n // the sniff is a heuristic over the first rows: a single chunk holding a huge quoted cell\n // is capped so the candidate scans stay bounded\n const body = stripLeadingComments(text.slice(0, PREVIEW_CHARS), this.syntax.comments ?? []);\n this.delimiterText =\n sniffDelimiter(body, sniffNewline(body), candidates, this.syntax.quote, this.syntax.skipQuoteErrors) ??\n candidates[0];\n }\n}\n\n/**\n * The record state machine of RecordReader, resumable at every record end so the reader can\n * yield a record before the next one overwrites the shared cell arrays. Every state lives on the\n * instance; `scan()` runs the per-character loop over one chunk from a position and returns where\n * it stopped (after the character that completed a record, with `ready` set, or the chunk end).\n */\nclass RecordScanner {\n /** Whether a record just completed. */\n ready = false;\n\n /** The cell count of the record in progress (the completed one while `ready`). */\n count = 0;\n\n /** The line the completed record started on (valid while `ready`, and after finish()). */\n recordLine = 1;\n\n /** The line the record in progress started on. */\n private startLine = 1;\n\n private readonly reader: RecordReader;\n\n private readonly quoteCode: number;\n\n private readonly quoteText: string;\n\n private readonly commentCodes: readonly number[];\n\n private delimiterCode = -1;\n\n private state: State = START;\n\n private field = \"\";\n\n private fieldQuoted = false;\n\n private line = 1;\n\n private lastWasCr = false;\n\n /** Whether no record has started yet (comment lines are recognised until one does). */\n private leading: boolean;\n\n private comment = \"\";\n\n /** The start of the unconsumed run of the current chunk that belongs to the field or comment. */\n private segment = 0;\n\n /**\n * Create a scanner over a reader's cell arrays.\n * @param reader - the reader\n */\n constructor(reader: RecordReader) {\n this.reader = reader;\n this.quoteCode = reader.syntax.quote.charCodeAt(0);\n this.quoteText = reader.syntax.quote;\n this.commentCodes = (reader.syntax.comments ?? []).map((c) => c.charCodeAt(0));\n this.leading = this.commentCodes.length > 0;\n }\n\n /**\n * Set the delimiter once it is known (before the first chunk is scanned).\n * @param code - the delimiter's character code\n */\n setDelimiter(code: number): void {\n if (this.delimiterCode < 0) {\n this.delimiterCode = code;\n }\n }\n\n /**\n * Scan one chunk from a position until a record completes or the chunk ends.\n * @param chunk - the chunk\n * @param from - where to start\n * @returns the position after the last character consumed\n */\n scan(chunk: string, from: number): number {\n const { quoteCode, delimiterCode } = this;\n const n = chunk.length;\n let i = from;\n this.segment = from;\n while (i < n) {\n const c = chunk.charCodeAt(i);\n if (this.state === COMMENT) {\n if (c === LF || c === CR) {\n this.comment += chunk.slice(this.segment, i);\n this.reader.leadingComments.push(this.comment);\n this.comment = \"\";\n this.state = START;\n this.endLine(c);\n this.segment = i + 1;\n }\n i++;\n continue;\n }\n if (this.state === QUOTED) {\n // jump to the next quote; the run in between is field text whose line breaks are counted\n const q = chunk.indexOf(this.quoteText, i);\n const end = q < 0 ? n : q;\n if (end > i) {\n this.countLineBreaks(chunk, i, end);\n }\n if (q < 0) {\n i = n;\n break;\n }\n this.field += chunk.slice(this.segment, q);\n this.state = CLOSING;\n this.lastWasCr = false;\n i = q + 1;\n continue;\n }\n if (this.state === CLOSING) {\n if (c === quoteCode) {\n this.field += this.quoteText;\n this.segment = i + 1;\n this.state = QUOTED;\n this.lastWasCr = false;\n i++;\n continue;\n }\n if (c !== delimiterCode && c !== LF && c !== CR) {\n this.reader.badQuote(this.startLine);\n }\n this.state = AFTER_QUOTED;\n this.segment = i;\n // fall through to the delimiter / line-end handling below without consuming c\n }\n if (c === delimiterCode || c === LF || c === CR) {\n if (c === LF && this.lastWasCr) {\n // the second half of a CRLF already ended the record\n this.lastWasCr = false;\n this.segment = i + 1;\n i++;\n continue;\n }\n if (this.state === UNQUOTED) {\n this.field += chunk.slice(this.segment, i);\n }\n if (c === delimiterCode) {\n this.push();\n this.state = START;\n this.lastWasCr = false;\n this.segment = i + 1;\n i++;\n continue;\n }\n const blank = this.state === START && this.count === 0;\n if (!blank) {\n this.push();\n this.ready = true;\n this.recordLine = this.startLine;\n }\n this.state = START;\n this.endLine(c);\n this.segment = i + 1;\n i++;\n if (this.ready) {\n return i;\n }\n continue;\n }\n this.lastWasCr = false;\n if (this.state === START) {\n if (this.leading && this.count === 0 && this.commentCodes.includes(c)) {\n this.state = COMMENT;\n this.segment = i;\n i++;\n continue;\n }\n this.leading = false;\n if (c === quoteCode) {\n this.state = QUOTED;\n this.fieldQuoted = true;\n this.segment = i + 1;\n } else {\n this.state = UNQUOTED;\n this.segment = i;\n }\n }\n i++;\n }\n return i;\n }\n\n /**\n * Keep the tail of a chunk that belongs to an open field or comment.\n * @param chunk - the chunk just scanned to its end\n */\n endChunk(chunk: string): void {\n const n = chunk.length;\n if (this.segment >= n) {\n return;\n }\n if (this.state === COMMENT) {\n this.comment += chunk.slice(this.segment, n);\n } else if (this.state === QUOTED || this.state === UNQUOTED) {\n this.field += chunk.slice(this.segment, n);\n }\n this.segment = n;\n }\n\n /**\n * The end of the input: an open comment is kept, an open quote is fatal, an open record\n * (no trailing line break) is completed.\n * @returns true when a last record is ready\n */\n finish(): boolean {\n const { state } = this;\n if (state === COMMENT) {\n this.reader.leadingComments.push(this.comment);\n return false;\n }\n if (state === QUOTED) {\n this.reader.unclosedQuote(this.startLine);\n }\n if (state !== START || this.count > 0) {\n this.push();\n this.recordLine = this.startLine;\n return true;\n }\n return false;\n }\n\n /**\n * Count the line breaks of a run of quoted text (a CRLF counts once, like the record loop).\n * @param chunk - the chunk\n * @param from - the first index of the run\n * @param to - the index after the run\n */\n private countLineBreaks(chunk: string, from: number, to: number): void {\n let { line, lastWasCr } = this;\n for (let i = from; i < to; i++) {\n const c = chunk.charCodeAt(i);\n if (c === LF) {\n if (!lastWasCr) {\n line++;\n }\n lastWasCr = false;\n } else if (c === CR) {\n line++;\n lastWasCr = true;\n } else {\n lastWasCr = false;\n }\n }\n this.line = line;\n this.lastWasCr = lastWasCr;\n }\n\n /** Store the field in progress as the next cell. */\n private push(): void {\n const { reader, count } = this;\n reader.cells[count] = this.field;\n reader.quoted[count] = this.fieldQuoted;\n this.count = count + 1;\n this.field = \"\";\n this.fieldQuoted = false;\n }\n\n /**\n * Count a line break that ends a record or a comment line.\n * @param c - the LF or CR\n */\n private endLine(c: number): void {\n if (!(c === LF && this.lastWasCr)) {\n this.line++;\n }\n this.startLine = this.line;\n this.lastWasCr = c === CR;\n }\n}\n\n/** What the CSV importer's reader needs besides the input. */\nexport interface CsvReaderOptions extends ReadOptions {\n /** The delimiter; null or undefined sniffs it from the preview. */\n readonly delimiter?: string | null | undefined;\n /** The characters opening a leading comment line (RecordSyntax.comments); none by default. */\n readonly comments?: readonly string[] | undefined;\n /** RecordSyntax.skipQuoteErrors; false by default. */\n readonly skipQuoteErrors?: boolean | undefined;\n}\n\n/**\n * Records of a CSV input, one string array per row, streamed: iterate with\n * `for await (const row of reader)` and read `reader.line` for the 1-based line the row starts\n * on. The delimiter is known after the first row (`reader.delimiter`). Rows come out as fresh\n * arrays of cell texts exactly as written (no trimming, no typing); `reader.quoted` tells, for\n * the row just yielded, which cells were quoted (a quoted empty cell is the empty string, an\n * unquoted one is \"not set\"). Blank lines and whitespace-only single-cell lines are skipped.\n */\nexport class CsvRecordReader implements AsyncIterable<string[]> {\n private readonly inner: RecordReader;\n\n /**\n * Create a reader; nothing is read until iteration starts.\n * @param input - the input\n * @param report - the report parse errors are recorded in\n * @param options - the delimiter, cancellation and progress\n */\n constructor(input: ImportInput, report: ImportReportBuilder, options: CsvReaderOptions = {}) {\n this.inner = new RecordReader(\n input,\n report,\n {\n delimiter: options.delimiter ?? null,\n quote: '\"',\n comments: options.comments,\n skipQuoteErrors: options.skipQuoteErrors,\n },\n { signal: options.signal, onProgress: options.onProgress, encoding: options.encoding },\n );\n }\n\n /**\n * The leading comment lines the reader skipped (SNAP `#` lines, the KONECT `%` header), in order.\n * @returns the lines without their line breaks\n */\n get leadingComments(): readonly string[] {\n return this.inner.leadingComments;\n }\n\n /**\n * The 1-based line the most recently yielded row starts on.\n * @returns the line; 0 before the first row\n */\n get line(): number {\n return this.inner.line;\n }\n\n /**\n * The delimiter in use.\n * @returns the given or sniffed delimiter; null before the sniff ran\n */\n get delimiter(): string | null {\n return this.inner.delimiter;\n }\n\n /**\n * Whether each cell of the row most recently yielded was quoted.\n * @returns the flags (valid for the first `row.length` entries)\n */\n get quoted(): readonly boolean[] {\n return this.inner.quoted;\n }\n\n /**\n * Iterate the rows.\n * @yields one row at a time as its cell texts\n * @returns nothing\n */\n async *[Symbol.asyncIterator](): AsyncGenerator<string[], void, undefined> {\n const { inner } = this;\n for await (const count of inner) {\n if (count === 1 && !inner.quoted[0] && inner.cells[0].trim().length === 0) {\n continue;\n }\n yield inner.cells.slice(0, count);\n }\n }\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -30,6 +30,21 @@ const UNKNOWN_ATTR_TYPE_CODE = "W_UNKNOWN_ATTR_TYPE";
|
|
|
30
30
|
const BAD_DEFAULT_CODE = "W_BAD_DEFAULT";
|
|
31
31
|
const BAD_OPTIONS_CODE = "W_BAD_OPTIONS";
|
|
32
32
|
const DUPLICATE_EDGE_ID_CODE = "E_DUPLICATE_EDGE_ID";
|
|
33
|
+
const BAD_VALUE_CODE = "E_BAD_VALUE";
|
|
34
|
+
const WIDENED_CODE = "W_WIDENED";
|
|
35
|
+
const DANGLING_REFERENCE_CODE = "W_DANGLING_REFERENCE";
|
|
36
|
+
const DUPLICATE_ATTRIBUTE_CODE = "W_DUPLICATE_ATTRIBUTE";
|
|
37
|
+
const PARENT_CYCLE_CODE = "E_PARENT_CYCLE";
|
|
38
|
+
const EQUATION_AS_TEXT_CODE = "W_EQUATION_AS_TEXT";
|
|
39
|
+
const STYLES_NOT_IMPORTED_CODE = "W_STYLES_NOT_IMPORTED";
|
|
40
|
+
const BAD_ASPECT_BLOCK_CODE = "E_BAD_ASPECT_BLOCK";
|
|
41
|
+
const ASPECT_ORDER_CODE = "W_ASPECT_ORDER";
|
|
42
|
+
const COUNT_MISMATCH_CODE = "W_COUNT_MISMATCH";
|
|
43
|
+
const STATUS_FAILED_CODE = "E_STATUS_FAILED";
|
|
44
|
+
const STATUS_WARNING_CODE = "W_STATUS_WARNING";
|
|
45
|
+
const TOO_LARGE_CODE = "E_TOO_LARGE";
|
|
46
|
+
const GRAPH_NOT_FOUND_CODE = "E_GRAPH_NOT_FOUND";
|
|
47
|
+
const AMBIGUOUS_GRAPH_NAME_CODE = "E_AMBIGUOUS_GRAPH_NAME";
|
|
33
48
|
const ROLE_DROPPED_CODE = "W_ROLE_DROPPED";
|
|
34
49
|
const PARENTS_DROPPED_CODE = "W_PARENTS_DROPPED";
|
|
35
50
|
const TEMPORAL_DROPPED_CODE = "W_TEMPORAL_DROPPED";
|
|
@@ -1451,6 +1466,13 @@ function startsWithUtf8(bytes) {
|
|
|
1451
1466
|
return false;
|
|
1452
1467
|
}
|
|
1453
1468
|
}
|
|
1469
|
+
function decodeEntryName(bytes) {
|
|
1470
|
+
try {
|
|
1471
|
+
return new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(bytes);
|
|
1472
|
+
} catch {
|
|
1473
|
+
return new TextDecoder("windows-1252").decode(bytes);
|
|
1474
|
+
}
|
|
1475
|
+
}
|
|
1454
1476
|
function concatBytes(chunks) {
|
|
1455
1477
|
if (chunks.length === 1) {
|
|
1456
1478
|
return chunks[0];
|
|
@@ -1792,6 +1814,58 @@ function reportUnusedOptions(options, report, used) {
|
|
|
1792
1814
|
}
|
|
1793
1815
|
return recorded;
|
|
1794
1816
|
}
|
|
1817
|
+
function chooseGraph(names, options, report) {
|
|
1818
|
+
const { graphIndex, graphName } = options ?? {};
|
|
1819
|
+
if (graphIndex !== void 0 && (typeof graphIndex !== "number" || !Number.isInteger(graphIndex) || graphIndex < 0)) {
|
|
1820
|
+
throw new GraphFormatError(
|
|
1821
|
+
"E_UNSUPPORTED",
|
|
1822
|
+
`option graphIndex: ${describe(graphIndex)} is not a non-negative integer`,
|
|
1823
|
+
{
|
|
1824
|
+
option: "graphIndex",
|
|
1825
|
+
found: graphIndex
|
|
1826
|
+
}
|
|
1827
|
+
);
|
|
1828
|
+
}
|
|
1829
|
+
if (graphName !== void 0 && typeof graphName !== "string") {
|
|
1830
|
+
throw new GraphFormatError("E_UNSUPPORTED", `option graphName: ${describe(graphName)} is not a string`, {
|
|
1831
|
+
option: "graphName",
|
|
1832
|
+
found: graphName
|
|
1833
|
+
});
|
|
1834
|
+
}
|
|
1835
|
+
if (graphIndex !== void 0 && graphName !== void 0) {
|
|
1836
|
+
throw new GraphFormatError("E_UNSUPPORTED", "options graphIndex and graphName both choose a graph; pass one", {
|
|
1837
|
+
option: "graphName",
|
|
1838
|
+
found: graphName
|
|
1839
|
+
});
|
|
1840
|
+
}
|
|
1841
|
+
if (names.length === 0) {
|
|
1842
|
+
return report.fail(NO_GRAPH_CODE, "the input holds no graph");
|
|
1843
|
+
}
|
|
1844
|
+
if (graphName !== void 0) {
|
|
1845
|
+
const matches = names.flatMap((name, i) => name === graphName ? [i] : []);
|
|
1846
|
+
if (matches.length > 1) {
|
|
1847
|
+
return report.fail(
|
|
1848
|
+
AMBIGUOUS_GRAPH_NAME_CODE,
|
|
1849
|
+
`graphName ${JSON.stringify(graphName)} names the graphs at indexes ${matches.join(", ")}; pass graphIndex`,
|
|
1850
|
+
{ element: graphName }
|
|
1851
|
+
);
|
|
1852
|
+
}
|
|
1853
|
+
if (matches.length === 0) {
|
|
1854
|
+
return report.fail(
|
|
1855
|
+
GRAPH_NOT_FOUND_CODE,
|
|
1856
|
+
`graphName ${JSON.stringify(graphName)} names none of the ${names.length} graph(s)`,
|
|
1857
|
+
{ element: graphName },
|
|
1858
|
+
{ names: [...names] }
|
|
1859
|
+
);
|
|
1860
|
+
}
|
|
1861
|
+
return matches[0];
|
|
1862
|
+
}
|
|
1863
|
+
const index = graphIndex ?? 0;
|
|
1864
|
+
if (index >= names.length) {
|
|
1865
|
+
return report.fail(GRAPH_NOT_FOUND_CODE, `graphIndex ${index} is beyond the ${names.length} graph(s)`);
|
|
1866
|
+
}
|
|
1867
|
+
return index;
|
|
1868
|
+
}
|
|
1795
1869
|
function resolveImportOptions(options, defaults) {
|
|
1796
1870
|
const o = options ?? {};
|
|
1797
1871
|
return Object.freeze({
|
|
@@ -2947,125 +3021,142 @@ function toReadableStream(chunks) {
|
|
|
2947
3021
|
});
|
|
2948
3022
|
}
|
|
2949
3023
|
export {
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
3024
|
+
PARENT_CYCLE_CODE as $,
|
|
3025
|
+
AMBIGUOUS_GRAPH_NAME_CODE as A,
|
|
3026
|
+
BAD_ASPECT_BLOCK_CODE as B,
|
|
2953
3027
|
COLUMN_RENAMED_CODE as C,
|
|
2954
|
-
|
|
3028
|
+
DANGLING_REFERENCE_CODE as D,
|
|
2955
3029
|
EMPTY_COLUMN_DROPPED_CODE as E,
|
|
2956
|
-
|
|
2957
|
-
|
|
3030
|
+
INVALID_ENCODING_CODE as F,
|
|
3031
|
+
GRAPH_NOT_FOUND_CODE as G,
|
|
2958
3032
|
HYPEREDGE_CODE as H,
|
|
2959
3033
|
ImportReportBuilder as I,
|
|
2960
|
-
|
|
2961
|
-
|
|
2962
|
-
|
|
2963
|
-
|
|
2964
|
-
|
|
2965
|
-
|
|
2966
|
-
|
|
2967
|
-
|
|
2968
|
-
|
|
2969
|
-
|
|
2970
|
-
|
|
2971
|
-
|
|
2972
|
-
|
|
2973
|
-
|
|
2974
|
-
|
|
2975
|
-
|
|
2976
|
-
|
|
2977
|
-
|
|
3034
|
+
INVALID_UTF8_CODE as J,
|
|
3035
|
+
IdCoercer as K,
|
|
3036
|
+
ImportError as L,
|
|
3037
|
+
LOSS as M,
|
|
3038
|
+
LineReader as N,
|
|
3039
|
+
MISSING_ENDPOINT_CODE as O,
|
|
3040
|
+
MISSING_ID_CODE as P,
|
|
3041
|
+
MIXED_DIRECTION_CODE as Q,
|
|
3042
|
+
MULTIPLE_GRAPHS_CODE as R,
|
|
3043
|
+
MUTUAL_AS_UNDIRECTED_CODE as S,
|
|
3044
|
+
MUTUAL_COLUMN as T,
|
|
3045
|
+
MUTUAL_EXPANDED_CODE as U,
|
|
3046
|
+
NO_CAPABILITIES as V,
|
|
3047
|
+
NO_GRAPH_CODE as W,
|
|
3048
|
+
OPTIONS_GAINED_CODE as X,
|
|
3049
|
+
OPTION_IGNORED_CODE as Y,
|
|
3050
|
+
PAIR_COLUMN as Z,
|
|
3051
|
+
PARENTS_DROPPED_CODE as _,
|
|
2978
3052
|
throwIfAborted as a,
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
|
|
2984
|
-
|
|
2985
|
-
|
|
2986
|
-
|
|
2987
|
-
|
|
2988
|
-
|
|
2989
|
-
|
|
2990
|
-
|
|
2991
|
-
|
|
2992
|
-
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
|
|
3002
|
-
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
|
|
3018
|
-
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
|
|
3023
|
-
|
|
3024
|
-
|
|
3025
|
-
|
|
3026
|
-
|
|
3027
|
-
|
|
3028
|
-
|
|
3029
|
-
|
|
3030
|
-
|
|
3031
|
-
|
|
3032
|
-
|
|
3033
|
-
|
|
3034
|
-
|
|
3035
|
-
|
|
3036
|
-
|
|
3037
|
-
|
|
3038
|
-
|
|
3039
|
-
|
|
3040
|
-
|
|
3041
|
-
|
|
3042
|
-
|
|
3043
|
-
|
|
3044
|
-
|
|
3045
|
-
|
|
3046
|
-
|
|
3047
|
-
|
|
3048
|
-
|
|
3049
|
-
|
|
3050
|
-
|
|
3051
|
-
|
|
3052
|
-
|
|
3053
|
-
|
|
3054
|
-
|
|
3055
|
-
|
|
3056
|
-
|
|
3057
|
-
|
|
3058
|
-
|
|
3059
|
-
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
|
|
3053
|
+
weightFromValue as a$,
|
|
3054
|
+
PARSE_ERROR_CODE as a0,
|
|
3055
|
+
PRECISION_CODE as a1,
|
|
3056
|
+
RENAMED_CODE as a2,
|
|
3057
|
+
ROLE_ASSUMED_CODE as a3,
|
|
3058
|
+
ROLE_DROPPED_CODE as a4,
|
|
3059
|
+
ROLE_TAKEN_CODE as a5,
|
|
3060
|
+
SINK_OPTION_CODE as a6,
|
|
3061
|
+
STATUS_FAILED_CODE as a7,
|
|
3062
|
+
STATUS_WARNING_CODE as a8,
|
|
3063
|
+
STORAGE_CLASS_CODE as a9,
|
|
3064
|
+
decodeEntryName as aA,
|
|
3065
|
+
encodeChunks as aB,
|
|
3066
|
+
explicitWeights as aC,
|
|
3067
|
+
formatDecimal as aD,
|
|
3068
|
+
formatF32 as aE,
|
|
3069
|
+
formatF64 as aF,
|
|
3070
|
+
formatGmlReal as aG,
|
|
3071
|
+
formatInteger as aH,
|
|
3072
|
+
inputLength as aI,
|
|
3073
|
+
isAbortError as aJ,
|
|
3074
|
+
isCanonicalIntegerText as aK,
|
|
3075
|
+
isImportInput as aL,
|
|
3076
|
+
isNmtoken as aM,
|
|
3077
|
+
isWeightField as aN,
|
|
3078
|
+
joinText as aO,
|
|
3079
|
+
mangleNmtoken as aP,
|
|
3080
|
+
pairFolding as aQ,
|
|
3081
|
+
parseWeightText as aR,
|
|
3082
|
+
readText as aS,
|
|
3083
|
+
reportSinkOptions as aT,
|
|
3084
|
+
reportUnusedOptions as aU,
|
|
3085
|
+
resolveExportOptions as aV,
|
|
3086
|
+
resolveImportOptions as aW,
|
|
3087
|
+
sanitizeIds as aX,
|
|
3088
|
+
toReadableStream as aY,
|
|
3089
|
+
isNameChar as aZ,
|
|
3090
|
+
countMixedEdges as a_,
|
|
3091
|
+
STRAY_TEXT_CODE as aa,
|
|
3092
|
+
STYLES_NOT_IMPORTED_CODE as ab,
|
|
3093
|
+
SYNTAX_CODE as ac,
|
|
3094
|
+
TEMPORAL_DROPPED_CODE as ad,
|
|
3095
|
+
TEMPORAL_TEXT_DROPPED_CODE as ae,
|
|
3096
|
+
TEXT_INFERRED_CODE as af,
|
|
3097
|
+
TOO_LARGE_CODE as ag,
|
|
3098
|
+
UNKNOWN_ATTR_TYPE_CODE as ah,
|
|
3099
|
+
UNKNOWN_ELEMENT_CODE as ai,
|
|
3100
|
+
UNKNOWN_ENCODING_CODE as aj,
|
|
3101
|
+
UNKNOWN_PARENT_CODE as ak,
|
|
3102
|
+
UNKNOWN_TYPE_CODE as al,
|
|
3103
|
+
WEIGHT_KEY_CLASH_CODE as am,
|
|
3104
|
+
WIDENED_CODE as an,
|
|
3105
|
+
XML_ILLEGAL_CHAR_CODE as ao,
|
|
3106
|
+
XML_SYNTAX_CODE as ap,
|
|
3107
|
+
canonicalId as aq,
|
|
3108
|
+
capabilities as ar,
|
|
3109
|
+
checkCapabilities as as,
|
|
3110
|
+
chooseGraph as at,
|
|
3111
|
+
coerceId as au,
|
|
3112
|
+
coerceIdText as av,
|
|
3113
|
+
collectBytes as aw,
|
|
3114
|
+
declareCompanion as ax,
|
|
3115
|
+
declareResolved as ay,
|
|
3116
|
+
decodeChunks as az,
|
|
3117
|
+
ASPECT_ORDER_CODE as b,
|
|
3118
|
+
uniqueColumnName as b0,
|
|
3119
|
+
TIME_TEXT_ROLE as b1,
|
|
3120
|
+
TIME_TEXT_SUFFIX as b2,
|
|
3121
|
+
declareAttribute as b3,
|
|
3122
|
+
parseDeclaredTemporal as b4,
|
|
3123
|
+
parseDeclaredValue as b5,
|
|
3124
|
+
losesPrecision as b6,
|
|
3125
|
+
parseTimeText as b7,
|
|
3126
|
+
splitListText as b8,
|
|
3127
|
+
timeTextCompanion as b9,
|
|
3128
|
+
parseDecimalText as ba,
|
|
3129
|
+
formatTimeValue as bb,
|
|
3130
|
+
mapDeclaredType as bc,
|
|
3131
|
+
joinListText as bd,
|
|
3132
|
+
formatTemporal as be,
|
|
3133
|
+
DictHeuristic as bf,
|
|
3134
|
+
DICT_SAMPLE_ROWS as bg,
|
|
3135
|
+
declareOn as bh,
|
|
3136
|
+
takenIn as bi,
|
|
3137
|
+
BAD_DEFAULT_CODE as c,
|
|
3138
|
+
BAD_OPTIONS_CODE as d,
|
|
3139
|
+
BAD_VALUE_CODE as e,
|
|
3140
|
+
COLUMN_RENAMED_LOSS_CODE as f,
|
|
3141
|
+
COUNT_HINT_CODE as g,
|
|
3142
|
+
COUNT_MISMATCH_CODE as h,
|
|
3143
|
+
DEFAULT_CHUNK_BYTES as i,
|
|
3144
|
+
DEFAULT_ERROR_LIMIT as j,
|
|
3145
|
+
DIRECTED_COLUMN as k,
|
|
3146
|
+
DIRECTION_FORCED_CODE as l,
|
|
3147
|
+
DIRECTION_REFUSED_CODE as m,
|
|
3148
|
+
DUPLICATE_ATTRIBUTE_CODE as n,
|
|
3149
|
+
DUPLICATE_EDGE_ID_CODE as o,
|
|
3150
|
+
DUPLICATE_KEY_CODE as p,
|
|
3151
|
+
DUPLICATE_NODE_CODE as q,
|
|
3152
|
+
DirectionResolver as r,
|
|
3153
|
+
EMPTY_INPUT_CODE as s,
|
|
3063
3154
|
textChunks as t,
|
|
3064
|
-
|
|
3065
|
-
|
|
3066
|
-
|
|
3067
|
-
|
|
3068
|
-
|
|
3069
|
-
|
|
3155
|
+
ENCODING_FALLBACK_CODE as u,
|
|
3156
|
+
EQUATION_AS_TEXT_CODE as v,
|
|
3157
|
+
ID_MERGED_CODE as w,
|
|
3158
|
+
ID_TEXT_COLLISION_CODE as x,
|
|
3159
|
+
ID_TEXT_TYPE_CODE as y,
|
|
3160
|
+
INTEGRAL_F64_CODE as z
|
|
3070
3161
|
};
|
|
3071
|
-
//# sourceMappingURL=writer-
|
|
3162
|
+
//# sourceMappingURL=writer-DHHfHn11.js.map
|