6 Commits

Author SHA1 Message Date
0fb86bc21b 1.1.2 2021-10-03 17:12:03 +02:00
cb5a24320c fix(core): update 2021-10-03 17:12:02 +02:00
cbc72cd55b 1.1.1 2018-08-20 00:49:01 +02:00
a2d8f9575d fix(Smartfuzzy.getClosestMatchForString() now returns the cloesest string directly): update 2018-08-20 00:49:01 +02:00
6da6c6cca9 1.1.0 2018-08-19 20:52:52 +02:00
dc856dd5c7 feat(ObjectSorter): now sorts objects by likability 2018-08-19 20:52:52 +02:00
10 changed files with 25579 additions and 420 deletions

25851
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
{
"name": "@pushrocks/smartfuzzy",
"version": "1.0.3",
"version": "1.1.2",
"private": false,
"description": "fuzzy match strings against word dictionaries/arrays",
"main": "dist/index.js",
@ -13,14 +13,15 @@
"build": "(tsbuild)"
},
"devDependencies": {
"@gitzone/tsbuild": "^2.0.22",
"@gitzone/tstest": "^1.0.15",
"@pushrocks/tapbundle": "^3.0.5",
"@gitzone/tsbuild": "^2.1.27",
"@gitzone/tstest": "^1.0.57",
"@pushrocks/tapbundle": "^3.2.14",
"@types/node": "^10.7.1"
},
"dependencies": {
"@types/leven": "^2.1.1",
"fuse.js": "^3.2.1",
"leven": "^2.1.0"
"@pushrocks/smartpromise": "^3.1.6",
"@tsclass/tsclass": "^3.0.33",
"fuse.js": "^6.4.6",
"leven": "^3.1.0"
}
}

View File

@ -0,0 +1,33 @@
import { expect, tap } from '@pushrocks/tapbundle';
import * as tsclass from '@tsclass/tsclass';
import * as smartfuzzy from '../ts/index';
tap.test('should sort objects', async () => {
const articleArray: tsclass.content.IArticle[] = [
{
title: 'Berlin has a ambivalent history',
content: 'it is known that Berlin has an interesting history',
author: null,
tags: ['city', 'Europe', 'hello'],
timestamp: Date.now(),
featuredImageUrl: null,
url: null
},
{
title: 'Washington is a great city',
content: 'it is known that Washington is one of the greatest cities in the world',
author: null,
tags: ['city', 'USA', 'hello'],
timestamp: Date.now(),
featuredImageUrl: null,
url: null
}
];
const testArticleSearch = new smartfuzzy.ArticleSearch(articleArray);
const result = await testArticleSearch.search('USA');
console.log(result);
});
tap.start();

21
test/test.objectsorter.ts Normal file
View File

@ -0,0 +1,21 @@
import { expect, tap } from '@pushrocks/tapbundle';
import * as smartfuzzy from '../ts/index';
tap.test('should sort objects', async () => {
class Car {
constructor(public brand: string) {}
}
let testObjectSorter: smartfuzzy.ObjectSorter<Car>;
testObjectSorter = new smartfuzzy.ObjectSorter([
new Car('BMW'),
new Car('Mercedes Benz'),
new Car('Volvo')
]);
const result = testObjectSorter.sort('Volvo', ['brand']);
console.log(result);
});
tap.start();

View File

@ -14,11 +14,13 @@ tap.test('should create an instance of Smartfuzzy', async () => {
});
tap.test('should compute a score', async () => {
testSmartfuzzy.getChangeScoreForString('Apple');
const result = testSmartfuzzy.getChangeScoreForString('Apple');
console.log(result);
});
tap.test('should get closest match', async () => {
testSmartfuzzy.getClosestMatchForString('Apple');
const result = testSmartfuzzy.getClosestMatchForString('Apple');
console.log(result);
});
tap.start();

View File

@ -1 +1,3 @@
export * from './smartfuzzy.articlesearch';
export * from './smartfuzzy.classes.smartfuzzy';
export * from './smartfuzzy.classes.objectsorter';

View File

@ -0,0 +1,64 @@
import * as plugins from './smartfuzzy.plugins';
/**
* an article search that searches articles in a weighted manner
*/
export class ArticleSearch {
public articles: plugins.tsclass.content.IArticle[] = [];
public needsUpdate: boolean = false;
private readyDeferred = plugins.smartpromise.defer();
private fuse: plugins.fuseJs<plugins.tsclass.content.IArticle>;
constructor(articleArrayArg?: plugins.tsclass.content.IArticle[]) {
this.fuse = new plugins.fuseJs(this.articles);
this.readyDeferred.resolve();
if (articleArrayArg) {
for (const article of articleArrayArg) {
this.addArticle(article);
}
}
}
/**
* allows adding an article
*/
addArticle(articleArg: plugins.tsclass.content.IArticle) {
this.articles.push(articleArg);
this.needsUpdate = true;
}
/**
* allows searching an article
*/
public async search(searchStringArg: string) {
if (this.needsUpdate) {
const oldDeferred = this.readyDeferred;
this.readyDeferred = plugins.smartpromise.defer();
this.needsUpdate = false;
if (oldDeferred.status !== 'fulfilled') {
this.readyDeferred.promise.then(oldDeferred.resolve);
}
this.fuse = new plugins.fuseJs(this.articles, {
keys: [
{
name: 'title',
weight: 3,
},
{
name: 'tags',
weight: 2,
},
{
name: 'content',
weight: 1,
},
],
});
this.readyDeferred.resolve();
} else {
await this.readyDeferred.promise;
}
return this.fuse.search(searchStringArg);
}
}

View File

@ -0,0 +1,26 @@
import * as plugins from './smartfuzzy.plugins';
export class ObjectSorter<T> {
public objectDictionary: T[];
constructor(objectDictionaryArg: T[] = []) {
this.objectDictionary = objectDictionaryArg;
}
sort(stringArg: string, objectKeysArg: string[]): plugins.fuseJs.FuseResult<T>[] {
const fuseOptions = {
shouldSort: true,
threshold: 0.6,
location: 0,
distance: 100,
maxPatternLength: 32,
minMatchCharLength: 1,
keys: objectKeysArg
};
const fuse = new plugins.fuseJs<T>(this.objectDictionary, fuseOptions);
const result = fuse.search(stringArg);
return result;
}
}

View File

@ -2,6 +2,8 @@ import * as plugins from './smartfuzzy.plugins';
export let standardExport = 'Hi there! :) This is an exported string';
export type TDictionaryMap = { [key: string]: number };
export class Smartfuzzy {
dictionary: string[];
constructor(dictionary: string[]) {
@ -24,22 +26,22 @@ export class Smartfuzzy {
* returns the closest match for a given string
* @param stringArg
*/
getChangeScoreForString(stringArg) {
const dictionaryMap: { [key: string]: number } = {};
getChangeScoreForString(stringArg: string): TDictionaryMap {
const dictionaryMap: TDictionaryMap = {};
for (const wordArg of this.dictionary) {
dictionaryMap[wordArg] = plugins.leven(stringArg, wordArg);
}
console.log(dictionaryMap);
return dictionaryMap;
}
getClosestMatchForString(stringArg: string) {
getClosestMatchForString(stringArg: string): string {
const fuseDictionary: { name: string }[] = [];
for (const wordArg of this.dictionary) {
fuseDictionary.push({
name: wordArg
});
}
const options = {
const fuseOptions = {
shouldSort: true,
threshold: 0.6,
location: 0,
@ -48,8 +50,12 @@ export class Smartfuzzy {
minMatchCharLength: 1,
keys: ['name']
};
const fuse = new plugins.fuseJs(fuseDictionary, options);
const result = fuse.search(stringArg);
console.log(result);
const fuse = new plugins.fuseJs(fuseDictionary, fuseOptions);
const fuzzyResult = fuse.search(stringArg);
let closestMatch: string = null;
if(fuzzyResult.length > 0) {
closestMatch = fuzzyResult[0].item.name
}
return closestMatch;
}
}

View File

@ -1,4 +1,19 @@
import leven = require('leven');
const fuseJs = require('fuse.js');
// @pushrocks scope
import * as smartpromise from '@pushrocks/smartpromise';
export {
smartpromise
}
// @tsclass scope
import * as tsclass from '@tsclass/tsclass';
export {
tsclass
}
// third party scope
import leven from 'leven';
import fuseJs from 'fuse.js';
export { leven, fuseJs };