mirror of
https://github.com/verdaccio/verdaccio.git
synced 2025-02-17 23:45:29 -05:00
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 <juanpicado19@gmail.com>
This commit is contained in:
parent
1cc00cf2ab
commit
5ddfa5264c
7 changed files with 50 additions and 9 deletions
12
.changeset/red-chefs-float.md
Normal file
12
.changeset/red-chefs-float.md
Normal file
|
@ -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.
|
||||||
|
|
|
@ -123,6 +123,16 @@ describe('endpoint web unit test', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Search', () => {
|
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) => {
|
test('should not find forbidden-place', (done) => {
|
||||||
request(app)
|
request(app)
|
||||||
.get('/-/verdaccio/search/forbidden-place')
|
.get('/-/verdaccio/search/forbidden-place')
|
||||||
|
|
|
@ -50,6 +50,7 @@
|
||||||
"async": "3.1.1",
|
"async": "3.1.1",
|
||||||
"debug": "^4.1.1",
|
"debug": "^4.1.1",
|
||||||
"lodash": "4.17.15",
|
"lodash": "4.17.15",
|
||||||
|
"lunr": "2.3.9",
|
||||||
"lunr-mutable-indexes": "^2.3.2",
|
"lunr-mutable-indexes": "^2.3.2",
|
||||||
"semver": "7.1.2"
|
"semver": "7.1.2"
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,14 +1,20 @@
|
||||||
// eslint-disable no-invalid-this
|
// eslint-disable no-invalid-this
|
||||||
|
|
||||||
|
import lunr from 'lunr';
|
||||||
import lunrMutable from 'lunr-mutable-indexes';
|
import lunrMutable from 'lunr-mutable-indexes';
|
||||||
import { Version, IPluginStorage, Config } from '@verdaccio/types';
|
import { Version, IPluginStorage, Config } from '@verdaccio/types';
|
||||||
import { IStorageHandler, IStorage } from './storage';
|
import { IStorageHandler, IStorage } from './storage';
|
||||||
|
|
||||||
|
export interface ISearchResult {
|
||||||
|
ref: string;
|
||||||
|
score: number;
|
||||||
|
}
|
||||||
|
|
||||||
export interface IWebSearch {
|
export interface IWebSearch {
|
||||||
index: lunrMutable.index;
|
index: lunrMutable.index;
|
||||||
storage: IStorageHandler;
|
storage: IStorageHandler;
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
query(query: string): any;
|
query(query: string): ISearchResult[];
|
||||||
add(pkg: Version): void;
|
add(pkg: Version): void;
|
||||||
remove(name: string): void;
|
remove(name: string): void;
|
||||||
reindex(): void;
|
reindex(): void;
|
||||||
|
@ -42,6 +48,8 @@ class Search implements IWebSearch {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
this.field('readme');
|
this.field('readme');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.index.builder.pipeline.remove(lunr.stemmer);
|
||||||
}
|
}
|
||||||
|
|
||||||
public init() {
|
public init() {
|
||||||
|
@ -55,7 +63,7 @@ class Search implements IWebSearch {
|
||||||
* @param {*} q the keyword
|
* @param {*} q the keyword
|
||||||
* @return {Array} list of results.
|
* @return {Array} list of results.
|
||||||
*/
|
*/
|
||||||
public query(query: string): any[] {
|
public query(query: string): ISearchResult[] {
|
||||||
const localStorage = this.storage.localStorage as IStorage;
|
const localStorage = this.storage.localStorage as IStorage;
|
||||||
|
|
||||||
return query === '*'
|
return query === '*'
|
||||||
|
|
|
@ -28,6 +28,7 @@ function addSearchWebApi(route: Router, storage: IStorageHandler, auth: IAuth):
|
||||||
debug('is allowed %o', allowed);
|
debug('is allowed %o', allowed);
|
||||||
if (err || !allowed) {
|
if (err || !allowed) {
|
||||||
debug('deny access');
|
debug('deny access');
|
||||||
|
reject(err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
debug('access succeed');
|
debug('access succeed');
|
||||||
|
@ -52,17 +53,17 @@ function addSearchWebApi(route: Router, storage: IStorageHandler, auth: IAuth):
|
||||||
res: $ResponseExtend,
|
res: $ResponseExtend,
|
||||||
next: $NextFunctionVer
|
next: $NextFunctionVer
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const results: string[] = SearchInstance.query(req.params.anything);
|
const results = SearchInstance.query(req.params.anything);
|
||||||
debug('search results %o', results);
|
debug('search results %o', results);
|
||||||
if (results.length > 0) {
|
if (results.length > 0) {
|
||||||
let packages: Package[] = [];
|
let packages: Package[] = [];
|
||||||
for (let pkgName of results) {
|
for (let result of results) {
|
||||||
try {
|
try {
|
||||||
const pkg = await getPackageInfo(pkgName, req.remote_user);
|
const pkg = await getPackageInfo(result.ref, req.remote_user);
|
||||||
debug('package found %o', pkgName);
|
debug('package found %o', result.ref);
|
||||||
packages.push(pkg);
|
packages.push(pkg);
|
||||||
} catch (err) {
|
} 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);
|
next(packages);
|
||||||
|
|
|
@ -9,7 +9,10 @@ import { initializeServer } from './helper';
|
||||||
setup([]);
|
setup([]);
|
||||||
|
|
||||||
const mockManifest = jest.fn();
|
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/ui-theme', () => mockManifest());
|
||||||
|
|
||||||
jest.mock('@verdaccio/store', () => ({
|
jest.mock('@verdaccio/store', () => ({
|
||||||
|
@ -74,7 +77,11 @@ describe('test web server', () => {
|
||||||
|
|
||||||
test('should fail search api', async () => {
|
test('should fail search api', async () => {
|
||||||
mockQuery.mockImplementation(() => {
|
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'))
|
const response = await supertest(await initializeServer('default-test.yaml'))
|
||||||
.get('/-/verdaccio/search/notFound')
|
.get('/-/verdaccio/search/notFound')
|
||||||
|
|
2
pnpm-lock.yaml
generated
2
pnpm-lock.yaml
generated
|
@ -978,6 +978,7 @@ importers:
|
||||||
async: 3.1.1
|
async: 3.1.1
|
||||||
debug: ^4.1.1
|
debug: ^4.1.1
|
||||||
lodash: 4.17.15
|
lodash: 4.17.15
|
||||||
|
lunr: 2.3.9
|
||||||
lunr-mutable-indexes: ^2.3.2
|
lunr-mutable-indexes: ^2.3.2
|
||||||
semver: 7.1.2
|
semver: 7.1.2
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -992,6 +993,7 @@ importers:
|
||||||
async: 3.1.1
|
async: 3.1.1
|
||||||
debug: 4.1.1
|
debug: 4.1.1
|
||||||
lodash: 4.17.15
|
lodash: 4.17.15
|
||||||
|
lunr: 2.3.9
|
||||||
lunr-mutable-indexes: 2.3.2
|
lunr-mutable-indexes: 2.3.2
|
||||||
semver: 7.1.2
|
semver: 7.1.2
|
||||||
devDependencies:
|
devDependencies:
|
||||||
|
|
Loading…
Add table
Reference in a new issue