graphql
Version:
A Query Language and Runtime which can target any service.
1 lines • 8 kB
Source Map (JSON)
{"version":3,"file":"suggestionList.js","sourceRoot":"","sources":["../../src/jsutils/suggestionList.ts"],"names":[],"mappings":"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","sourcesContent":["import { naturalCompare } from './naturalCompare.ts';\n\n/**\n * Given an invalid input string and a list of valid options, returns a filtered\n * list of valid options sorted based on their similarity with the input.\n *\n * @internal\n */\nexport function suggestionList(\n input: string,\n options: ReadonlyArray<string>,\n): Array<string> {\n const optionsByDistance = Object.create(null);\n const lexicalDistance = new LexicalDistance(input);\n\n const threshold = Math.floor(input.length * 0.4) + 1;\n for (const option of options) {\n const distance = lexicalDistance.measure(option, threshold);\n if (distance !== undefined) {\n optionsByDistance[option] = distance;\n }\n }\n\n return Object.keys(optionsByDistance).sort((a, b) => {\n const distanceDiff = optionsByDistance[a] - optionsByDistance[b];\n return distanceDiff !== 0 ? distanceDiff : naturalCompare(a, b);\n });\n}\n\n/**\n * Computes the lexical distance between strings A and B.\n *\n * The \"distance\" between two strings is given by counting the minimum number\n * of edits needed to transform string A into string B. An edit can be an\n * insertion, deletion, or substitution of a single character, or a swap of two\n * adjacent characters.\n *\n * Includes a custom alteration from Damerau-Levenshtein to treat case changes\n * as a single edit which helps identify mis-cased values with an edit distance\n * of 1.\n *\n * This distance can be useful for detecting typos in input or sorting\n *\n * @internal\n */\nclass LexicalDistance {\n _input: string;\n _inputLowerCase: string;\n _inputArray: Array<number>;\n _rows: [Array<number>, Array<number>, Array<number>];\n\n constructor(input: string) {\n this._input = input;\n this._inputLowerCase = input.toLowerCase();\n this._inputArray = stringToArray(this._inputLowerCase);\n\n this._rows = [\n new Array(input.length + 1).fill(0),\n new Array(input.length + 1).fill(0),\n new Array(input.length + 1).fill(0),\n ];\n }\n\n measure(option: string, threshold: number): number | undefined {\n if (this._input === option) {\n return 0;\n }\n\n const optionLowerCase = option.toLowerCase();\n\n // Any case change counts as a single edit\n if (this._inputLowerCase === optionLowerCase) {\n return 1;\n }\n\n let a = stringToArray(optionLowerCase);\n let b = this._inputArray;\n\n if (a.length < b.length) {\n const tmp = a;\n a = b;\n b = tmp;\n }\n const aLength = a.length;\n const bLength = b.length;\n\n if (aLength - bLength > threshold) {\n return undefined;\n }\n\n const rows = this._rows;\n for (let j = 0; j <= bLength; j++) {\n rows[0][j] = j;\n }\n\n for (let i = 1; i <= aLength; i++) {\n const upRow = rows[(i - 1) % 3];\n const currentRow = rows[i % 3];\n\n let smallestCell = (currentRow[0] = i);\n for (let j = 1; j <= bLength; j++) {\n const cost = a[i - 1] === b[j - 1] ? 0 : 1;\n\n let currentCell = Math.min(\n upRow[j] + 1, // delete\n currentRow[j - 1] + 1, // insert\n upRow[j - 1] + cost, // substitute\n );\n\n if (i > 1 && j > 1 && a[i - 1] === b[j - 2] && a[i - 2] === b[j - 1]) {\n // transposition\n const doubleDiagonalCell = rows[(i - 2) % 3][j - 2];\n currentCell = Math.min(currentCell, doubleDiagonalCell + 1);\n }\n\n if (currentCell < smallestCell) {\n smallestCell = currentCell;\n }\n\n currentRow[j] = currentCell;\n }\n\n // Early exit, since distance can't go smaller than smallest element of the previous row.\n if (smallestCell > threshold) {\n return undefined;\n }\n }\n\n const distance = rows[aLength % 3][bLength];\n return distance <= threshold ? distance : undefined;\n }\n}\n\nfunction stringToArray(str: string): Array<number> {\n const strLength = str.length;\n const array = new Array(strLength);\n for (let i = 0; i < strLength; ++i) {\n array[i] = str.charCodeAt(i);\n }\n return array;\n}\n"]}