Refactor to use buildSuggestionAdvice
MODIFY
packages/@romejs/consume/Consumer.ts
packages/@romejs/consume/Consumer.ts
@@ -13,8 +13,8 @@ import {
DiagnosticPointer,
getDiagnosticsFromError,
DiagnosticCategory,
+ buildSuggestionAdvice,
} from '@romejs/diagnostics';
-import {suggestClosest} from '@romejs/suggest';
import {UnknownObject} from '@romejs/typescript-helpers';
import {
JSONValue,
@@ -533,21 +533,15 @@ export default class Consumer {
for (const [key, value] of this.asMap(false, false)) {
if (!this.usedNames.has(key)) {
- const suggestion = suggestClosest(key, knownProperties);
-
value.unexpected(`Unknown <emphasis>${key}</emphasis> ${type}`, {
target: 'key',
at: 'suffix',
atParent: true,
- advice: suggestion
- ? [
- {
- type: 'log',
- category: 'info',
- message: `Did you mean <emphasis>${suggestion}</emphasis>?`,
- },
- ]
- : undefined,
+ advice: buildSuggestionAdvice({
+ value: key,
+ items: knownProperties,
+ ignoreCase: true,
+ }),
});
}

MODIFY
packages/@romejs/diagnostics/helpers.ts
packages/@romejs/diagnostics/helpers.ts
@@ -12,15 +12,29 @@ import {Position} from '@romejs/parser-core';
import {get1} from '@romejs/ob1';
import {NEWLINE} from '@romejs/js-parser-utils';
-export function buildSuggestionAdvice(
- value: string,
- items: Array<string>,
- minRating: number = 0.8,
- formatItem?: (item: string) => string,
-): PartialDiagnosticAdvice {
+type BuildSuggestionAdviceOptions = {
+ value: string;
+ items: Array<string>;
+ minRating?: number;
+ ignoreCase?: boolean;
+ formatItem?: (item: string) => string;
+};
+export function buildSuggestionAdvice({
+ value,
+ items,
+ minRating = 0.5,
+ ignoreCase,
+ formatItem,
+}: BuildSuggestionAdviceOptions): PartialDiagnosticAdvice {
const advice: PartialDiagnosticAdvice = [];
- const ratings = orderBySimilarity(value, items, minRating);
+ const ratings = orderBySimilarity(
+ value,
+ items,
+ minRating,
+ formatItem,
+ ignoreCase,
+ );
const strings = ratings.map(item => {
const {target} = item;

MODIFY
packages/@romejs/string-utils/orderBySimilarity.ts
packages/@romejs/string-utils/orderBySimilarity.ts
@@ -101,6 +101,7 @@ export function orderBySimilarity(
targets: Array<string>,
minRating?: number,
strMap?: (str: string) => string,
+ ignoreCase?: boolean = false,
): Ratings {
if (targets.length === 0) {
return [];
@@ -115,6 +116,16 @@ export function orderBySimilarity(
compareTarget = strMap(target);
}
+ if (ignoreCase) {
+ return {
+ target,
+ rating: compareTwoStrings(
+ compareStr.toLowerCase(),
+ compareTarget.toLowerCase(),
+ ),
+ };
+ }
+
return {
target,
rating: compareTwoStrings(compareStr, compareTarget),

DELETE
packages/@romejs/suggest/index.test.ts
-import {suggestClosest} from '@romejs/suggest';
-import test from '@romejs/test';
-
-test('should suggest test', t => {
- const result = suggestClosest('tst', ['lint', 'ci', 'test', 'bundle']);
-
- t.is(result, 'test');
-});
-
-test('should suggest nothing', t => {
- const result = suggestClosest('not even close', [
- 'lint',
- 'ci',
- 'test',
- 'bundle',
- ]);
-
- t.is(result, undefined);
-});

DELETE
packages/@romejs/suggest/index.ts
-import leven from './leven';
-
-// Arbitrary threshold all suggestions must hit
-// A lower number means higher quality suggestions but
-// will be less likley to find a suggestion
-const threshold = 2;
-
-export function suggestClosest(
- text: string,
- suggestions: Array<string>,
-): string | undefined {
- let current;
- let currentScore = threshold;
-
- for (const suggestion of suggestions) {
- const score = leven(text, suggestion);
-
- if (score <= currentScore) {
- currentScore = currentScore;
- current = suggestion;
- }
- }
-
- return current;
-}

DELETE
packages/@romejs/suggest/leven.ts
-// Original source: https://github.com/sindresorhus/leven/blob/master/index.js
-
-const charCodeCache: Array<number> = [];
-const array: Array<number> = [];
-
-export default (left: string, right: string): number => {
- if (left === right) {
- return 0;
- }
-
- const swap = left;
-
- // Swapping the strings if `a` is longer than `b` so we know which one is the
- // shortest & which one is the longest
- if (left.length > right.length) {
- left = right;
- right = swap;
- }
-
- let leftLength = left.length;
- let rightLength = right.length;
-
- // Performing suffix trimming:
- // We can linearly drop suffix common to both strings since they
- // don't increase distance at all
- // Note: `~-` is the bitwise way to perform a `- 1` operation
- while (
- leftLength > 0 &&
- left.charCodeAt(~-leftLength) === right.charCodeAt(~-rightLength)
- ) {
- leftLength--;
- rightLength--;
- }
-
- // Performing prefix trimming
- // We can linearly drop prefix common to both strings since they
- // don't increase distance at all
- let start = 0;
-
- while (
- start < leftLength &&
- left.charCodeAt(start) === right.charCodeAt(start)
- ) {
- start++;
- }
-
- leftLength -= start;
- rightLength -= start;
-
- if (leftLength === 0) {
- return rightLength;
- }
-
- let bCharCode;
- let result;
- let temp;
- let temp2;
- let i = 0;
- let j = 0;
-
- while (i < leftLength) {
- charCodeCache[i] = left.charCodeAt(start + i);
- array[i] = ++i;
- }
-
- while (j < rightLength) {
- bCharCode = right.charCodeAt(start + j);
- temp = j++;
- result = j;
-
- for (i = 0; i < leftLength; i++) {
- temp2 = bCharCode === charCodeCache[i] ? temp : temp + 1;
- temp = array[i];
-
- result = array[i] =
- temp > result
- ? temp2 > result
- ? result + 1
- : temp2
- : temp2 > temp
- ? temp + 1
- : temp2;
- }
- }
-
- return result as number;
-};

DELETE
packages/@romejs/suggest/package.json
-{
- "name": "@romejs/suggest",
- "private": true,
- "type": "module",
- "main": "index.ts",
- "version": "0.0.0"
-}

Refactor to use buildSuggestionAdvice