From 5ddfa5264c16499bfd54154e856913074411bc51 Mon Sep 17 00:00:00 2001 From: Leonardo Metzger Date: Fri, 7 May 2021 01:43:29 -0300 Subject: [PATCH] fix: fix the exact search phrase (#2225) * fix: Fix the exact search phrase * fix: Add changeset to fix of exact search phrase Co-authored-by: Juan Picado --- .changeset/red-chefs-float.md | 12 ++++++++++++ packages/server/test/web/index.spec.ts | 10 ++++++++++ packages/store/package.json | 1 + packages/store/src/search.ts | 12 ++++++++++-- packages/web/src/api/search.ts | 11 ++++++----- packages/web/test/api.search.test.ts | 11 +++++++++-- pnpm-lock.yaml | 2 ++ 7 files changed, 50 insertions(+), 9 deletions(-) create mode 100644 .changeset/red-chefs-float.md diff --git a/.changeset/red-chefs-float.md b/.changeset/red-chefs-float.md new file mode 100644 index 000000000000..755f3cd9c885 --- /dev/null +++ b/.changeset/red-chefs-float.md @@ -0,0 +1,12 @@ +--- +'@verdaccio/store': patch +'@verdaccio/web': patch +--- + +Fix the search by exact name of the package + +Full package name queries was not finding anithing. It was happening +becouse of stemmer of [lunr.js](https://lunrjs.com/). + +To fix this, the stemmer of [lunr.js](https://lunrjs.com/) was removed from search pipeline. + diff --git a/packages/server/test/web/index.spec.ts b/packages/server/test/web/index.spec.ts index 877eb3f0db42..562475bc9c20 100644 --- a/packages/server/test/web/index.spec.ts +++ b/packages/server/test/web/index.spec.ts @@ -123,6 +123,16 @@ describe('endpoint web unit test', () => { }); describe('Search', () => { + test('should find @scope/pk1-test', (done) => { + request(app) + .get('/-/verdaccio/search/@scope%2fpk1-test') + .expect(HTTP_STATUS.OK) + .end(function (err, res) { + expect(res.body).toHaveLength(1); + done(); + }); + }); + test('should not find forbidden-place', (done) => { request(app) .get('/-/verdaccio/search/forbidden-place') diff --git a/packages/store/package.json b/packages/store/package.json index 386c70635598..0f7af037584b 100644 --- a/packages/store/package.json +++ b/packages/store/package.json @@ -50,6 +50,7 @@ "async": "3.1.1", "debug": "^4.1.1", "lodash": "4.17.15", + "lunr": "2.3.9", "lunr-mutable-indexes": "^2.3.2", "semver": "7.1.2" }, diff --git a/packages/store/src/search.ts b/packages/store/src/search.ts index 7a5784d5f458..397c59727d2c 100644 --- a/packages/store/src/search.ts +++ b/packages/store/src/search.ts @@ -1,14 +1,20 @@ // eslint-disable no-invalid-this +import lunr from 'lunr'; import lunrMutable from 'lunr-mutable-indexes'; import { Version, IPluginStorage, Config } from '@verdaccio/types'; import { IStorageHandler, IStorage } from './storage'; +export interface ISearchResult { + ref: string; + score: number; +} + export interface IWebSearch { index: lunrMutable.index; storage: IStorageHandler; // eslint-disable-next-line @typescript-eslint/no-explicit-any - query(query: string): any; + query(query: string): ISearchResult[]; add(pkg: Version): void; remove(name: string): void; reindex(): void; @@ -42,6 +48,8 @@ class Search implements IWebSearch { // @ts-ignore this.field('readme'); }); + + this.index.builder.pipeline.remove(lunr.stemmer); } public init() { @@ -55,7 +63,7 @@ class Search implements IWebSearch { * @param {*} q the keyword * @return {Array} list of results. */ - public query(query: string): any[] { + public query(query: string): ISearchResult[] { const localStorage = this.storage.localStorage as IStorage; return query === '*' diff --git a/packages/web/src/api/search.ts b/packages/web/src/api/search.ts index 78e5181ba2c1..bb5d2f325899 100644 --- a/packages/web/src/api/search.ts +++ b/packages/web/src/api/search.ts @@ -28,6 +28,7 @@ function addSearchWebApi(route: Router, storage: IStorageHandler, auth: IAuth): debug('is allowed %o', allowed); if (err || !allowed) { debug('deny access'); + reject(err); return; } debug('access succeed'); @@ -52,17 +53,17 @@ function addSearchWebApi(route: Router, storage: IStorageHandler, auth: IAuth): res: $ResponseExtend, next: $NextFunctionVer ): Promise { - const results: string[] = SearchInstance.query(req.params.anything); + const results = SearchInstance.query(req.params.anything); debug('search results %o', results); if (results.length > 0) { let packages: Package[] = []; - for (let pkgName of results) { + for (let result of results) { try { - const pkg = await getPackageInfo(pkgName, req.remote_user); - debug('package found %o', pkgName); + const pkg = await getPackageInfo(result.ref, req.remote_user); + debug('package found %o', result.ref); packages.push(pkg); } catch (err) { - debug('search for %o failed err %o', pkgName, err?.message); + debug('search for %o failed err %o', result.ref, err?.message); } } next(packages); diff --git a/packages/web/test/api.search.test.ts b/packages/web/test/api.search.test.ts index c2e28d198789..e4bf7c0f65a7 100644 --- a/packages/web/test/api.search.test.ts +++ b/packages/web/test/api.search.test.ts @@ -9,7 +9,10 @@ import { initializeServer } from './helper'; setup([]); const mockManifest = jest.fn(); -const mockQuery = jest.fn(() => ['pkg1', 'pk2']); +const mockQuery = jest.fn(() => [ + { ref: 'pkg1', score: 1 }, + { ref: 'pk2', score: 0.9 }, +]); jest.mock('@verdaccio/ui-theme', () => mockManifest()); jest.mock('@verdaccio/store', () => ({ @@ -74,7 +77,11 @@ describe('test web server', () => { test('should fail search api', async () => { mockQuery.mockImplementation(() => { - return ['aa', 'bb', 'cc']; + return [ + { ref: 'aa', score: 1 }, + { ref: 'bb', score: 0.8 }, + { ref: 'cc', score: 0.6 }, + ]; }); const response = await supertest(await initializeServer('default-test.yaml')) .get('/-/verdaccio/search/notFound') diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index cbff75f17b70..ae17fba15eb3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -978,6 +978,7 @@ importers: async: 3.1.1 debug: ^4.1.1 lodash: 4.17.15 + lunr: 2.3.9 lunr-mutable-indexes: ^2.3.2 semver: 7.1.2 dependencies: @@ -992,6 +993,7 @@ importers: async: 3.1.1 debug: 4.1.1 lodash: 4.17.15 + lunr: 2.3.9 lunr-mutable-indexes: 2.3.2 semver: 7.1.2 devDependencies: