You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
126 lines
4.6 KiB
126 lines
4.6 KiB
"use strict"; |
|
Object.defineProperty(exports, "__esModule", { value: true }); |
|
exports.importTrie = exports.serializeTrie = exports.DATA = void 0; |
|
const TrieNode_1 = require("./TrieNode"); |
|
const gensequence_1 = require("gensequence"); |
|
const convertToTrieRefNodes_1 = require("./convertToTrieRefNodes"); |
|
const EOW = '*'; |
|
exports.DATA = EOW; |
|
function toReferences(node) { |
|
return gensequence_1.genSequence(convertToTrieRefNodes_1.convertToTrieRefNodes(node)); |
|
} |
|
const regExpEscapeChars = /([[\]\\,:{}*])/g; |
|
const regExTrailingComma = /,(\}|\n)/g; |
|
function escapeChar(char) { |
|
return char.replace(regExpEscapeChars, '\\$1'); // lgtm[js/incomplete-sanitization] |
|
} |
|
function trieToExportString(node, base) { |
|
function* walk(node) { |
|
if (node.f) { |
|
yield EOW; |
|
} |
|
if (node.r) { |
|
const refs = [...node.r].sort((a, b) => (a[0] < b[0] ? -1 : 1)); |
|
for (const n of refs) { |
|
const [c, r] = n; |
|
const ref = r ? r.toString(base) : ''; |
|
yield escapeChar(c) + ref + ','; |
|
} |
|
} |
|
} |
|
return gensequence_1.genSequence(walk(node)); |
|
} |
|
function generateHeader(base, comment) { |
|
const header = ['#!/usr/bin/env cspell-trie reader', 'TrieXv1', 'base=' + base] |
|
.concat(comment ? comment.split('\n').map((a) => '# ' + a) : []) |
|
.concat(['# Data:']); |
|
return gensequence_1.genSequence(header).map((a) => a + '\n'); |
|
} |
|
/** |
|
* Serialize a TrieNode. |
|
* Note: This is destructive. The node will no longer be usable. |
|
* Even though it is possible to preserve the trie, dealing with very large tries can consume a lot of memory. |
|
* Considering this is the last step before exporting, it was decided to let this be destructive. |
|
*/ |
|
function serializeTrie(root, options = 16) { |
|
options = typeof options === 'number' ? { base: options } : options; |
|
const { base = 16, comment = '' } = options; |
|
const radix = base > 36 ? 36 : base < 10 ? 10 : base; |
|
const rows = toReferences(root).map((node) => { |
|
const row = [...trieToExportString(node, radix), '\n'].join('').replace(regExTrailingComma, '$1'); |
|
return row; |
|
}); |
|
return generateHeader(radix, comment).concat(rows); |
|
} |
|
exports.serializeTrie = serializeTrie; |
|
function* toIterableIterator(iter) { |
|
yield* iter; |
|
} |
|
function importTrie(linesX) { |
|
let radix = 16; |
|
const comment = /^\s*#/; |
|
const iter = toIterableIterator(linesX); |
|
function parseHeaderRows(headerRows) { |
|
const header = headerRows.slice(0, 2).join('\n'); |
|
const headerReg = /^TrieXv1\nbase=(\d+)$/; |
|
/* istanbul ignore if */ |
|
if (!headerReg.test(header)) |
|
throw new Error('Unknown file format'); |
|
radix = Number.parseInt(header.replace(headerReg, '$1'), 10); |
|
} |
|
function readHeader(iter) { |
|
const headerRows = []; |
|
// eslint-disable-next-line no-constant-condition |
|
while (true) { |
|
const next = iter.next(); |
|
if (next.done) { |
|
break; |
|
} |
|
const line = next.value.trim(); |
|
if (!line || comment.test(line)) { |
|
continue; |
|
} |
|
if (line === exports.DATA) { |
|
break; |
|
} |
|
headerRows.push(line); |
|
} |
|
parseHeaderRows(headerRows); |
|
} |
|
const regNotEscapedCommas = /(^|[^\\]),/g; |
|
const regUnescapeCommas = /__COMMA__/g; |
|
const regUnescape = /[\\](.)/g; |
|
const flagsWord = { f: TrieNode_1.FLAG_WORD }; |
|
function splitLine(line) { |
|
const pattern = '$1__COMMA__'; |
|
return line |
|
.replace(regNotEscapedCommas, pattern) |
|
.split(regUnescapeCommas) |
|
.map((a) => a.replace(regUnescape, '$1')); |
|
} |
|
function decodeLine(line, nodes) { |
|
const isWord = line[0] === EOW; |
|
line = isWord ? line.slice(1) : line; |
|
const flags = isWord ? flagsWord : {}; |
|
const children = splitLine(line) |
|
.filter((a) => !!a) |
|
.map((a) => [a[0], Number.parseInt(a.slice(1) || '0', radix)]) |
|
.map(([k, i]) => [k, nodes[i]]); |
|
const cNode = children.length ? { c: new TrieNode_1.ChildMap(children) } : {}; |
|
return { ...cNode, ...flags }; |
|
} |
|
readHeader(iter); |
|
const n = gensequence_1.genSequence([exports.DATA]) |
|
.concat(iter) |
|
.map((a) => a.replace(/\r?\n/, '')) |
|
.filter((a) => !!a) |
|
.reduce((acc, line) => { |
|
const { lines, nodes } = acc; |
|
const root = decodeLine(line, nodes); |
|
nodes[lines] = root; |
|
return { lines: lines + 1, root, nodes }; |
|
}, { lines: 0, nodes: [], root: {} }); |
|
return n.root; |
|
} |
|
exports.importTrie = importTrie; |
|
//# sourceMappingURL=importExportV1.js.map
|