"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Trie = exports.defaultTrieOptions = void 0; const gensequence_1 = require("gensequence"); const suggest_1 = require("./suggest"); const util_1 = require("./util"); const walker_1 = require("./walker"); const _defaultTrieOptions = { compoundCharacter: '+', stripCaseAndAccentsPrefix: '~', forbiddenWordPrefix: '!', }; exports.defaultTrieOptions = Object.freeze(_defaultTrieOptions); function mergeOptionalWithDefaults(options) { const { compoundCharacter = exports.defaultTrieOptions.compoundCharacter, stripCaseAndAccentsPrefix = exports.defaultTrieOptions.stripCaseAndAccentsPrefix, forbiddenWordPrefix = exports.defaultTrieOptions.forbiddenWordPrefix, } = options || {}; return { compoundCharacter, stripCaseAndAccentsPrefix, forbiddenWordPrefix }; } class Trie { constructor(root, count, options) { this.root = root; this.count = count; this._options = mergeOptionalWithDefaults(options); } /** * Number of words in the Trie */ size() { var _a; this.count = (_a = this.count) !== null && _a !== void 0 ? _a : util_1.countWords(this.root); return this.count; } get options() { return this._options; } find(text, minCompoundLength = false) { const minLength = !minCompoundLength || minCompoundLength === true ? undefined : minCompoundLength; return minCompoundLength ? this.findCompound(text, minLength) : this.findExact(text); } findCompound(text, minCompoundLength = 3, minLength = 0) { let n = this.root; let p; let q; for (p = 0; n && n.c && p < text.length; p = q) { n = n.c.get(text[p]); q = p + 1; if (n && n.f && q < text.length && q >= minCompoundLength) { const r = this.findCompound(text.slice(q), minCompoundLength, minCompoundLength); if (r && r.f) { return r; } } } return p === text.length && p >= minLength ? n : undefined; } findExact(text) { let n = this.root; let p; for (p = 0; n && n.c && p < text.length; ++p) { n = n.c.get(text[p]); } return p === text.length ? n : undefined; } has(word, minCompoundLength) { const n = this.find(word, minCompoundLength); return !!n && util_1.isWordTerminationNode(n); } /** * Provides an ordered sequence of words with the prefix of text. */ completeWord(text) { const n = this.find(text); return gensequence_1.genSequence(n && util_1.isWordTerminationNode(n) ? [text] : []).concat(n ? util_1.iteratorTrieWords(n).map((suffix) => text + suffix) : []); } /** * Suggest spellings for `text`. The results are sorted by edit distance with changes near the beginning of a word having a greater impact. * @param text - the text to search for * @param maxNumSuggestions - the maximum number of suggestions to return. * @param compoundMethod - Use to control splitting words. * @param numChanges - the maximum number of changes allowed to text. This is an approximate value, since some changes cost less than others. * the lower the value, the faster results are returned. Values less than 4 are best. */ suggest(text, maxNumSuggestions, compoundMethod, numChanges) { return this.suggestWithCost(text, maxNumSuggestions, compoundMethod, numChanges).map((a) => a.word); } /** * Suggest spellings for `text`. The results are sorted by edit distance with changes near the beginning of a word having a greater impact. * The results include the word and adjusted edit cost. This is useful for merging results from multiple tries. */ suggestWithCost(text, maxNumSuggestions, compoundMethod, numChanges) { return suggest_1.suggest(this.root, text, maxNumSuggestions, compoundMethod, numChanges); } /** * genSuggestions will generate suggestions and send them to `collector`. `collector` is responsible for returning the max acceptable cost. * Costs are measured in weighted changes. A cost of 100 is the same as 1 edit. Some edits are considered cheaper. * Returning a MaxCost < 0 will effectively cause the search for suggestions to stop. */ genSuggestions(collector, compoundMethod) { collector.collect(suggest_1.genSuggestions(this.root, collector.word, compoundMethod)); } /** * Returns an iterator that can be used to get all words in the trie. For some dictionaries, this can result in millions of words. */ words() { return util_1.iteratorTrieWords(this.root); } /** * Allows iteration over the entire tree. * On the returned Iterator, calling .next(goDeeper: boolean), allows for controlling the depth. */ iterate() { return walker_1.walker(this.root); } insert(word) { util_1.insert(word, this.root); return this; } static create(words, options) { const root = util_1.createTriFromList(words); util_1.orderTrie(root); return new Trie(root, undefined, options); } } exports.Trie = Trie; //# sourceMappingURL=trie.js.map