cspell-trie-lib 5.18.0-alpha.0 → 5.18.3

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.
Files changed (34) hide show
  1. package/dist/lib/distance/weightedMaps.d.ts +4 -2
  2. package/dist/lib/distance/weightedMaps.js +14 -3
  3. package/dist/lib/find.d.ts +8 -7
  4. package/dist/lib/find.js +6 -4
  5. package/dist/lib/index.d.ts +2 -1
  6. package/dist/lib/index.js +3 -1
  7. package/dist/lib/mappers/mapToSuggestionCostDef.js +2 -2
  8. package/dist/lib/suggestCollector.d.ts +1 -1
  9. package/dist/lib/suggestCollector.js +2 -1
  10. package/dist/lib/{genSuggestionsOptions.d.ts → suggestions/genSuggestionsOptions.d.ts} +6 -1
  11. package/dist/lib/{genSuggestionsOptions.js → suggestions/genSuggestionsOptions.js} +1 -0
  12. package/dist/lib/suggestions/suggest.d.ts +2 -2
  13. package/dist/lib/suggestions/suggest.js +5 -5
  14. package/dist/lib/suggestions/suggestAStar.d.ts +1 -1
  15. package/dist/lib/suggestions/suggestAStar.js +2 -2
  16. package/dist/lib/suggestions/suggestCollector.d.ts +24 -6
  17. package/dist/lib/suggestions/suggestCollector.js +62 -21
  18. package/dist/lib/suggestions/walker/hintedWalker.d.ts +22 -0
  19. package/dist/lib/suggestions/walker/hintedWalker.js +109 -0
  20. package/dist/lib/suggestions/walker/index.d.ts +5 -0
  21. package/dist/lib/suggestions/walker/index.js +18 -0
  22. package/dist/lib/suggestions/walker/walker.d.ts +8 -0
  23. package/dist/lib/suggestions/walker/walker.js +43 -0
  24. package/dist/lib/suggestions/walker/walkerTypes.d.ts +24 -0
  25. package/dist/lib/suggestions/walker/walkerTypes.js +21 -0
  26. package/dist/lib/trie-util.js +1 -2
  27. package/dist/lib/trie.d.ts +1 -1
  28. package/dist/lib/trie.js +10 -4
  29. package/dist/lib/types.d.ts +9 -0
  30. package/dist/lib/utils/util.d.ts +13 -0
  31. package/dist/lib/utils/util.js +25 -1
  32. package/dist/lib/walker.d.ts +1 -42
  33. package/dist/lib/walker.js +11 -151
  34. package/package.json +6 -6
@@ -74,11 +74,13 @@ export declare function prettyPrintReplace(trie: TrieTrieCost, pfx?: string, ind
74
74
  export declare function prettyPrintSwap(trie: TrieTrieCost, pfx?: string, indent?: string): string;
75
75
  export declare function prettyPrintWeightMap(map: WeightMap): string;
76
76
  export declare function lookupReplaceCost(map: WeightMap, a: string, b: string): undefined | number;
77
+ declare function normalizeDef(def: SuggestionCostMapDef): SuggestionCostMapDef;
77
78
  export declare const __testing__: {
78
- splitMap: typeof splitMap;
79
- splitMapSubstrings: typeof splitMapSubstrings;
80
79
  findTrieCostPrefixes: typeof findTrieCostPrefixes;
81
80
  findTrieTrieCostPrefixes: typeof findTrieTrieCostPrefixes;
81
+ normalizeDef: typeof normalizeDef;
82
+ splitMap: typeof splitMap;
83
+ splitMapSubstrings: typeof splitMapSubstrings;
82
84
  };
83
85
  export {};
84
86
  //# sourceMappingURL=weightedMaps.d.ts.map
@@ -1,6 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.__testing__ = exports.lookupReplaceCost = exports.prettyPrintWeightMap = exports.prettyPrintSwap = exports.prettyPrintReplace = exports.splitMapSubstrings = exports.splitMapSubstringsIterable = exports.addDefsToWeightMap = exports.addDefToWeightMap = exports.createWeightMap = void 0;
4
+ const suggestCollector_1 = require("../suggestions/suggestCollector");
5
+ const matchPossibleWordSeparators = /[+∙•・●]/g;
4
6
  function createWeightMap(...defs) {
5
7
  const map = _createWeightMap();
6
8
  addDefsToWeightMap(map, defs);
@@ -17,7 +19,8 @@ function addDefsToWeightMap(map, defs) {
17
19
  addSetToTrieTrieCost(map.replace, set, def.replace, def.penalty);
18
20
  addSetToTrieTrieCost(map.swap, set, def.swap, def.penalty);
19
21
  }
20
- for (const def of defs) {
22
+ for (const _def of defs) {
23
+ const def = normalizeDef(_def);
21
24
  const mapSets = splitMap(def);
22
25
  mapSets.forEach((s) => addSet(s, def));
23
26
  }
@@ -262,10 +265,18 @@ function lookupReplaceCost(map, a, b) {
262
265
  return t === null || t === void 0 ? void 0 : t.c;
263
266
  }
264
267
  exports.lookupReplaceCost = lookupReplaceCost;
268
+ function normalizeDef(def) {
269
+ const { map, ...rest } = def;
270
+ return { ...rest, map: normalizeMap(map) };
271
+ }
272
+ function normalizeMap(map) {
273
+ return map.replace(matchPossibleWordSeparators, suggestCollector_1.DEFAULT_COMPOUNDED_WORD_SEPARATOR);
274
+ }
265
275
  exports.__testing__ = {
266
- splitMap,
267
- splitMapSubstrings,
268
276
  findTrieCostPrefixes,
269
277
  findTrieTrieCostPrefixes,
278
+ normalizeDef,
279
+ splitMap,
280
+ splitMapSubstrings,
270
281
  };
271
282
  //# sourceMappingURL=weightedMaps.js.map
@@ -1,5 +1,6 @@
1
- import { TrieNode } from './TrieNode';
1
+ import { TrieNode, TrieRoot } from './TrieNode';
2
2
  import type { PartialWithUndefined } from './types';
3
+ declare type Root = PartialWithUndefined<TrieRoot>;
3
4
  /**
4
5
  * No compounding allowed.
5
6
  */
@@ -48,20 +49,20 @@ export interface FindFullNodeResult extends FindNodeResult, FindFullResult {
48
49
  * @param word A pre normalized word use `normalizeWord` or `normalizeWordToLowercase`
49
50
  * @param options
50
51
  */
51
- export declare function findWord(root: TrieNode, word: string, options?: PartialFindOptions): FindFullResult;
52
+ export declare function findWord(root: Root, word: string, options?: PartialFindOptions): FindFullResult;
52
53
  /**
53
54
  *
54
55
  * @param root Trie root node. root.c contains the compound root and forbidden root.
55
56
  * @param word A pre normalized word use `normalizeWord` or `normalizeWordToLowercase`
56
57
  * @param options
57
58
  */
58
- export declare function findWordNode(root: TrieNode, word: string, options?: PartialFindOptions): FindFullNodeResult;
59
- export declare function findLegacyCompound(root: TrieNode, word: string, options: FindOptions): FindFullNodeResult;
60
- export declare function findCompoundNode(root: TrieNode | undefined, word: string, compoundCharacter: string, ignoreCasePrefix: string): FindFullNodeResult;
61
- export declare function findWordExact(root: TrieNode | undefined, word: string): boolean;
59
+ export declare function findWordNode(root: Root, word: string, options?: PartialFindOptions): FindFullNodeResult;
60
+ export declare function findLegacyCompound(root: Root, word: string, options: FindOptions): FindFullNodeResult;
61
+ export declare function findCompoundNode(root: Root | undefined, word: string, compoundCharacter: string, ignoreCasePrefix: string): FindFullNodeResult;
62
+ export declare function findWordExact(root: Root | TrieNode | undefined, word: string): boolean;
62
63
  export declare function isEndOfWordNode(n: TrieNode | undefined): boolean;
63
64
  declare function findLegacyCompoundWord(roots: (TrieNode | undefined)[], word: string, minCompoundLength: number): FindResult;
64
- export declare function isForbiddenWord(root: TrieNode | undefined, word: string, forbiddenPrefix: string): boolean;
65
+ export declare function isForbiddenWord(root: Root | TrieNode | undefined, word: string, forbiddenPrefix: string): boolean;
65
66
  export declare function createFindOptions(options: PartialFindOptions | undefined): FindOptions;
66
67
  export declare const __testing__: {
67
68
  findLegacyCompoundWord: typeof findLegacyCompoundWord;
package/dist/lib/find.js CHANGED
@@ -42,8 +42,8 @@ exports.findWordNode = findWordNode;
42
42
  * @param options
43
43
  */
44
44
  function _findWord(root, word, options) {
45
- const { found, forbidden, compoundUsed, caseMatched } = _findWordNode(root, word, options);
46
- return { found, forbidden, compoundUsed, caseMatched };
45
+ const { node: _, ...result } = _findWordNode(root, word, options);
46
+ return result;
47
47
  }
48
48
  /**
49
49
  *
@@ -52,9 +52,10 @@ function _findWord(root, word, options) {
52
52
  * @param options
53
53
  */
54
54
  function _findWordNode(root, word, options) {
55
+ var _a, _b;
55
56
  const compoundMode = knownCompoundModes.get(options.compoundMode) || _defaultFindOptions.compoundMode;
56
- const compoundPrefix = options.compoundMode === 'compound' ? options.compoundFix : '';
57
- const ignoreCasePrefix = options.matchCase ? '' : options.caseInsensitivePrefix;
57
+ const compoundPrefix = options.compoundMode === 'compound' ? (_a = root.compoundCharacter) !== null && _a !== void 0 ? _a : options.compoundFix : '';
58
+ const ignoreCasePrefix = options.matchCase ? '' : (_b = root.stripCaseAndAccentsPrefix) !== null && _b !== void 0 ? _b : options.caseInsensitivePrefix;
58
59
  function __findCompound() {
59
60
  const f = findCompoundWord(root, word, compoundPrefix, ignoreCasePrefix);
60
61
  const result = { ...f };
@@ -99,6 +100,7 @@ function findCompoundNode(root, word, compoundCharacter, ignoreCasePrefix) {
99
100
  var _a, _b, _c;
100
101
  // Approach - do a depth first search for the matching word.
101
102
  const stack = [
103
+ // { n: root, compoundPrefix: '', cr: undefined, caseMatched: true },
102
104
  { n: root, compoundPrefix: ignoreCasePrefix, cr: undefined, caseMatched: true },
103
105
  ];
104
106
  const compoundPrefix = compoundCharacter || ignoreCasePrefix;
@@ -6,7 +6,8 @@ export { ExportOptions, importTrie, serializeTrie } from './io/importExport';
6
6
  export { mapDictionaryInformationToWeightMap } from './mappers/mapDictionaryInfoToWeightMap';
7
7
  export type { SuggestionCostMapDef } from './models/suggestionCostsDef';
8
8
  export { parseDictionary, parseDictionaryLines } from './SimpleDictionaryParser';
9
- export { MaxCost, suggestionCollector, SuggestionCollector, SuggestionResult } from './suggestCollector';
9
+ export { impersonateCollector, suggestionCollector } from './suggestCollector';
10
+ export type { MaxCost, SuggestionCollector, SuggestionResult } from './suggestCollector';
10
11
  export { CASE_INSENSITIVE_PREFIX, COMPOUND, COMPOUND_FIX, defaultTrieOptions, FORBID, FORBID_PREFIX, NORMALIZED, OPTIONAL_COMPOUND, OPTIONAL_COMPOUND_FIX, Trie, } from './trie';
11
12
  export type { FindWordOptions, PartialTrieOptions, TrieOptions } from './trie';
12
13
  export { countNodes, countWords, createTrieRoot, createTriFromList, findNode, has, insert, isCircular, isDefined, isWordTerminationNode, iterateTrie, iteratorTrieWords, mergeDefaults, mergeOptionalWithDefaults, normalizeWord, normalizeWordForCaseInsensitive, normalizeWordToLowercase, orderTrie, trieNodeToRoot, walk, } from './trie-util';
package/dist/lib/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.WORD_SEPARATOR = exports.walker = exports.JOIN_SEPARATOR = exports.hintedWalker = exports.CompoundWordsMethod = exports.FLAG_WORD = exports.ChildMap = exports.TrieBuilder = exports.buildTrieFast = exports.buildTrie = exports.walk = exports.trieNodeToRoot = exports.orderTrie = exports.normalizeWordToLowercase = exports.normalizeWordForCaseInsensitive = exports.normalizeWord = exports.mergeOptionalWithDefaults = exports.mergeDefaults = exports.iteratorTrieWords = exports.iterateTrie = exports.isWordTerminationNode = exports.isDefined = exports.isCircular = exports.insert = exports.has = exports.findNode = exports.createTriFromList = exports.createTrieRoot = exports.countWords = exports.countNodes = exports.Trie = exports.OPTIONAL_COMPOUND_FIX = exports.OPTIONAL_COMPOUND = exports.NORMALIZED = exports.FORBID_PREFIX = exports.FORBID = exports.defaultTrieOptions = exports.COMPOUND_FIX = exports.COMPOUND = exports.CASE_INSENSITIVE_PREFIX = exports.suggestionCollector = exports.parseDictionaryLines = exports.parseDictionary = exports.mapDictionaryInformationToWeightMap = exports.serializeTrie = exports.importTrie = exports.editDistanceWeighted = exports.editDistance = exports.createWeightedMap = exports.consolidate = void 0;
3
+ exports.walker = exports.JOIN_SEPARATOR = exports.hintedWalker = exports.CompoundWordsMethod = exports.FLAG_WORD = exports.ChildMap = exports.TrieBuilder = exports.buildTrieFast = exports.buildTrie = exports.walk = exports.trieNodeToRoot = exports.orderTrie = exports.normalizeWordToLowercase = exports.normalizeWordForCaseInsensitive = exports.normalizeWord = exports.mergeOptionalWithDefaults = exports.mergeDefaults = exports.iteratorTrieWords = exports.iterateTrie = exports.isWordTerminationNode = exports.isDefined = exports.isCircular = exports.insert = exports.has = exports.findNode = exports.createTriFromList = exports.createTrieRoot = exports.countWords = exports.countNodes = exports.Trie = exports.OPTIONAL_COMPOUND_FIX = exports.OPTIONAL_COMPOUND = exports.NORMALIZED = exports.FORBID_PREFIX = exports.FORBID = exports.defaultTrieOptions = exports.COMPOUND_FIX = exports.COMPOUND = exports.CASE_INSENSITIVE_PREFIX = exports.suggestionCollector = exports.impersonateCollector = exports.parseDictionaryLines = exports.parseDictionary = exports.mapDictionaryInformationToWeightMap = exports.serializeTrie = exports.importTrie = exports.editDistanceWeighted = exports.editDistance = exports.createWeightedMap = exports.consolidate = void 0;
4
+ exports.WORD_SEPARATOR = void 0;
4
5
  var consolidate_1 = require("./consolidate");
5
6
  Object.defineProperty(exports, "consolidate", { enumerable: true, get: function () { return consolidate_1.consolidate; } });
6
7
  var distance_1 = require("./distance");
@@ -16,6 +17,7 @@ var SimpleDictionaryParser_1 = require("./SimpleDictionaryParser");
16
17
  Object.defineProperty(exports, "parseDictionary", { enumerable: true, get: function () { return SimpleDictionaryParser_1.parseDictionary; } });
17
18
  Object.defineProperty(exports, "parseDictionaryLines", { enumerable: true, get: function () { return SimpleDictionaryParser_1.parseDictionaryLines; } });
18
19
  var suggestCollector_1 = require("./suggestCollector");
20
+ Object.defineProperty(exports, "impersonateCollector", { enumerable: true, get: function () { return suggestCollector_1.impersonateCollector; } });
19
21
  Object.defineProperty(exports, "suggestionCollector", { enumerable: true, get: function () { return suggestCollector_1.suggestionCollector; } });
20
22
  var trie_1 = require("./trie");
21
23
  Object.defineProperty(exports, "CASE_INSENSITIVE_PREFIX", { enumerable: true, get: function () { return trie_1.CASE_INSENSITIVE_PREFIX; } });
@@ -51,14 +51,14 @@ function calcFirstCharacterReplace(cs, editCost) {
51
51
  ...(0, cspell_pipe_1.pipeSync)((0, text_1.expandCharacterSet)(cs.characters), (0, cspell_pipe_1.opUnique)(), (0, cspell_pipe_1.opMap)((letter) => `(^${letter})`)),
52
52
  ]
53
53
  .sort()
54
- .join('');
54
+ .join('') + '(^)';
55
55
  const penalty = editCost.firstLetterPenalty;
56
56
  // Make it a bit cheaper so it will match
57
57
  const cost = cs.cost - penalty;
58
58
  return {
59
59
  map: mapOfFirstLetters,
60
60
  replace: cost,
61
- penalty,
61
+ penalty: penalty * 2,
62
62
  };
63
63
  }
64
64
  exports.calcFirstCharacterReplace = calcFirstCharacterReplace;
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * This file is here to support code the referenced suggest directly and limit the exports.
3
3
  */
4
- export { compSuggestionResults, defaultSuggestionCollectorOptions, isSuggestionResult, suggestionCollector, } from './suggestions/suggestCollector';
4
+ export { compSuggestionResults, defaultSuggestionCollectorOptions, impersonateCollector, isSuggestionResult, suggestionCollector, } from './suggestions/suggestCollector';
5
5
  export type { Cost, FilterWordFn, GenerateNextParam, GenerateSuggestionResult, MaxCost, Progress, SuggestionCollector, SuggestionCollectorOptions, SuggestionGenerator, SuggestionResult, } from './suggestions/suggestCollector';
6
6
  //# sourceMappingURL=suggestCollector.d.ts.map
@@ -1,12 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.suggestionCollector = exports.isSuggestionResult = exports.defaultSuggestionCollectorOptions = exports.compSuggestionResults = void 0;
3
+ exports.suggestionCollector = exports.isSuggestionResult = exports.impersonateCollector = exports.defaultSuggestionCollectorOptions = exports.compSuggestionResults = void 0;
4
4
  /**
5
5
  * This file is here to support code the referenced suggest directly and limit the exports.
6
6
  */
7
7
  var suggestCollector_1 = require("./suggestions/suggestCollector");
8
8
  Object.defineProperty(exports, "compSuggestionResults", { enumerable: true, get: function () { return suggestCollector_1.compSuggestionResults; } });
9
9
  Object.defineProperty(exports, "defaultSuggestionCollectorOptions", { enumerable: true, get: function () { return suggestCollector_1.defaultSuggestionCollectorOptions; } });
10
+ Object.defineProperty(exports, "impersonateCollector", { enumerable: true, get: function () { return suggestCollector_1.impersonateCollector; } });
10
11
  Object.defineProperty(exports, "isSuggestionResult", { enumerable: true, get: function () { return suggestCollector_1.isSuggestionResult; } });
11
12
  Object.defineProperty(exports, "suggestionCollector", { enumerable: true, get: function () { return suggestCollector_1.suggestionCollector; } });
12
13
  //# sourceMappingURL=suggestCollector.js.map
@@ -1,4 +1,4 @@
1
- import { WeightMap } from '.';
1
+ import { WeightMap } from '..';
2
2
  import { CompoundWordsMethod } from './walker';
3
3
  export interface GenSuggestionOptionsStrict {
4
4
  /**
@@ -15,6 +15,11 @@ export interface GenSuggestionOptionsStrict {
15
15
  * 3 is a good number. Above 5 can be very slow.
16
16
  */
17
17
  changeLimit: number;
18
+ /**
19
+ * Inserts a compound character between compounded word segments.
20
+ * @default ""
21
+ */
22
+ compoundSeparator?: string;
18
23
  }
19
24
  export declare type GenSuggestionOptions = Partial<GenSuggestionOptionsStrict>;
20
25
  export interface SuggestionOptionsStrict extends GenSuggestionOptionsStrict {
@@ -17,6 +17,7 @@ const keyMapOfGenSuggestionOptionsStrict = {
17
17
  changeLimit: 'changeLimit',
18
18
  compoundMethod: 'compoundMethod',
19
19
  ignoreCase: 'ignoreCase',
20
+ compoundSeparator: 'compoundSeparator',
20
21
  };
21
22
  const keyMapOfSuggestionOptionsStrict = {
22
23
  ...keyMapOfGenSuggestionOptionsStrict,
@@ -1,6 +1,6 @@
1
- import { GenSuggestionOptions, SuggestionOptions } from '../genSuggestionsOptions';
2
- import { SuggestionGenerator, SuggestionResult } from './suggestCollector';
3
1
  import { TrieRoot } from '../TrieNode';
2
+ import { GenSuggestionOptions, SuggestionOptions } from './genSuggestionsOptions';
3
+ import { SuggestionGenerator, SuggestionResult } from './suggestCollector';
4
4
  export declare function suggest(root: TrieRoot | TrieRoot[], word: string, options?: SuggestionOptions): SuggestionResult[];
5
5
  export declare function genSuggestions(root: TrieRoot | TrieRoot[], word: string, options?: GenSuggestionOptions): SuggestionGenerator;
6
6
  export declare function genCompoundableSuggestions(root: TrieRoot, word: string, options?: GenSuggestionOptions): SuggestionGenerator;
@@ -1,11 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.genCompoundableSuggestions = exports.genSuggestions = exports.suggest = void 0;
4
- const genSuggestionsOptions_1 = require("../genSuggestionsOptions");
4
+ const trie_util_1 = require("../trie-util");
5
+ const genSuggestionsOptions_1 = require("./genSuggestionsOptions");
5
6
  const orthography_1 = require("./orthography");
6
7
  const suggestCollector_1 = require("./suggestCollector");
7
- const trie_util_1 = require("../trie-util");
8
- const walker_1 = require("../walker");
8
+ const walker_1 = require("./walker");
9
9
  const baseCost = 100;
10
10
  const swapCost = 75;
11
11
  const postSwapCost = swapCost - baseCost;
@@ -18,7 +18,7 @@ function suggest(root, word, options = {}) {
18
18
  const opts = (0, genSuggestionsOptions_1.createSuggestionOptions)(options);
19
19
  const collectorOpts = (0, trie_util_1.clean)(opts);
20
20
  const collector = (0, suggestCollector_1.suggestionCollector)(word, collectorOpts);
21
- collector.collect(genSuggestions(root, word, opts));
21
+ collector.collect(genSuggestions(root, word, { ...opts, ...collector.genSuggestionOptions }));
22
22
  return collector.suggestions;
23
23
  }
24
24
  exports.suggest = suggest;
@@ -68,7 +68,7 @@ function* genCompoundableSuggestions(root, word, options = {}) {
68
68
  }
69
69
  stack[0] = { a, b };
70
70
  const hint = word;
71
- const iWalk = (0, walker_1.hintedWalker)(root, ignoreCase, hint, compoundMethod);
71
+ const iWalk = (0, walker_1.hintedWalker)(root, ignoreCase, hint, compoundMethod, options.compoundSeparator);
72
72
  let goDeeper = true;
73
73
  for (let r = iWalk.next({ goDeeper }); !stopNow && !r.done; r = iWalk.next({ goDeeper })) {
74
74
  const { text, node, depth } = r.value;
@@ -1,6 +1,6 @@
1
1
  import { TrieRoot } from '../TrieNode';
2
2
  import { SuggestionGenerator, SuggestionResult } from './suggestCollector';
3
- import { GenSuggestionOptionsStrict, SuggestionOptions } from '../genSuggestionsOptions';
3
+ import { GenSuggestionOptionsStrict, SuggestionOptions } from './genSuggestionsOptions';
4
4
  export declare function genCompoundableSuggestions(root: TrieRoot, word: string, options: GenSuggestionOptionsStrict): SuggestionGenerator;
5
5
  export declare function suggest(root: TrieRoot | TrieRoot[], word: string, options: SuggestionOptions): SuggestionResult[];
6
6
  export declare function genSuggestions(root: TrieRoot | TrieRoot[], word: string, options: GenSuggestionOptionsStrict): SuggestionGenerator;
@@ -1,11 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.genSuggestions = exports.suggest = exports.genCompoundableSuggestions = void 0;
4
- const walker_1 = require("../walker");
4
+ const walker_1 = require("./walker");
5
5
  const suggestCollector_1 = require("./suggestCollector");
6
6
  const PairingHeap_1 = require("../utils/PairingHeap");
7
7
  const orthography_1 = require("./orthography");
8
- const genSuggestionsOptions_1 = require("../genSuggestionsOptions");
8
+ const genSuggestionsOptions_1 = require("./genSuggestionsOptions");
9
9
  function* genCompoundableSuggestions(root, word, options) {
10
10
  const { compoundMethod, ignoreCase, changeLimit } = options;
11
11
  const len = word.length;
@@ -1,10 +1,19 @@
1
1
  import { WeightMap } from '..';
2
+ import { RequireOptional } from '../types';
3
+ import { GenSuggestionOptions, GenSuggestionOptionsStrict } from './genSuggestionsOptions';
4
+ export declare const DEFAULT_COMPOUNDED_WORD_SEPARATOR = "\u2219";
2
5
  export declare type Cost = number;
3
6
  export declare type MaxCost = Cost;
4
- export interface SuggestionResult {
7
+ export interface SuggestionResultBase {
8
+ /** The suggested word */
5
9
  word: string;
10
+ /** The edit cost 100 = 1 edit */
6
11
  cost: Cost;
7
12
  }
13
+ export interface SuggestionResult extends SuggestionResultBase {
14
+ /** The suggested word with compound marks, generally a `•` */
15
+ compoundWord?: string | undefined;
16
+ }
8
17
  export interface Progress {
9
18
  type: 'progress';
10
19
  /** Number of Completed Tasks so far */
@@ -16,7 +25,7 @@ export interface Progress {
16
25
  remaining: number;
17
26
  }
18
27
  export declare type GenerateNextParam = MaxCost | symbol | undefined;
19
- export declare type GenerateSuggestionResult = SuggestionResult | Progress | undefined;
28
+ export declare type GenerateSuggestionResult = SuggestionResultBase | Progress | undefined;
20
29
  /**
21
30
  * Ask for the next result.
22
31
  * maxCost - sets the max cost for following suggestions
@@ -26,7 +35,7 @@ export declare type GenerateSuggestionResult = SuggestionResult | Progress | und
26
35
  * The SuggestionIterator is generally the
27
36
  */
28
37
  export declare type SuggestionGenerator = Generator<GenerateSuggestionResult, void, GenerateNextParam>;
29
- export declare function compSuggestionResults(a: SuggestionResult, b: SuggestionResult): number;
38
+ export declare function compSuggestionResults(a: SuggestionResultBase, b: SuggestionResultBase): number;
30
39
  export declare type FilterWordFn = (word: string, cost: number) => boolean;
31
40
  export interface SuggestionCollector {
32
41
  /**
@@ -40,7 +49,7 @@ export interface SuggestionCollector {
40
49
  * if (r === collector.symbolStopProcessing) // ...stop generating suggestions.
41
50
  */
42
51
  collect: (src: SuggestionGenerator, timeout?: number, filter?: FilterWordFn) => void;
43
- add: (suggestion: SuggestionResult) => SuggestionCollector;
52
+ add: (suggestion: SuggestionResultBase) => SuggestionCollector;
44
53
  readonly suggestions: SuggestionResult[];
45
54
  readonly changeLimit: number;
46
55
  readonly maxCost: number;
@@ -48,12 +57,13 @@ export interface SuggestionCollector {
48
57
  readonly maxNumSuggestions: number;
49
58
  readonly includesTies: boolean;
50
59
  readonly ignoreCase: boolean;
60
+ readonly genSuggestionOptions: GenSuggestionOptions;
51
61
  /**
52
62
  * Possible value sent to the SuggestionIterator telling it to stop processing.
53
63
  */
54
64
  readonly symbolStopProcessing: symbol;
55
65
  }
56
- export interface SuggestionCollectorOptions {
66
+ export interface SuggestionCollectorOptions extends Omit<GenSuggestionOptionsStrict, 'ignoreCase' | 'changeLimit'> {
57
67
  /**
58
68
  * number of best matching suggestions.
59
69
  * @default 10
@@ -90,7 +100,15 @@ export interface SuggestionCollectorOptions {
90
100
  */
91
101
  weightMap?: WeightMap | undefined;
92
102
  }
93
- export declare const defaultSuggestionCollectorOptions: SuggestionCollectorOptions;
103
+ export declare const defaultSuggestionCollectorOptions: RequireOptional<SuggestionCollectorOptions>;
94
104
  export declare function suggestionCollector(wordToMatch: string, options: SuggestionCollectorOptions): SuggestionCollector;
105
+ /**
106
+ * Impersonating a Collector, allows searching for multiple variants on the same word.
107
+ * The collection is still in the original collector.
108
+ * @param collector - collector to impersonate
109
+ * @param word - word to present instead of `collector.word`.
110
+ * @returns a SuggestionCollector
111
+ */
112
+ export declare function impersonateCollector(collector: SuggestionCollector, word: string): SuggestionCollector;
95
113
  export declare function isSuggestionResult(s: GenerateSuggestionResult): s is SuggestionResult;
96
114
  //# sourceMappingURL=suggestCollector.d.ts.map
@@ -1,9 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.isSuggestionResult = exports.suggestionCollector = exports.defaultSuggestionCollectorOptions = exports.compSuggestionResults = void 0;
3
+ exports.isSuggestionResult = exports.impersonateCollector = exports.suggestionCollector = exports.defaultSuggestionCollectorOptions = exports.compSuggestionResults = exports.DEFAULT_COMPOUNDED_WORD_SEPARATOR = void 0;
4
4
  const __1 = require("..");
5
+ const weightedMaps_1 = require("../distance/weightedMaps");
5
6
  const timer_1 = require("../utils/timer");
6
- const walker_1 = require("../walker");
7
+ const util_1 = require("../utils/util");
8
+ const walker_1 = require("./walker");
7
9
  const defaultMaxNumberSuggestions = 10;
8
10
  const BASE_COST = 100;
9
11
  const MAX_NUM_CHANGES = 5;
@@ -11,9 +13,12 @@ const MAX_COST_SCALE = 0.5;
11
13
  // max allowed cost scale should be a bit over 50% to allow for suggestions to short words, but not too high to have too many suggestions.
12
14
  const MAX_ALLOWED_COST_SCALE = 1.03 * MAX_COST_SCALE;
13
15
  const collator = new Intl.Collator();
14
- const regexSeparator = new RegExp(`[${regexQuote(walker_1.JOIN_SEPARATOR + walker_1.WORD_SEPARATOR)}]`, 'g');
16
+ // This is a bit broken, it was supposed to also include JOIN_SEPARATOR (`+`)
17
+ // Add it back later.
18
+ const regexSeparator = new RegExp(`[${(0, util_1.regexQuote)(walker_1.WORD_SEPARATOR)}]`, 'g');
15
19
  const wordLengthCost = [0, 50, 25, 5, 0];
16
20
  const EXTRA_WORD_COST = 5;
21
+ exports.DEFAULT_COMPOUNDED_WORD_SEPARATOR = '∙';
17
22
  /** time in ms */
18
23
  const DEFAULT_COLLECTOR_TIMEOUT = 1000;
19
24
  const symStopProcessing = Symbol('Collector Stop Processing');
@@ -29,12 +34,28 @@ exports.defaultSuggestionCollectorOptions = Object.freeze({
29
34
  includeTies: false,
30
35
  ignoreCase: true,
31
36
  timeout: DEFAULT_COLLECTOR_TIMEOUT,
37
+ weightMap: undefined,
38
+ compoundSeparator: '',
39
+ compoundMethod: undefined,
32
40
  });
33
41
  function suggestionCollector(wordToMatch, options) {
34
- const { filter = () => true, changeLimit = MAX_NUM_CHANGES, includeTies = false, ignoreCase = true, timeout = DEFAULT_COLLECTOR_TIMEOUT, weightMap, } = options;
42
+ const { filter = () => true, changeLimit = MAX_NUM_CHANGES, includeTies = false, ignoreCase = true, timeout = DEFAULT_COLLECTOR_TIMEOUT, weightMap, compoundSeparator = exports.defaultSuggestionCollectorOptions.compoundSeparator, } = options;
35
43
  const numSuggestions = Math.max(options.numSuggestions, 0) || 0;
44
+ const numSugToHold = weightMap ? numSuggestions * 2 : numSuggestions;
36
45
  const sugs = new Map();
37
46
  let maxCost = BASE_COST * Math.min(wordToMatch.length * MAX_ALLOWED_COST_SCALE, changeLimit);
47
+ const useSeparator = compoundSeparator ||
48
+ (weightMap ? exports.DEFAULT_COMPOUNDED_WORD_SEPARATOR : exports.defaultSuggestionCollectorOptions.compoundSeparator);
49
+ const fnCleanWord = !useSeparator || useSeparator === compoundSeparator ? (w) => w : (0, util_1.replaceAllFactory)(useSeparator, '');
50
+ if (useSeparator && weightMap) {
51
+ (0, weightedMaps_1.addDefToWeightMap)(weightMap, { map: useSeparator, insDel: 50 });
52
+ }
53
+ const genSuggestionOptions = (0, util_1.clean)({
54
+ changeLimit,
55
+ ignoreCase,
56
+ compoundMethod: options.compoundMethod,
57
+ compoundSeparator: useSeparator,
58
+ });
38
59
  let timeRemaining = timeout;
39
60
  function dropMax() {
40
61
  if (sugs.size < 2 || !numSuggestions) {
@@ -42,7 +63,7 @@ function suggestionCollector(wordToMatch, options) {
42
63
  return;
43
64
  }
44
65
  const sorted = [...sugs.values()].sort(compSuggestionResults);
45
- let i = numSuggestions - 1;
66
+ let i = numSugToHold - 1;
46
67
  maxCost = sorted[i].cost;
47
68
  for (; i < sorted.length && sorted[i].cost <= maxCost; ++i) {
48
69
  /* empty */
@@ -57,9 +78,6 @@ function suggestionCollector(wordToMatch, options) {
57
78
  (words.length - 1) * EXTRA_WORD_COST;
58
79
  return { word: sug.word, cost: sug.cost + extraCost };
59
80
  }
60
- function handleProgress(_progress) {
61
- // Do nothing.
62
- }
63
81
  function collectSuggestion(suggestion) {
64
82
  const { word, cost } = adjustCost(suggestion);
65
83
  if (cost <= maxCost && filter(suggestion.word, cost)) {
@@ -69,7 +87,7 @@ function suggestionCollector(wordToMatch, options) {
69
87
  }
70
88
  else {
71
89
  sugs.set(word, { word, cost });
72
- if (cost < maxCost && sugs.size > numSuggestions) {
90
+ if (cost < maxCost && sugs.size > numSugToHold) {
73
91
  dropMax();
74
92
  }
75
93
  }
@@ -102,11 +120,24 @@ function suggestionCollector(wordToMatch, options) {
102
120
  }
103
121
  continue;
104
122
  }
105
- handleProgress(value);
106
123
  }
107
124
  timeRemaining -= timer.elapsed();
108
125
  }
126
+ function cleanCompoundResult(sr) {
127
+ const { word, cost } = sr;
128
+ const cWord = fnCleanWord(word);
129
+ if (cWord !== word) {
130
+ return {
131
+ word: cWord,
132
+ cost,
133
+ compoundWord: word,
134
+ };
135
+ }
136
+ return { ...sr };
137
+ }
109
138
  function suggestions() {
139
+ if (numSuggestions < 1 || !sugs.size)
140
+ return [];
110
141
  const NF = 'NFD';
111
142
  const nWordToMatch = wordToMatch.normalize(NF);
112
143
  const rawValues = [...sugs.values()];
@@ -116,10 +147,14 @@ function suggestionCollector(wordToMatch, options) {
116
147
  cost: (0, __1.editDistanceWeighted)(nWordToMatch, word.normalize(NF), weightMap, 110),
117
148
  }))
118
149
  : rawValues;
119
- const sorted = values.sort(compSuggestionResults);
120
- if (!includeTies && sorted.length > numSuggestions) {
121
- sorted.length = numSuggestions;
150
+ const sorted = values.sort(compSuggestionResults).map(cleanCompoundResult);
151
+ let i = Math.min(sorted.length, numSuggestions) - 1;
152
+ const limit = includeTies ? sorted.length : Math.min(sorted.length, numSuggestions);
153
+ const maxCost = sorted[i].cost;
154
+ for (++i; i < limit && sorted[i].cost === maxCost; ++i) {
155
+ // loop
122
156
  }
157
+ sorted.length = i;
123
158
  return sorted;
124
159
  }
125
160
  const collector = {
@@ -146,21 +181,27 @@ function suggestionCollector(wordToMatch, options) {
146
181
  includesTies: includeTies,
147
182
  ignoreCase,
148
183
  symbolStopProcessing: symStopProcessing,
184
+ genSuggestionOptions,
149
185
  };
150
186
  return collector;
151
187
  }
152
188
  exports.suggestionCollector = suggestionCollector;
189
+ /**
190
+ * Impersonating a Collector, allows searching for multiple variants on the same word.
191
+ * The collection is still in the original collector.
192
+ * @param collector - collector to impersonate
193
+ * @param word - word to present instead of `collector.word`.
194
+ * @returns a SuggestionCollector
195
+ */
196
+ function impersonateCollector(collector, word) {
197
+ const r = Object.create(collector);
198
+ Object.defineProperty(r, 'word', { value: word, writable: false });
199
+ return r;
200
+ }
201
+ exports.impersonateCollector = impersonateCollector;
153
202
  function isSuggestionResult(s) {
154
203
  const r = s;
155
204
  return (r === null || r === void 0 ? void 0 : r.cost) !== undefined && r.word != undefined;
156
205
  }
157
206
  exports.isSuggestionResult = isSuggestionResult;
158
- /**
159
- *
160
- * @param text verbatim text to be inserted into a regexp
161
- * @returns text that can be used in a regexp.
162
- */
163
- function regexQuote(text) {
164
- return text.replace(/[[\]\-+(){},|*.\\]/g, '\\$1');
165
- }
166
207
  //# sourceMappingURL=suggestCollector.js.map
@@ -0,0 +1,22 @@
1
+ import { TrieRoot } from '../../TrieNode';
2
+ import { CompoundWordsMethod, YieldResult } from './walkerTypes';
3
+ /**
4
+ * Ask for the next result.
5
+ * goDeeper of true tells the walker to go deeper in the Trie if possible. Default is true.
6
+ * This can be used to limit the walker's depth.
7
+ */
8
+ export declare type HintedWalkerIterator = Generator<YieldResult, void, Hinting | undefined>;
9
+ export declare function hintedWalker(root: TrieRoot, ignoreCase: boolean, hint: string, compoundingMethod: CompoundWordsMethod | undefined, emitWordSeparator?: string): HintedWalkerIterator;
10
+ /**
11
+ * Walks the Trie and yields a value at each node.
12
+ * next(goDeeper: boolean):
13
+ */
14
+ declare function hintedWalkerNext(root: TrieRoot, ignoreCase: boolean, hint: string, compoundingMethod: CompoundWordsMethod | undefined, emitWordSeparator?: string): HintedWalkerIterator;
15
+ export interface Hinting {
16
+ goDeeper: boolean;
17
+ }
18
+ export declare const __testing__: {
19
+ hintedWalkerNext: typeof hintedWalkerNext;
20
+ };
21
+ export {};
22
+ //# sourceMappingURL=hintedWalker.d.ts.map
@@ -0,0 +1,109 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.__testing__ = exports.hintedWalker = void 0;
4
+ const trie_util_1 = require("../../trie-util");
5
+ const walkerTypes_1 = require("./walkerTypes");
6
+ function hintedWalker(root, ignoreCase, hint, compoundingMethod, emitWordSeparator) {
7
+ return hintedWalkerNext(root, ignoreCase, hint, compoundingMethod, emitWordSeparator);
8
+ }
9
+ exports.hintedWalker = hintedWalker;
10
+ /**
11
+ * Walks the Trie and yields a value at each node.
12
+ * next(goDeeper: boolean):
13
+ */
14
+ function* hintedWalkerNext(root, ignoreCase, hint, compoundingMethod, emitWordSeparator = '') {
15
+ const _compoundingMethod = compoundingMethod !== null && compoundingMethod !== void 0 ? compoundingMethod : walkerTypes_1.CompoundWordsMethod.NONE;
16
+ const compoundCharacter = root.compoundCharacter;
17
+ const noCaseCharacter = root.stripCaseAndAccentsPrefix;
18
+ const rawRoots = [root, ignoreCase ? root.c.get(noCaseCharacter) : undefined].filter(trie_util_1.isDefined);
19
+ const specialRootsPrefix = existMap([compoundCharacter, noCaseCharacter, root.forbiddenWordPrefix]);
20
+ function filterRoot(root) {
21
+ var _a;
22
+ const children = (_a = root.c) === null || _a === void 0 ? void 0 : _a.entries();
23
+ const c = children && [...children].filter(([v]) => !(v in specialRootsPrefix));
24
+ return {
25
+ c: c && new Map(c),
26
+ };
27
+ }
28
+ const roots = rawRoots.map(filterRoot);
29
+ const compoundRoots = rawRoots.map((r) => { var _a; return (_a = r.c) === null || _a === void 0 ? void 0 : _a.get(compoundCharacter); }).filter(trie_util_1.isDefined);
30
+ const setOfCompoundRoots = new Set(compoundRoots);
31
+ const rootsForCompoundMethods = roots.concat(compoundRoots);
32
+ const compoundMethodRoots = {
33
+ [walkerTypes_1.CompoundWordsMethod.NONE]: [],
34
+ [walkerTypes_1.CompoundWordsMethod.JOIN_WORDS]: [...rootsForCompoundMethods.map((r) => [walkerTypes_1.JOIN_SEPARATOR, r])],
35
+ [walkerTypes_1.CompoundWordsMethod.SEPARATE_WORDS]: [...rootsForCompoundMethods.map((r) => [walkerTypes_1.WORD_SEPARATOR, r])],
36
+ };
37
+ function* children(n, hintOffset) {
38
+ if (n.c) {
39
+ const h = hint.slice(hintOffset, hintOffset + 3) + hint.slice(Math.max(0, hintOffset - 2), hintOffset);
40
+ const hints = new Set(h);
41
+ const c = n.c;
42
+ // First yield the hints
43
+ yield* [...hints]
44
+ .filter((a) => c.has(a))
45
+ .map((letter) => ({
46
+ letter,
47
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
48
+ node: c.get(letter),
49
+ hintOffset: hintOffset + 1,
50
+ }));
51
+ // We don't want to suggest the compound character.
52
+ hints.add(compoundCharacter);
53
+ // Then yield everything else.
54
+ yield* [...c]
55
+ .filter((a) => !hints.has(a[0]))
56
+ .map(([letter, node]) => ({
57
+ letter,
58
+ node,
59
+ hintOffset: hintOffset + 1,
60
+ }));
61
+ if (c.has(compoundCharacter) && !setOfCompoundRoots.has(n)) {
62
+ for (const compoundRoot of compoundRoots) {
63
+ for (const child of children(compoundRoot, hintOffset)) {
64
+ const { letter, node, hintOffset } = child;
65
+ yield { letter: emitWordSeparator + letter, node, hintOffset };
66
+ }
67
+ }
68
+ }
69
+ }
70
+ if (n.f) {
71
+ yield* [...compoundMethodRoots[_compoundingMethod]].map(([letter, node]) => ({
72
+ letter: letter,
73
+ node,
74
+ hintOffset,
75
+ }));
76
+ }
77
+ }
78
+ for (const root of roots) {
79
+ let depth = 0;
80
+ const stack = [];
81
+ const stackText = [''];
82
+ stack[depth] = children(root, depth);
83
+ let ir;
84
+ while (depth >= 0) {
85
+ while (!(ir = stack[depth].next()).done) {
86
+ const { letter: char, node, hintOffset } = ir.value;
87
+ const text = stackText[depth] + char;
88
+ const hinting = (yield { text, node, depth });
89
+ if (hinting && hinting.goDeeper) {
90
+ depth++;
91
+ stackText[depth] = text;
92
+ stack[depth] = children(node, hintOffset);
93
+ }
94
+ }
95
+ depth -= 1;
96
+ }
97
+ }
98
+ }
99
+ function existMap(values) {
100
+ const m = Object.create(null);
101
+ for (const v of values) {
102
+ m[v] = true;
103
+ }
104
+ return m;
105
+ }
106
+ exports.__testing__ = {
107
+ hintedWalkerNext,
108
+ };
109
+ //# sourceMappingURL=hintedWalker.js.map
@@ -0,0 +1,5 @@
1
+ export * from './walker';
2
+ export { hintedWalker } from './hintedWalker';
3
+ export type { HintedWalkerIterator, Hinting } from './hintedWalker';
4
+ export * from './walkerTypes';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
5
+ }) : (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ o[k2] = m[k];
8
+ }));
9
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
10
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
11
+ };
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.hintedWalker = void 0;
14
+ __exportStar(require("./walker"), exports);
15
+ var hintedWalker_1 = require("./hintedWalker");
16
+ Object.defineProperty(exports, "hintedWalker", { enumerable: true, get: function () { return hintedWalker_1.hintedWalker; } });
17
+ __exportStar(require("./walkerTypes"), exports);
18
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,8 @@
1
+ import { TrieNode } from '../../TrieNode';
2
+ import { CompoundWordsMethod, WalkerIterator } from './walkerTypes';
3
+ /**
4
+ * Walks the Trie and yields a value at each node.
5
+ * next(goDeeper: boolean):
6
+ */
7
+ export declare function walker(root: TrieNode, compoundingMethod?: CompoundWordsMethod): WalkerIterator;
8
+ //# sourceMappingURL=walker.d.ts.map
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.walker = void 0;
4
+ const walkerTypes_1 = require("./walkerTypes");
5
+ /**
6
+ * Walks the Trie and yields a value at each node.
7
+ * next(goDeeper: boolean):
8
+ */
9
+ function* walker(root, compoundingMethod = walkerTypes_1.CompoundWordsMethod.NONE) {
10
+ const roots = {
11
+ [walkerTypes_1.CompoundWordsMethod.NONE]: [],
12
+ [walkerTypes_1.CompoundWordsMethod.JOIN_WORDS]: [[walkerTypes_1.JOIN_SEPARATOR, root]],
13
+ [walkerTypes_1.CompoundWordsMethod.SEPARATE_WORDS]: [[walkerTypes_1.WORD_SEPARATOR, root]],
14
+ };
15
+ function* children(n) {
16
+ if (n.c) {
17
+ yield* n.c;
18
+ }
19
+ if (n.f) {
20
+ yield* roots[compoundingMethod];
21
+ }
22
+ }
23
+ let depth = 0;
24
+ const stack = [];
25
+ stack[depth] = { t: '', c: children(root) };
26
+ let ir;
27
+ while (depth >= 0) {
28
+ let baseText = stack[depth].t;
29
+ while (!(ir = stack[depth].c.next()).done) {
30
+ const [char, node] = ir.value;
31
+ const text = baseText + char;
32
+ const goDeeper = yield { text, node, depth };
33
+ if (goDeeper || goDeeper === undefined) {
34
+ depth++;
35
+ baseText = text;
36
+ stack[depth] = { t: text, c: children(node) };
37
+ }
38
+ }
39
+ depth -= 1;
40
+ }
41
+ }
42
+ exports.walker = walker;
43
+ //# sourceMappingURL=walker.js.map
@@ -0,0 +1,24 @@
1
+ import { TrieNode } from '../../TrieNode';
2
+ export declare const JOIN_SEPARATOR = "+";
3
+ export declare const WORD_SEPARATOR = " ";
4
+ export interface YieldResult {
5
+ text: string;
6
+ node: TrieNode;
7
+ depth: number;
8
+ }
9
+ export declare enum CompoundWordsMethod {
10
+ /**
11
+ * Do not compound words.
12
+ */
13
+ NONE = 0,
14
+ /**
15
+ * Create word compounds separated by spaces.
16
+ */
17
+ SEPARATE_WORDS = 1,
18
+ /**
19
+ * Create word compounds without separation.
20
+ */
21
+ JOIN_WORDS = 2
22
+ }
23
+ export declare type WalkerIterator = Generator<YieldResult, void, boolean | undefined>;
24
+ //# sourceMappingURL=walkerTypes.d.ts.map
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CompoundWordsMethod = exports.WORD_SEPARATOR = exports.JOIN_SEPARATOR = void 0;
4
+ exports.JOIN_SEPARATOR = '+';
5
+ exports.WORD_SEPARATOR = ' ';
6
+ var CompoundWordsMethod;
7
+ (function (CompoundWordsMethod) {
8
+ /**
9
+ * Do not compound words.
10
+ */
11
+ CompoundWordsMethod[CompoundWordsMethod["NONE"] = 0] = "NONE";
12
+ /**
13
+ * Create word compounds separated by spaces.
14
+ */
15
+ CompoundWordsMethod[CompoundWordsMethod["SEPARATE_WORDS"] = 1] = "SEPARATE_WORDS";
16
+ /**
17
+ * Create word compounds without separation.
18
+ */
19
+ CompoundWordsMethod[CompoundWordsMethod["JOIN_WORDS"] = 2] = "JOIN_WORDS";
20
+ })(CompoundWordsMethod = exports.CompoundWordsMethod || (exports.CompoundWordsMethod = {}));
21
+ //# sourceMappingURL=walkerTypes.js.map
@@ -171,11 +171,10 @@ exports.isCircular = isCircular;
171
171
  */
172
172
  function mergeDefaults(value, defaultValue) {
173
173
  const result = { ...defaultValue };
174
- const allowedKeys = new Set(Object.keys(defaultValue));
175
174
  if (value) {
176
175
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
177
176
  for (const [k, v] of Object.entries(value)) {
178
- if (allowedKeys.has(k)) {
177
+ if (k in result) {
179
178
  result[k] = v !== null && v !== void 0 ? v : result[k];
180
179
  }
181
180
  }
@@ -1,7 +1,7 @@
1
1
  import { Sequence } from 'gensequence';
2
2
  import { FindFullResult } from './find';
3
- import { SuggestionOptions } from './genSuggestionsOptions';
4
3
  import { SuggestionCollector, SuggestionResult } from './suggestCollector';
4
+ import { SuggestionOptions } from './suggestions/genSuggestionsOptions';
5
5
  import { PartialTrieOptions, TrieNode, TrieOptions, TrieRoot } from './TrieNode';
6
6
  import { CompoundWordsMethod, WalkerIterator } from './walker';
7
7
  export { CASE_INSENSITIVE_PREFIX, COMPOUND_FIX, defaultTrieOptions, FORBID_PREFIX, OPTIONAL_COMPOUND_FIX, } from './constants';
package/dist/lib/trie.js CHANGED
@@ -6,6 +6,7 @@ const constants_1 = require("./constants");
6
6
  const find_1 = require("./find");
7
7
  const suggest_1 = require("./suggest");
8
8
  const trie_util_1 = require("./trie-util");
9
+ const util_1 = require("./utils/util");
9
10
  const walker_1 = require("./walker");
10
11
  var constants_2 = require("./constants");
11
12
  Object.defineProperty(exports, "CASE_INSENSITIVE_PREFIX", { enumerable: true, get: function () { return constants_2.CASE_INSENSITIVE_PREFIX; } });
@@ -142,10 +143,15 @@ class Trie {
142
143
  * The results include the word and adjusted edit cost. This is useful for merging results from multiple tries.
143
144
  */
144
145
  suggestWithCost(text, options) {
146
+ const sep = options.compoundSeparator;
147
+ const adjWord = sep ? (0, util_1.replaceAllFactory)(sep, '') : (a) => a;
145
148
  const optFilter = options.filter;
146
149
  const filter = optFilter
147
- ? (word, cost) => !this.isForbiddenWord(word) && optFilter(word, cost)
148
- : (word) => !this.isForbiddenWord(word);
150
+ ? (word, cost) => {
151
+ const w = adjWord(word);
152
+ return !this.isForbiddenWord(w) && optFilter(w, cost);
153
+ }
154
+ : (word) => !this.isForbiddenWord(adjWord(word));
149
155
  const opts = { ...options, filter };
150
156
  return (0, suggest_1.suggest)(this.root, text, opts);
151
157
  }
@@ -156,8 +162,8 @@ class Trie {
156
162
  */
157
163
  genSuggestions(collector, compoundMethod) {
158
164
  const filter = (word) => !this.isForbiddenWord(word);
159
- const { changeLimit, ignoreCase } = collector;
160
- const suggestions = (0, suggest_1.genSuggestions)(this.root, collector.word, (0, trie_util_1.clean)({ compoundMethod, changeLimit, ignoreCase }));
165
+ const options = (0, trie_util_1.clean)({ compoundMethod, ...collector.genSuggestionOptions });
166
+ const suggestions = (0, suggest_1.genSuggestions)(this.root, collector.word, options);
161
167
  collector.collect(suggestions, undefined, filter);
162
168
  }
163
169
  /**
@@ -52,9 +52,18 @@ export declare type NoUndefined<T> = {
52
52
  export declare type OnlyOptionalOrUndefined<T> = {
53
53
  [P in keyof T as P extends OptionalOrUndefinedKeys<T> ? P : never]: T[P];
54
54
  };
55
+ /**
56
+ * Make fields that can be `undefined` optional
57
+ */
55
58
  export declare type MakeOptional<T> = OnlyRequired<T> & Partial<OnlyOptionalOrUndefined<T>>;
59
+ /**
60
+ * Like Required, but keeps the Optional.
61
+ */
56
62
  export declare type RemoveUndefined<T> = {
57
63
  [P in keyof T]: Exclude<T[P], undefined>;
58
64
  };
65
+ /**
66
+ * Make all `undefined` optional and removes the `undefined`
67
+ */
59
68
  export declare type UndefinedToOptional<T> = RemoveUndefined<MakeOptional<T>>;
60
69
  //# sourceMappingURL=types.d.ts.map
@@ -15,4 +15,17 @@ export declare function cleanCopy<T, U = UndefinedToOptional<T>>(t: T): U;
15
15
  export declare function clean<T, U = UndefinedToOptional<T>>(t: T): U;
16
16
  export declare function unique<T>(a: Iterable<T>): T[];
17
17
  export declare function flatten<T>(i: Iterable<Iterable<T>>): Iterable<T>;
18
+ export declare function replaceAll(text: string, match: string, withText: string): string;
19
+ /**
20
+ *
21
+ * @param text verbatim text to be inserted into a regexp
22
+ * @returns text that can be used in a regexp.
23
+ */
24
+ export declare function regexQuote(text: string): string;
25
+ /**
26
+ * Factory to create a function that will replace all occurrences of `match` with `withText`
27
+ * @param match - string to match
28
+ * @param replaceWithText - the text to substitute.
29
+ */
30
+ export declare function replaceAllFactory(match: string, replaceWithText: string): (text: string) => string;
18
31
  //# sourceMappingURL=util.d.ts.map
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.flatten = exports.unique = exports.clean = exports.cleanCopy = exports.isDefined = void 0;
3
+ exports.replaceAllFactory = exports.regexQuote = exports.replaceAll = exports.flatten = exports.unique = exports.clean = exports.cleanCopy = exports.isDefined = void 0;
4
4
  function isDefined(a) {
5
5
  return a !== undefined;
6
6
  }
@@ -40,4 +40,28 @@ function* flatten(i) {
40
40
  }
41
41
  }
42
42
  exports.flatten = flatten;
43
+ function replaceAll(text, match, withText) {
44
+ const fn = replaceAllFactory(match, withText);
45
+ return fn(text);
46
+ }
47
+ exports.replaceAll = replaceAll;
48
+ /**
49
+ *
50
+ * @param text verbatim text to be inserted into a regexp
51
+ * @returns text that can be used in a regexp.
52
+ */
53
+ function regexQuote(text) {
54
+ return text.replace(/([[\]\-+(){},|*.\\])/g, '\\$1');
55
+ }
56
+ exports.regexQuote = regexQuote;
57
+ /**
58
+ * Factory to create a function that will replace all occurrences of `match` with `withText`
59
+ * @param match - string to match
60
+ * @param replaceWithText - the text to substitute.
61
+ */
62
+ function replaceAllFactory(match, replaceWithText) {
63
+ const r = RegExp(regexQuote(match), 'g');
64
+ return (text) => text.replace(r, replaceWithText);
65
+ }
66
+ exports.replaceAllFactory = replaceAllFactory;
43
67
  //# sourceMappingURL=util.js.map
@@ -1,43 +1,2 @@
1
- import { TrieNode, TrieRoot } from './TrieNode';
2
- export declare const JOIN_SEPARATOR = "+";
3
- export declare const WORD_SEPARATOR = " ";
4
- export interface YieldResult {
5
- text: string;
6
- node: TrieNode;
7
- depth: number;
8
- }
9
- export declare enum CompoundWordsMethod {
10
- /**
11
- * Do not compound words.
12
- */
13
- NONE = 0,
14
- /**
15
- * Create word compounds separated by spaces.
16
- */
17
- SEPARATE_WORDS = 1,
18
- /**
19
- * Create word compounds without separation.
20
- */
21
- JOIN_WORDS = 2
22
- }
23
- export declare type WalkerIterator = Generator<YieldResult, void, boolean | undefined>;
24
- /**
25
- * Walks the Trie and yields a value at each node.
26
- * next(goDeeper: boolean):
27
- */
28
- export declare function walker(root: TrieNode, compoundingMethod?: CompoundWordsMethod): WalkerIterator;
29
- export interface Hinting {
30
- goDeeper: boolean;
31
- }
32
- /**
33
- * Ask for the next result.
34
- * goDeeper of true tells the walker to go deeper in the Trie if possible. Default is true.
35
- * This can be used to limit the walker's depth.
36
- */
37
- export declare type HintedWalkerIterator = Generator<YieldResult, void, Hinting | undefined>;
38
- /**
39
- * Walks the Trie and yields a value at each node.
40
- * next(goDeeper: boolean):
41
- */
42
- export declare function hintedWalker(root: TrieRoot, ignoreCase: boolean, hint: string, compoundingMethod: CompoundWordsMethod | undefined): HintedWalkerIterator;
1
+ export * from './suggestions/walker/index';
43
2
  //# sourceMappingURL=walker.d.ts.map
@@ -1,154 +1,14 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
5
+ }) : (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ o[k2] = m[k];
8
+ }));
9
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
10
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
11
+ };
2
12
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.hintedWalker = exports.walker = exports.CompoundWordsMethod = exports.WORD_SEPARATOR = exports.JOIN_SEPARATOR = void 0;
4
- const trie_util_1 = require("./trie-util");
5
- exports.JOIN_SEPARATOR = '+';
6
- exports.WORD_SEPARATOR = ' ';
7
- var CompoundWordsMethod;
8
- (function (CompoundWordsMethod) {
9
- /**
10
- * Do not compound words.
11
- */
12
- CompoundWordsMethod[CompoundWordsMethod["NONE"] = 0] = "NONE";
13
- /**
14
- * Create word compounds separated by spaces.
15
- */
16
- CompoundWordsMethod[CompoundWordsMethod["SEPARATE_WORDS"] = 1] = "SEPARATE_WORDS";
17
- /**
18
- * Create word compounds without separation.
19
- */
20
- CompoundWordsMethod[CompoundWordsMethod["JOIN_WORDS"] = 2] = "JOIN_WORDS";
21
- })(CompoundWordsMethod = exports.CompoundWordsMethod || (exports.CompoundWordsMethod = {}));
22
- /**
23
- * Walks the Trie and yields a value at each node.
24
- * next(goDeeper: boolean):
25
- */
26
- function* walker(root, compoundingMethod = CompoundWordsMethod.NONE) {
27
- const roots = {
28
- [CompoundWordsMethod.NONE]: [],
29
- [CompoundWordsMethod.JOIN_WORDS]: [[exports.JOIN_SEPARATOR, root]],
30
- [CompoundWordsMethod.SEPARATE_WORDS]: [[exports.WORD_SEPARATOR, root]],
31
- };
32
- function* children(n) {
33
- if (n.c) {
34
- yield* n.c;
35
- }
36
- if (n.f) {
37
- yield* roots[compoundingMethod];
38
- }
39
- }
40
- let depth = 0;
41
- const stack = [];
42
- stack[depth] = { t: '', c: children(root) };
43
- let ir;
44
- while (depth >= 0) {
45
- let baseText = stack[depth].t;
46
- while (!(ir = stack[depth].c.next()).done) {
47
- const [char, node] = ir.value;
48
- const text = baseText + char;
49
- const goDeeper = yield { text, node, depth };
50
- if (goDeeper || goDeeper === undefined) {
51
- depth++;
52
- baseText = text;
53
- stack[depth] = { t: text, c: children(node) };
54
- }
55
- }
56
- depth -= 1;
57
- }
58
- }
59
- exports.walker = walker;
60
- /**
61
- * Walks the Trie and yields a value at each node.
62
- * next(goDeeper: boolean):
63
- */
64
- function* hintedWalker(root, ignoreCase, hint, compoundingMethod) {
65
- const _compoundingMethod = compoundingMethod !== null && compoundingMethod !== void 0 ? compoundingMethod : CompoundWordsMethod.NONE;
66
- const compoundCharacter = root.compoundCharacter;
67
- const noCaseCharacter = root.stripCaseAndAccentsPrefix;
68
- const rawRoots = [root, ignoreCase ? root.c.get(noCaseCharacter) : undefined].filter(trie_util_1.isDefined);
69
- const specialRootsPrefix = existMap([compoundCharacter, noCaseCharacter, root.forbiddenWordPrefix]);
70
- function filterRoot(root) {
71
- var _a;
72
- const children = (_a = root.c) === null || _a === void 0 ? void 0 : _a.entries();
73
- const c = children && [...children].filter(([v]) => !(v in specialRootsPrefix));
74
- return {
75
- c: c && new Map(c),
76
- };
77
- }
78
- const roots = rawRoots.map(filterRoot);
79
- const compoundRoots = rawRoots.map((r) => { var _a; return (_a = r.c) === null || _a === void 0 ? void 0 : _a.get(compoundCharacter); }).filter(trie_util_1.isDefined);
80
- const rootsForCompoundMethods = roots.concat(compoundRoots);
81
- const compoundMethodRoots = {
82
- [CompoundWordsMethod.NONE]: [],
83
- [CompoundWordsMethod.JOIN_WORDS]: [...rootsForCompoundMethods.map((r) => [exports.JOIN_SEPARATOR, r])],
84
- [CompoundWordsMethod.SEPARATE_WORDS]: [...rootsForCompoundMethods.map((r) => [exports.WORD_SEPARATOR, r])],
85
- };
86
- function* children(n, hintOffset) {
87
- if (n.c) {
88
- const h = hint.slice(hintOffset, hintOffset + 3) + hint.slice(Math.max(0, hintOffset - 2), hintOffset);
89
- const hints = new Set(h);
90
- const c = n.c;
91
- // First yield the hints
92
- yield* [...hints]
93
- .filter((a) => c.has(a))
94
- .map((letter) => ({
95
- letter,
96
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
97
- node: c.get(letter),
98
- hintOffset: hintOffset + 1,
99
- }));
100
- // We don't want to suggest the compound character.
101
- hints.add(compoundCharacter);
102
- // Then yield everything else.
103
- yield* [...c]
104
- .filter((a) => !hints.has(a[0]))
105
- .map(([letter, node]) => ({
106
- letter,
107
- node,
108
- hintOffset: hintOffset + 1,
109
- }));
110
- if (c.has(compoundCharacter)) {
111
- for (const compoundRoot of compoundRoots) {
112
- yield* children(compoundRoot, hintOffset);
113
- }
114
- }
115
- }
116
- if (n.f) {
117
- yield* [...compoundMethodRoots[_compoundingMethod]].map(([letter, node]) => ({
118
- letter,
119
- node,
120
- hintOffset,
121
- }));
122
- }
123
- }
124
- for (const root of roots) {
125
- let depth = 0;
126
- const stack = [];
127
- let baseText = '';
128
- stack[depth] = children(root, depth);
129
- let ir;
130
- while (depth >= 0) {
131
- while (!(ir = stack[depth].next()).done) {
132
- const { letter: char, node, hintOffset } = ir.value;
133
- const text = baseText + char;
134
- const hinting = (yield { text, node, depth });
135
- if (hinting && hinting.goDeeper) {
136
- depth++;
137
- baseText = text;
138
- stack[depth] = children(node, hintOffset);
139
- }
140
- }
141
- depth -= 1;
142
- baseText = baseText.slice(0, -1);
143
- }
144
- }
145
- }
146
- exports.hintedWalker = hintedWalker;
147
- function existMap(values) {
148
- const m = Object.create(null);
149
- for (const v of values) {
150
- m[v] = true;
151
- }
152
- return m;
153
- }
13
+ __exportStar(require("./suggestions/walker/index"), exports);
154
14
  //# sourceMappingURL=walker.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cspell-trie-lib",
3
- "version": "5.18.0-alpha.0",
3
+ "version": "5.18.3",
4
4
  "description": "Trie Data Structure to support cspell.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -37,7 +37,7 @@
37
37
  },
38
38
  "homepage": "https://github.com/streetsidesoftware/cspell#readme",
39
39
  "dependencies": {
40
- "@cspell/cspell-pipe": "^5.18.0-alpha.0",
40
+ "@cspell/cspell-pipe": "^5.18.3",
41
41
  "fs-extra": "^10.0.0",
42
42
  "gensequence": "^3.1.1"
43
43
  },
@@ -45,13 +45,13 @@
45
45
  "node": ">=12.13.0"
46
46
  },
47
47
  "devDependencies": {
48
- "@cspell/cspell-types": "^5.18.0-alpha.0",
49
- "@cspell/dict-en_us": "^2.1.4",
48
+ "@cspell/cspell-types": "^5.18.3",
49
+ "@cspell/dict-en_us": "^2.1.5",
50
50
  "@cspell/dict-es-es": "^2.1.0",
51
51
  "@types/fs-extra": "^9.0.13",
52
- "@types/node": "^17.0.13",
52
+ "@types/node": "^17.0.14",
53
53
  "jest": "^27.4.7",
54
54
  "rimraf": "^3.0.2"
55
55
  },
56
- "gitHead": "d3c6f34444f19e9d8e375d1cbea6f99d0f270716"
56
+ "gitHead": "c650c8d0d58fc0398a6f745a0ad48d46f982332f"
57
57
  }