Skip to content

Commit

Permalink
refactor: refactor type definitions for suggestion edit maps (#2258)
Browse files Browse the repository at this point in the history
  • Loading branch information
Jason3S committed Jan 16, 2022
1 parent 7a5084a commit 60d5c5e
Show file tree
Hide file tree
Showing 15 changed files with 492 additions and 89 deletions.
122 changes: 122 additions & 0 deletions cspell.schema.json
Expand Up @@ -30,6 +30,96 @@
],
"type": "string"
},
"CostMapDefInsDel": {
"additionalProperties": false,
"properties": {
"description": {
"description": "A description to describe the purpose of the map.",
"type": "string"
},
"insDel": {
"description": "The cost to insert/delete one of the substrings in the map. Note: insert/delete costs are symmetrical.",
"type": "number"
},
"map": {
"description": "The set of substrings to map, these are generally single character strings.\n\nMultiple sets can be defined by using a `|` to separate them.\n\nExample: `\"eéê|aåá\"` contains two different sets.\n\nTo add a multi-character substring use `()`.\n\nExample: `\"f(ph)(gh)\"` results in the following set: `f`, `ph`, `gh`.",
"type": "string"
},
"replace": {
"description": "The cost to replace of of the substrings in the map with another substring in the map. Example: Map['a', 'i'] This would be the cost to substitute `a` with `i`: Like `bat` to `bit` or the reverse.",
"type": "number"
},
"swap": {
"description": "The cost to swap two adjacent substrings found in the map. Example: Map['e', 'i'] This represents the cost to change `ei` to `ie` or the reverse.",
"type": "number"
}
},
"required": [
"insDel",
"map"
],
"type": "object"
},
"CostMapDefReplace": {
"additionalProperties": false,
"properties": {
"description": {
"description": "A description to describe the purpose of the map.",
"type": "string"
},
"insDel": {
"description": "The cost to insert/delete one of the substrings in the map. Note: insert/delete costs are symmetrical.",
"type": "number"
},
"map": {
"description": "The set of substrings to map, these are generally single character strings.\n\nMultiple sets can be defined by using a `|` to separate them.\n\nExample: `\"eéê|aåá\"` contains two different sets.\n\nTo add a multi-character substring use `()`.\n\nExample: `\"f(ph)(gh)\"` results in the following set: `f`, `ph`, `gh`.",
"type": "string"
},
"replace": {
"description": "The cost to replace of of the substrings in the map with another substring in the map. Example: Map['a', 'i'] This would be the cost to substitute `a` with `i`: Like `bat` to `bit` or the reverse.",
"type": "number"
},
"swap": {
"description": "The cost to swap two adjacent substrings found in the map. Example: Map['e', 'i'] This represents the cost to change `ei` to `ie` or the reverse.",
"type": "number"
}
},
"required": [
"map",
"replace"
],
"type": "object"
},
"CostMapDefSwap": {
"additionalProperties": false,
"properties": {
"description": {
"description": "A description to describe the purpose of the map.",
"type": "string"
},
"insDel": {
"description": "The cost to insert/delete one of the substrings in the map. Note: insert/delete costs are symmetrical.",
"type": "number"
},
"map": {
"description": "The set of substrings to map, these are generally single character strings.\n\nMultiple sets can be defined by using a `|` to separate them.\n\nExample: `\"eéê|aåá\"` contains two different sets.\n\nTo add a multi-character substring use `()`.\n\nExample: `\"f(ph)(gh)\"` results in the following set: `f`, `ph`, `gh`.",
"type": "string"
},
"replace": {
"description": "The cost to replace of of the substrings in the map with another substring in the map. Example: Map['a', 'i'] This would be the cost to substitute `a` with `i`: Like `bat` to `bit` or the reverse.",
"type": "number"
},
"swap": {
"description": "The cost to swap two adjacent substrings found in the map. Example: Map['e', 'i'] This represents the cost to change `ei` to `ie` or the reverse.",
"type": "number"
}
},
"required": [
"map",
"swap"
],
"type": "object"
},
"CustomDictionaryPath": {
"description": "A File System Path to a dictionary file.",
"pattern": "^.*\\.txt$",
Expand Down Expand Up @@ -85,6 +175,10 @@
"$ref": "#/definitions/ReplaceMap",
"description": "Replacement pairs."
},
"suggestionEditCosts": {
"$ref": "#/definitions/SuggestionCostsDefs",
"description": "Used in making suggestions. The lower the value, the more likely the suggestion will be near the top of the suggestion list."
},
"type": {
"$ref": "#/definitions/DictionaryFileTypes",
"default": "S",
Expand Down Expand Up @@ -143,6 +237,10 @@
],
"description": "Defines the scope for when words will be added to the dictionary. Scope values: `user`, `workspace`, `folder`."
},
"suggestionEditCosts": {
"$ref": "#/definitions/SuggestionCostsDefs",
"description": "Used in making suggestions. The lower the value, the more likely the suggestion will be near the top of the suggestion list."
},
"type": {
"$ref": "#/definitions/DictionaryFileTypes",
"default": "S",
Expand Down Expand Up @@ -183,6 +281,10 @@
"$ref": "#/definitions/ReplaceMap",
"description": "Replacement pairs."
},
"suggestionEditCosts": {
"$ref": "#/definitions/SuggestionCostsDefs",
"description": "Used in making suggestions. The lower the value, the more likely the suggestion will be near the top of the suggestion list."
},
"type": {
"$ref": "#/definitions/DictionaryFileTypes",
"default": "S",
Expand Down Expand Up @@ -742,6 +844,26 @@
"description": "Simple Glob string, the root will be globRoot.",
"type": "string"
},
"SuggestionCostMapDef": {
"anyOf": [
{
"$ref": "#/definitions/CostMapDefReplace"
},
{
"$ref": "#/definitions/CostMapDefInsDel"
},
{
"$ref": "#/definitions/CostMapDefSwap"
}
],
"description": "A WeightedMapDef enables setting weights for edits between related characters and substrings.\n\nMultiple groups can be defined using a `|`. A multi-character substring is defined using `()`.\n\nFor example, in some languages, some letters sound alike.\n\n```ts { map: 'sc(sh)(sch)(ss)|t(tt)', // two groups. replace: 50, // Make it 1/2 the cost of a normal edit to replace a `t` with `tt`. } ```\n\nThe following could be used to make inserting, removing, or replacing vowels cheaper. ```ts { map: 'aeiouy', //. insDel: 50, // Make it is cheaper to insert or delete a vowel. replace: 45, // It is even cheaper to replace one with another. } ```\n\nNote: the default edit distance is 100."
},
"SuggestionCostsDefs": {
"items": {
"$ref": "#/definitions/SuggestionCostMapDef"
},
"type": "array"
},
"Version": {
"anyOf": [
{
Expand Down
55 changes: 55 additions & 0 deletions packages/cspell-trie-lib/src/__snapshots__/index.test.ts.snap
@@ -0,0 +1,55 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Validate index.ts Track changes to the API. 1`] = `
Array [
"CASE_INSENSITIVE_PREFIX",
"COMPOUND",
"COMPOUND_FIX",
"ChildMap",
"CompoundWordsMethod",
"FLAG_WORD",
"FORBID",
"FORBID_PREFIX",
"JOIN_SEPARATOR",
"NORMALIZED",
"OPTIONAL_COMPOUND",
"OPTIONAL_COMPOUND_FIX",
"Trie",
"TrieBuilder",
"WORD_SEPARATOR",
"buildTrie",
"buildTrieFast",
"consolidate",
"countNodes",
"countWords",
"createTriFromList",
"createTrieRoot",
"createWeightedMap",
"defaultTrieOptions",
"editDistance",
"editDistanceWeighted",
"findNode",
"has",
"hintedWalker",
"importTrie",
"insert",
"isCircular",
"isDefined",
"isWordTerminationNode",
"iterateTrie",
"iteratorTrieWords",
"mergeDefaults",
"mergeOptionalWithDefaults",
"normalizeWord",
"normalizeWordForCaseInsensitive",
"normalizeWordToLowercase",
"orderTrie",
"parseDictionary",
"parseDictionaryLines",
"serializeTrie",
"suggestionCollector",
"trieNodeToRoot",
"walk",
"walker",
]
`;
5 changes: 4 additions & 1 deletion packages/cspell-trie-lib/src/index.test.ts
@@ -1,7 +1,10 @@
import * as lib from '.';
import * as lib from './index';

describe('Validate index.ts', () => {
test('index', () => {
expect(typeof lib.Trie).toBe('function');
});
test('Track changes to the API.', () => {
expect(Object.keys(lib).sort()).toMatchSnapshot();
});
});
9 changes: 5 additions & 4 deletions packages/cspell-trie-lib/src/lib/distance/distance.ts
@@ -1,9 +1,10 @@
import { distanceAStarWeighted } from './distanceAStarWeighted';
import { levenshteinDistance } from './levenshtein';
import type { WeightedMapDef, WeightedMapTrie } from './weightedMaps';
import type { SuggestionCostMapDef } from './suggestionCostsDef';
import type { WeightedMapTrie } from './weightedMaps';
import { addWeightedDefMapToTrie, buildWeightedMapTrie } from './weightedMaps';

export type { WeightedMapDef } from './weightedMaps';
export type { SuggestionCostMapDef } from './suggestionCostsDef';

const defaultCost = 100;

Expand Down Expand Up @@ -46,7 +47,7 @@ export type WeightedMap = WeightedMapTrie;
* @param defs - list of definitions
* @returns A Weighted Map to be used with distance calculations.
*/
export function createWeightedMap(defs: WeightedMapDef[]): WeightedMap {
export function createWeightedMap(defs: SuggestionCostMapDef[]): WeightedMap {
return buildWeightedMapTrie(defs);
}

Expand All @@ -55,6 +56,6 @@ export function createWeightedMap(defs: WeightedMapDef[]): WeightedMap {
* @param weightedMap - map to update
* @param def - the definition to use
*/
export function updatedWeightedMap(weightedMap: WeightedMap, def: WeightedMapDef): void {
export function updatedWeightedMap(weightedMap: WeightedMap, def: SuggestionCostMapDef): void {
addWeightedDefMapToTrie(def, weightedMap);
}
5 changes: 3 additions & 2 deletions packages/cspell-trie-lib/src/lib/distance/index.ts
@@ -1,2 +1,3 @@
export { editDistance, createWeightedMap, editDistanceWeighted } from './distance';
export type { WeightedMap, WeightedMapDef } from './distance';
export { createWeightedMap, editDistance, editDistanceWeighted } from './distance';
export type { WeightedMap } from './distance';
export type { SuggestionCostMapDef } from './suggestionCostsDef';
73 changes: 73 additions & 0 deletions packages/cspell-trie-lib/src/lib/distance/suggestionCostsDef.ts
@@ -0,0 +1,73 @@
// cspell:ignore aeiouy
/**
* A WeightedMapDef enables setting weights for edits between related characters and substrings.
*
* Multiple groups can be defined using a `|`.
* A multi-character substring is defined using `()`.
*
* For example, in some languages, some letters sound alike.
*
* ```ts
* {
* map: 'sc(sh)(sch)(ss)|t(tt)', // two groups.
* replace: 50, // Make it 1/2 the cost of a normal edit to replace a `t` with `tt`.
* }
* ```
*
* The following could be used to make inserting, removing, or replacing vowels cheaper.
* ```ts
* {
* map: 'aeiouy', //.
* insDel: 50, // Make it is cheaper to insert or delete a vowel.
* replace: 45, // It is even cheaper to replace one with another.
* }
* ```
*
* Note: the default edit distance is 100.
*/
export type SuggestionCostMapDef = CostMapDefReplace | CostMapDefInsDel | CostMapDefSwap;

interface CostMapDefBase {
/**
* The set of substrings to map, these are generally single character strings.
*
* Multiple sets can be defined by using a `|` to separate them.
*
* Example: `"eéê|aåá"` contains two different sets.
*
* To add a multi-character substring use `()`.
*
* Example: `"f(ph)(gh)"` results in the following set: `f`, `ph`, `gh`.
*/
map: string;
/** The cost to insert/delete one of the substrings in the map. Note: insert/delete costs are symmetrical. */
insDel?: number;
/**
* The cost to replace of of the substrings in the map with another substring in the map.
* Example: Map['a', 'i']
* This would be the cost to substitute `a` with `i`: Like `bat` to `bit` or the reverse.
*/
replace?: number;
/**
* The cost to swap two adjacent substrings found in the map.
* Example: Map['e', 'i']
* This represents the cost to change `ei` to `ie` or the reverse.
*/
swap?: number;
/**
* A description to describe the purpose of the map.
*/
description?: string;
}

export interface CostMapDefReplace extends CostMapDefBase {
replace: number;
}

export interface CostMapDefInsDel extends CostMapDefBase {
insDel: number;
}

export interface CostMapDefSwap extends CostMapDefBase {
swap: number;
}
@@ -1,4 +1,5 @@
import { __testing__, addWeightedDefMapToTrie, WeightedMapDef } from './weightedMaps';
import type { SuggestionCostMapDef } from './suggestionCostsDef';
import { addWeightedDefMapToTrie, __testing__ } from './weightedMaps';

const { splitMapSubstrings, splitMap } = __testing__;

Expand Down Expand Up @@ -35,7 +36,7 @@ describe('Validate weightedMaps', () => {
${'ab'} | ${undefined} | ${2} | ${undefined} | ${{ a: { r: { a: { rep: 2 }, b: { rep: 2 } } }, b: { r: { a: { rep: 2 }, b: { rep: 2 } } } }}
${'a|b'} | ${undefined} | ${2} | ${undefined} | ${{ a: { r: { a: { rep: 2 } } }, b: { r: { b: { rep: 2 } } } }}
`('splitMap "$map"', ({ map, insDel, replace, swap, expected }) => {
const def: WeightedMapDef = {
const def: SuggestionCostMapDef = {
map,
insDel,
replace,
Expand Down

0 comments on commit 60d5c5e

Please sign in to comment.