Compare commits
13 Commits
Author | SHA1 | Date | |
---|---|---|---|
58f7458acd | |||
34d8c86856 | |||
d4cea26fb5 | |||
de87e314c0 | |||
cddd1163ec | |||
0fb86bc21b | |||
cb5a24320c | |||
cbc72cd55b | |||
a2d8f9575d | |||
6da6c6cca9 | |||
dc856dd5c7 | |||
fdf9ec6358 | |||
8021e9f96f |
16
.gitignore
vendored
16
.gitignore
vendored
@ -1,6 +1,20 @@
|
||||
.nogit/
|
||||
node_modules/
|
||||
|
||||
# artifacts
|
||||
coverage/
|
||||
public/
|
||||
pages/
|
||||
|
||||
# installs
|
||||
node_modules/
|
||||
|
||||
# caches
|
||||
.yarn/
|
||||
.cache/
|
||||
.rpt2_cache
|
||||
|
||||
# builds
|
||||
dist/
|
||||
dist_*/
|
||||
|
||||
# custom
|
108
.gitlab-ci.yml
108
.gitlab-ci.yml
@ -1,10 +1,10 @@
|
||||
# gitzone standard
|
||||
image: hosttoday/ht-docker-node:npmci
|
||||
# gitzone ci_default
|
||||
image: registry.gitlab.com/hosttoday/ht-docker-node:npmci
|
||||
|
||||
cache:
|
||||
paths:
|
||||
- .npmci_cache/
|
||||
key: "$CI_BUILD_STAGE"
|
||||
key: '$CI_BUILD_STAGE'
|
||||
|
||||
stages:
|
||||
- security
|
||||
@ -19,56 +19,62 @@ mirror:
|
||||
stage: security
|
||||
script:
|
||||
- npmci git mirror
|
||||
only:
|
||||
- tags
|
||||
tags:
|
||||
- lossless
|
||||
- docker
|
||||
- notpriv
|
||||
|
||||
snyk:
|
||||
auditProductionDependencies:
|
||||
image: registry.gitlab.com/hosttoday/ht-docker-node:npmci
|
||||
stage: security
|
||||
script:
|
||||
- npmci command npm install -g snyk
|
||||
- npmci command npm install --ignore-scripts
|
||||
- npmci command snyk test
|
||||
- npmci npm prepare
|
||||
- npmci command npm install --production --ignore-scripts
|
||||
- npmci command npm config set registry https://registry.npmjs.org
|
||||
- npmci command npm audit --audit-level=high --only=prod --production
|
||||
tags:
|
||||
- docker
|
||||
- notpriv
|
||||
allow_failure: true
|
||||
|
||||
auditDevDependencies:
|
||||
image: registry.gitlab.com/hosttoday/ht-docker-node:npmci
|
||||
stage: security
|
||||
script:
|
||||
- npmci npm prepare
|
||||
- npmci command npm install --ignore-scripts
|
||||
- npmci command npm config set registry https://registry.npmjs.org
|
||||
- npmci command npm audit --audit-level=high --only=dev
|
||||
tags:
|
||||
- docker
|
||||
allow_failure: true
|
||||
|
||||
# ====================
|
||||
# test stage
|
||||
# ====================
|
||||
testLEGACY:
|
||||
stage: test
|
||||
script:
|
||||
- npmci node install legacy
|
||||
- npmci npm install
|
||||
- npmci npm test
|
||||
coverage: /\d+.?\d+?\%\s*coverage/
|
||||
tags:
|
||||
- docker
|
||||
- notpriv
|
||||
allow_failure: true
|
||||
|
||||
testLTS:
|
||||
stage: test
|
||||
script:
|
||||
- npmci node install lts
|
||||
- npmci npm install
|
||||
- npmci npm test
|
||||
coverage: /\d+.?\d+?\%\s*coverage/
|
||||
tags:
|
||||
- docker
|
||||
- notpriv
|
||||
|
||||
testSTABLE:
|
||||
testStable:
|
||||
stage: test
|
||||
script:
|
||||
- npmci npm prepare
|
||||
- npmci node install stable
|
||||
- npmci npm install
|
||||
- npmci npm test
|
||||
coverage: /\d+.?\d+?\%\s*coverage/
|
||||
tags:
|
||||
- docker
|
||||
- notpriv
|
||||
|
||||
testBuild:
|
||||
stage: test
|
||||
script:
|
||||
- npmci npm prepare
|
||||
- npmci node install stable
|
||||
- npmci npm install
|
||||
- npmci command npm run build
|
||||
coverage: /\d+.?\d+?\%\s*coverage/
|
||||
tags:
|
||||
- docker
|
||||
|
||||
release:
|
||||
stage: release
|
||||
@ -78,6 +84,7 @@ release:
|
||||
only:
|
||||
- tags
|
||||
tags:
|
||||
- lossless
|
||||
- docker
|
||||
- notpriv
|
||||
|
||||
@ -86,20 +93,16 @@ release:
|
||||
# ====================
|
||||
codequality:
|
||||
stage: metadata
|
||||
image: docker:stable
|
||||
allow_failure: true
|
||||
services:
|
||||
- docker:stable-dind
|
||||
only:
|
||||
- tags
|
||||
script:
|
||||
- export SP_VERSION=$(echo "$CI_SERVER_VERSION" | sed 's/^\([0-9]*\)\.\([0-9]*\).*/\1-\2-stable/')
|
||||
- docker run
|
||||
--env SOURCE_CODE="$PWD"
|
||||
--volume "$PWD":/code
|
||||
--volume /var/run/docker.sock:/var/run/docker.sock
|
||||
"registry.gitlab.com/gitlab-org/security-products/codequality:$SP_VERSION" /code
|
||||
artifacts:
|
||||
paths: [codeclimate.json]
|
||||
- npmci command npm install -g tslint typescript
|
||||
- npmci npm prepare
|
||||
- npmci npm install
|
||||
- npmci command "tslint -c tslint.json ./ts/**/*.ts"
|
||||
tags:
|
||||
- lossless
|
||||
- docker
|
||||
- priv
|
||||
|
||||
@ -110,17 +113,20 @@ trigger:
|
||||
only:
|
||||
- tags
|
||||
tags:
|
||||
- lossless
|
||||
- docker
|
||||
- notpriv
|
||||
|
||||
pages:
|
||||
image: hosttoday/ht-docker-node:npmci
|
||||
stage: metadata
|
||||
script:
|
||||
- npmci command npm install -g typedoc typescript
|
||||
- npmci node install lts
|
||||
- npmci command npm install -g @gitzone/tsdoc
|
||||
- npmci npm prepare
|
||||
- npmci npm install
|
||||
- npmci command typedoc --module "commonjs" --target "ES2016" --out public/ ts/
|
||||
- npmci command tsdoc
|
||||
tags:
|
||||
- lossless
|
||||
- docker
|
||||
- notpriv
|
||||
only:
|
||||
@ -130,13 +136,3 @@ pages:
|
||||
paths:
|
||||
- public
|
||||
allow_failure: true
|
||||
|
||||
windowsCompatibility:
|
||||
image: stefanscherer/node-windows:10-build-tools
|
||||
stage: metadata
|
||||
script:
|
||||
- npm install & npm test
|
||||
coverage: /\d+.?\d+?\%\s*coverage/
|
||||
tags:
|
||||
- windows
|
||||
allow_failure: true
|
||||
|
11
.vscode/launch.json
vendored
Normal file
11
.vscode/launch.json
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"command": "npm test",
|
||||
"name": "Run npm test",
|
||||
"request": "launch",
|
||||
"type": "node-terminal"
|
||||
}
|
||||
]
|
||||
}
|
26
.vscode/settings.json
vendored
Normal file
26
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
{
|
||||
"json.schemas": [
|
||||
{
|
||||
"fileMatch": ["/npmextra.json"],
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"npmci": {
|
||||
"type": "object",
|
||||
"description": "settings for npmci"
|
||||
},
|
||||
"gitzone": {
|
||||
"type": "object",
|
||||
"description": "settings for gitzone",
|
||||
"properties": {
|
||||
"projectType": {
|
||||
"type": "string",
|
||||
"enum": ["website", "element", "service", "npm", "wcc"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
@ -1,4 +1,15 @@
|
||||
{
|
||||
"gitzone": {
|
||||
"projectType": "npm",
|
||||
"module": {
|
||||
"githost": "gitlab.com",
|
||||
"gitscope": "pushrocks",
|
||||
"gitrepo": "smartfuzzy",
|
||||
"shortDescription": "search things easily",
|
||||
"npmPackagename": "@pushrocks/smartfuzzy",
|
||||
"license": "MIT"
|
||||
}
|
||||
},
|
||||
"npmci": {
|
||||
"npmGlobalTools": [],
|
||||
"npmAccessLevel": "public"
|
||||
|
25848
package-lock.json
generated
25848
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
40
package.json
40
package.json
@ -1,10 +1,10 @@
|
||||
{
|
||||
"name": "smartfuzzy",
|
||||
"version": "1.0.2",
|
||||
"name": "@pushrocks/smartfuzzy",
|
||||
"version": "1.1.5",
|
||||
"private": false,
|
||||
"description": "fuzzy match strings against word dictionaries/arrays",
|
||||
"main": "dist/index.js",
|
||||
"typings": "dist/index.d.ts",
|
||||
"main": "dist_ts/index.js",
|
||||
"typings": "dist_ts/index.d.ts",
|
||||
"author": "Lossless GmbH",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
@ -13,14 +13,30 @@
|
||||
"build": "(tsbuild)"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@gitzone/tsbuild": "^2.0.22",
|
||||
"@gitzone/tstest": "^1.0.15",
|
||||
"@pushrocks/tapbundle": "^3.0.5",
|
||||
"@types/node": "^10.7.1"
|
||||
"@gitzone/tsbuild": "^2.1.27",
|
||||
"@gitzone/tstest": "^1.0.57",
|
||||
"@pushrocks/tapbundle": "^3.2.14",
|
||||
"@types/node": "^16.10.2"
|
||||
},
|
||||
"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"
|
||||
},
|
||||
"browserslist": [
|
||||
"last 1 chrome versions"
|
||||
],
|
||||
"files": [
|
||||
"ts/**/*",
|
||||
"ts_web/**/*",
|
||||
"dist/**/*",
|
||||
"dist_*/**/*",
|
||||
"dist_ts/**/*",
|
||||
"dist_ts_web/**/*",
|
||||
"assets/**/*",
|
||||
"cli.js",
|
||||
"npmextra.json",
|
||||
"readme.md"
|
||||
]
|
||||
}
|
||||
|
34
test/test.articlesearch.ts
Normal file
34
test/test.articlesearch.ts
Normal file
@ -0,0 +1,34 @@
|
||||
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);
|
||||
console.log(result[0].matches);
|
||||
});
|
||||
|
||||
tap.start();
|
21
test/test.objectsorter.ts
Normal file
21
test/test.objectsorter.ts
Normal 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();
|
@ -8,17 +8,19 @@ tap.test('should create an instance of Smartfuzzy', async () => {
|
||||
'Sony',
|
||||
'Deutsche Bahn',
|
||||
'Apple Inc.',
|
||||
"Trader Joe's"
|
||||
"Trader Joe's",
|
||||
]);
|
||||
expect(testSmartfuzzy).to.be.instanceof(smartfuzzy.Smartfuzzy);
|
||||
});
|
||||
|
||||
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();
|
@ -1 +1,3 @@
|
||||
export * from './smartfuzzy.articlesearch';
|
||||
export * from './smartfuzzy.classes.smartfuzzy';
|
||||
export * from './smartfuzzy.classes.objectsorter';
|
||||
|
65
ts/smartfuzzy.articlesearch.ts
Normal file
65
ts/smartfuzzy.articlesearch.ts
Normal file
@ -0,0 +1,65 @@
|
||||
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,
|
||||
},
|
||||
],
|
||||
includeMatches: true,
|
||||
});
|
||||
this.readyDeferred.resolve();
|
||||
} else {
|
||||
await this.readyDeferred.promise;
|
||||
}
|
||||
return this.fuse.search(searchStringArg);
|
||||
}
|
||||
}
|
24
ts/smartfuzzy.classes.objectsorter.ts
Normal file
24
ts/smartfuzzy.classes.objectsorter.ts
Normal file
@ -0,0 +1,24 @@
|
||||
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;
|
||||
}
|
||||
}
|
@ -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,32 +26,36 @@ 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
|
||||
name: wordArg,
|
||||
});
|
||||
}
|
||||
const options = {
|
||||
const fuseOptions = {
|
||||
shouldSort: true,
|
||||
threshold: 0.6,
|
||||
location: 0,
|
||||
distance: 100,
|
||||
maxPatternLength: 32,
|
||||
minMatchCharLength: 1,
|
||||
keys: ['name']
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,15 @@
|
||||
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 };
|
||||
|
14
tslint.json
14
tslint.json
@ -1,7 +1,17 @@
|
||||
{
|
||||
"extends": ["tslint:latest", "tslint-config-prettier"],
|
||||
"rules": {
|
||||
"semicolon": [true, "always"]
|
||||
"semicolon": [true, "always"],
|
||||
"no-console": false,
|
||||
"ordered-imports": false,
|
||||
"object-literal-sort-keys": false,
|
||||
"member-ordering": {
|
||||
"options":{
|
||||
"order": [
|
||||
"static-method"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
"defaultSeverity": "warning"
|
||||
}
|
||||
|
Reference in New Issue
Block a user