diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index b85fc2a..441975c 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -10,14 +10,10 @@ jobs: fail-fast: false matrix: node-version: - - 14 - - 12 - - 10 - - 8 - - 6 + - 16 steps: - uses: actions/checkout@v2 - - uses: actions/setup-node@v1 + - uses: actions/setup-node@v2 with: node-version: ${{ matrix.node-version }} - run: npm install diff --git a/bench.js b/bench.js index c623c3e..30b9062 100644 --- a/bench.js +++ b/bench.js @@ -1,31 +1,30 @@ /* globals bench suite */ -'use strict'; -const levenshteinEditDistance = require('levenshtein-edit-distance'); -const fastLevenshtein = require('fast-levenshtein').get; -const levenshteinComponent = require('levenshtein-component'); -const ld = require('ld').computeDistance; -const levdist = require('levdist'); -const natural = require('natural').LevenshteinDistance; -const levenshtein = require('levenshtein'); -const talisman = require('talisman/metrics/distance/levenshtein'); -const leven = require('.'); +import levenshteinEditDistance from 'levenshtein-edit-distance'; +import {get as fastLevenshtein} from 'fast-levenshtein'; +import levenshteinComponent from 'levenshtein-component'; +import {computeDistance as ld} from 'ld'; +import levdist from 'levdist'; +import {LevenshteinDistance as natural} from 'natural'; +import levenshtein from 'levenshtein'; +import talisman from 'talisman/metrics/distance/levenshtein'; +import leven from './index.js'; -function run(fn) { - fn('a', 'b'); - fn('ab', 'ac'); - fn('ac', 'bc'); - fn('abc', 'axc'); - fn('kitten', 'sitting'); - fn('xabxcdxxefxgx', '1ab2cd34ef5g6'); - fn('cat', 'cow'); - fn('xabxcdxxefxgx', 'abcdefg'); - fn('javawasneat', 'scalaisgreat'); - fn('example', 'samples'); - fn('sturgeon', 'urgently'); - fn('levenshtein', 'frankenstein'); - fn('distance', 'difference'); - fn('因為我是中國人所以我會說中文', '因為我是英國人所以我會說英文'); - fn('Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim.', 'Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim.'); +function run(function_) { + function_('a', 'b'); + function_('ab', 'ac'); + function_('ac', 'bc'); + function_('abc', 'axc'); + function_('kitten', 'sitting'); + function_('xabxcdxxefxgx', '1ab2cd34ef5g6'); + function_('cat', 'cow'); + function_('xabxcdxxefxgx', 'abcdefg'); + function_('javawasneat', 'scalaisgreat'); + function_('example', 'samples'); + function_('sturgeon', 'urgently'); + function_('levenshtein', 'frankenstein'); + function_('distance', 'difference'); + function_('因為我是中國人所以我會說中文', '因為我是英國人所以我會說英文'); + function_('Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim.', 'Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim.'); } suite('leven', () => { diff --git a/index.d.ts b/index.d.ts index 571833a..391475a 100644 --- a/index.d.ts +++ b/index.d.ts @@ -1,21 +1,12 @@ -declare const leven: { - /** - Measure the difference between two strings. - - @example - ``` - import leven = require('leven'); - - leven('cat', 'cow'); - //=> 2 - ``` - */ - (left: string, right: string): number; - - // TODO: Remove this for the next major release, refactor the whole definition to: - // declare function leven(left: string, right: string): number; - // export = leven; - default: typeof leven; -}; - -export = leven; +/** +Measure the difference between two strings. + +@example +``` +import leven from 'leven'; + +leven('cat', 'cow'); +//=> 2 +``` +*/ +export default function leven(first: string, second: string): number; diff --git a/index.js b/index.js index 25f5a3d..9eaec1f 100644 --- a/index.js +++ b/index.js @@ -1,31 +1,30 @@ -'use strict'; const array = []; -const charCodeCache = []; +const characterCodeCache = []; -const leven = (left, right) => { - if (left === right) { +export default function leven(first, second) { + if (first === second) { return 0; } - const swap = left; + const swap = first; // 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; + if (first.length > second.length) { + first = second; + second = swap; } - let leftLength = left.length; - let rightLength = right.length; + let firstLength = first.length; + let secondLength = second.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--; + while (firstLength > 0 && (first.charCodeAt(~-firstLength) === second.charCodeAt(~-secondLength))) { + firstLength--; + secondLength--; } // Performing prefix trimming @@ -33,45 +32,41 @@ const leven = (left, right) => { // don't increase distance at all let start = 0; - while (start < leftLength && (left.charCodeAt(start) === right.charCodeAt(start))) { + while (start < firstLength && (first.charCodeAt(start) === second.charCodeAt(start))) { start++; } - leftLength -= start; - rightLength -= start; + firstLength -= start; + secondLength -= start; - if (leftLength === 0) { - return rightLength; + if (firstLength === 0) { + return secondLength; } - let bCharCode; + let bCharacterCode; let result; - let temp; - let temp2; - let i = 0; - let j = 0; + let temporary; + let temporary2; + let index = 0; + let index2 = 0; - while (i < leftLength) { - charCodeCache[i] = left.charCodeAt(start + i); - array[i] = ++i; + while (index < firstLength) { + characterCodeCache[index] = first.charCodeAt(start + index); + array[index] = ++index; } - while (j < rightLength) { - bCharCode = right.charCodeAt(start + j); - temp = j++; - result = j; + while (index2 < secondLength) { + bCharacterCode = second.charCodeAt(start + index2); + temporary = index2++; + result = index2; - for (i = 0; i < leftLength; i++) { - temp2 = bCharCode === charCodeCache[i] ? temp : temp + 1; - temp = array[i]; + for (index = 0; index < firstLength; index++) { + temporary2 = bCharacterCode === characterCodeCache[index] ? temporary : temporary + 1; + temporary = array[index]; // eslint-disable-next-line no-multi-assign - result = array[i] = temp > result ? temp2 > result ? result + 1 : temp2 : temp2 > temp ? temp + 1 : temp2; + result = array[index] = temporary > result ? (temporary2 > result ? result + 1 : temporary2) : (temporary2 > temporary ? temporary + 1 : temporary2); } } return result; -}; - -module.exports = leven; -// TODO: Remove this for the next major release -module.exports.default = leven; +} diff --git a/index.test-d.ts b/index.test-d.ts index 79b7ca2..38bc9ad 100644 --- a/index.test-d.ts +++ b/index.test-d.ts @@ -1,4 +1,4 @@ import {expectType} from 'tsd'; -import leven = require('.'); +import leven from './index.js'; expectType(leven('kitten', 'sitting')); diff --git a/package.json b/package.json index bc75e7a..9326404 100644 --- a/package.json +++ b/package.json @@ -10,8 +10,10 @@ "email": "sindresorhus@gmail.com", "url": "https://sindresorhus.com" }, + "type": "module", + "exports": "./index.js", "engines": { - "node": ">=6" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, "scripts": { "test": "xo && ava && tsd", @@ -41,17 +43,17 @@ "matching" ], "devDependencies": { - "ava": "^1.4.1", - "fast-levenshtein": "^2.0.6", + "ava": "^3.15.0", + "fast-levenshtein": "^3.0.0", "ld": "^0.1.0", - "levdist": "^2.2.9", + "levdist": "^2.2.10", "levenshtein": "^1.0.5", "levenshtein-component": "^0.0.1", - "levenshtein-edit-distance": "^2.0.3", + "levenshtein-edit-distance": "^3.0.0", "matcha": "^0.7.0", - "natural": "^0.6.3", - "talisman": "^0.21.0", - "tsd": "^0.7.2", - "xo": "^0.24.0" + "natural": "^5.0.4", + "talisman": "^1.1.4", + "tsd": "^0.17.0", + "xo": "^0.44.0" } } diff --git a/readme.md b/readme.md index 89b13b1..fd1e08a 100644 --- a/readme.md +++ b/readme.md @@ -11,7 +11,7 @@ $ npm install leven ## Usage ```js -const leven = require('leven'); +import leven from 'leven'; leven('cat', 'cow'); //=> 2 diff --git a/test.js b/test.js index d35b1b5..367abda 100644 --- a/test.js +++ b/test.js @@ -1,5 +1,5 @@ import test from 'ava'; -import leven from '.'; +import leven from './index.js'; test('main', t => { t.is(leven('a', 'b'), 1);