From 20b22483a0a58fdcfda402b985a0eac36327fcb1 Mon Sep 17 00:00:00 2001 From: Chloe Date: Tue, 30 Jul 2024 12:50:27 -0400 Subject: [PATCH] fix: replace fuse.js with leven to fix no similar matching name error (#452) * fix: replace fuse.js with leven to fix no similar matching name error * fix: code coverage * store prev leven call --- package.json | 2 +- pnpm-lock.yaml | 16 ++++----- react/player/BUILD | 2 +- .../player/src/asset/__tests__/index.test.tsx | 35 ++++++++++++++++--- react/player/src/asset/index.tsx | 22 +++++++++--- tsconfig.json | 3 +- 6 files changed, 59 insertions(+), 21 deletions(-) diff --git a/package.json b/package.json index f816f09c8..7498f5645 100644 --- a/package.json +++ b/package.json @@ -105,7 +105,6 @@ "eslint-plugin-prettier": "^5.0.1", "eslint-plugin-react": "^7.33.2", "framer-motion": "^10.16.4", - "fuse.js": "^7.0.0", "gh-pages": "^4.0.0", "github-slugger": "^1.0.0", "globby": "^11.0.1", @@ -115,6 +114,7 @@ "husky": "^7.0.2", "is-ci-cli": "^2.2.0", "lcov-result-merger": "^3.1.0", + "leven":"4.0.0", "lint-staged": "^11.2.3", "lucide-react": "^0.316.0", "lunr": "^2.3.9", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2d1fafc53..82b8b218c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -270,9 +270,6 @@ importers: framer-motion: specifier: ^10.16.4 version: 10.18.0(react-dom@18.3.1)(react@18.3.1) - fuse.js: - specifier: ^7.0.0 - version: 7.0.0 gh-pages: specifier: ^4.0.0 version: 4.0.0 @@ -300,6 +297,9 @@ importers: lcov-result-merger: specifier: ^3.1.0 version: 3.3.0 + leven: + specifier: 4.0.0 + version: 4.0.0 lint-staged: specifier: ^11.2.3 version: 11.2.6 @@ -11422,11 +11422,6 @@ packages: resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==, tarball: https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz} dev: false - /fuse.js@7.0.0: - resolution: {integrity: sha512-14F4hBIxqKvD4Zz/XjDc3y94mNZN6pRv3U13Udo0lNLCWRBUsrMv2xwcF/y/Z5sV6+FQW+/ow68cHpm4sunt8Q==, tarball: https://registry.npmjs.org/fuse.js/-/fuse.js-7.0.0.tgz} - engines: {node: '>=10'} - dev: false - /gensync@1.0.0-beta.2: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==, tarball: https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz} engines: {node: '>=6.9.0'} @@ -13195,6 +13190,11 @@ packages: engines: {node: '>=6'} dev: false + /leven@4.0.0: + resolution: {integrity: sha512-puehA3YKku3osqPlNuzGDUHq8WpwXupUg1V6NXdV38G+gr+gkBwFC8g1b/+YcIvp8gnqVIus+eJCH/eGsRmJNw==, tarball: https://registry.npmjs.org/leven/-/leven-4.0.0.tgz} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dev: false + /levn@0.4.1: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==, tarball: https://registry.npmjs.org/levn/-/levn-0.4.1.tgz} engines: {node: '>= 0.8.0'} diff --git a/react/player/BUILD b/react/player/BUILD index 14087a38d..2da83ea88 100644 --- a/react/player/BUILD +++ b/react/player/BUILD @@ -27,6 +27,6 @@ js_pipeline( ":node_modules/@player-ui/react-subscribe", "//:node_modules/react-error-boundary", "//:node_modules/tapable-ts", - "//:node_modules/fuse.js", + "//:node_modules/leven", ], ) diff --git a/react/player/src/asset/__tests__/index.test.tsx b/react/player/src/asset/__tests__/index.test.tsx index 2e1b6fdcb..dba54bba6 100644 --- a/react/player/src/asset/__tests__/index.test.tsx +++ b/react/player/src/asset/__tests__/index.test.tsx @@ -30,17 +30,42 @@ test("it prioritizes local type and id", () => { expect(asset.getByText("foo")).not.toBeUndefined(); }); -test("throws an error for an asset missing implementation or not registered", () => { +test("throws an error for an asset missing implementation or not registered WITHOUT similar matching type", () => { const assetDef = { asset: { id: "bar-id", - type: "bar", + type: "test", + }, + } as unknown as AssetType; + + const registry: AssetRegistryType = new Registry([ + [{ type: "bar", key: "bar-key" }, () =>
bar
], + [{ type: "foo", key: "foo-key" }, () =>
foo
], + ]); + + expect(() => + render( + + + , + ), + ) + .toThrowError(`No implementation found for id: bar-id type: test. Did you mean bar? \n + Registered Asset matching functions are listed below: \n + [{"type":"foo","key":"foo-key"},{"type":"bar","key":"bar-key"}]`); +}); + +test("throws an error for an asset missing implementation or not registered WITH similar matching type", () => { + const assetDef = { + asset: { + id: "foo-id", + type: "foo1", }, } as unknown as AssetType; const registry: AssetRegistryType = new Registry([ + [{ type: "bar", key: "bar-key" }, () =>
bar
], [{ type: "foo", key: "foo-key" }, () =>
foo
], - [{ type: "bar1", key: "bar-key" }, () =>
bar
], ]); expect(() => @@ -50,9 +75,9 @@ test("throws an error for an asset missing implementation or not registered", () , ), ) - .toThrowError(`No implementation found for id: bar-id type: bar. Did you mean {"type":"bar1","key":"bar-key"}? \n + .toThrowError(`No implementation found for id: foo-id type: foo1. Did you mean foo? \n Registered Asset matching functions are listed below: \n - [{"type":"bar1","key":"bar-key"},{"type":"foo","key":"foo-key"}]`); + [{"type":"foo","key":"foo-key"},{"type":"bar","key":"bar-key"}]`); }); test("throws an error for an asset missing type", () => { diff --git a/react/player/src/asset/index.tsx b/react/player/src/asset/index.tsx index 23555db57..176d0fb9a 100644 --- a/react/player/src/asset/index.tsx +++ b/react/player/src/asset/index.tsx @@ -1,7 +1,7 @@ import React from "react"; +import leven from "leven"; import type { Asset as AssetType, AssetWrapper } from "@player-ui/player"; import type { Registry } from "@player-ui/partial-match-registry"; -import Fuse from "fuse.js"; export type AssetRegistryType = Registry>; @@ -66,13 +66,25 @@ export const ReactAsset = ( matchList.push(asset.key); }); - const fuse = new Fuse(matchList, { keys: ["type", "key"] }); - const similarType = JSON.stringify( - fuse.search(unwrapped.type as string)[0].item, + const typeList = matchList.map( + (match) => JSON.parse(JSON.stringify(match)).type, ); + const similarType = typeList.reduce((prev, curr) => { + const next = { + value: leven(unwrapped.type, curr), + type: curr, + }; + + if (prev !== undefined && prev.value < next.value) { + return prev; + } + + return next; + }, undefined); + throw Error( - `No implementation found for id: ${unwrapped.id} type: ${unwrapped.type}. Did you mean ${similarType}? \n + `No implementation found for id: ${unwrapped.id} type: ${unwrapped.type}. Did you mean ${similarType.type}? \n Registered Asset matching functions are listed below: \n ${JSON.stringify(matchList)}`, ); diff --git a/tsconfig.json b/tsconfig.json index dfd5594f6..f3ca31b75 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -22,6 +22,7 @@ "resolveJsonModule": true, "composite": true, "lib": ["DOM", "ES2020"], - "isolatedDeclarations": true + "isolatedDeclarations": true, + "noUncheckedIndexedAccess": true, } }