You're Invited:Meet the Socket Team at RSAC and BSidesSF 2026, March 23–26.RSVP
Socket
Book a DemoSign in
Socket

@nexucis/fuzzy

Package Overview
Dependencies
Maintainers
1
Versions
10
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@nexucis/fuzzy - npm Package Compare versions

Comparing version
0.3.0
to
0.4.0
+229
dist/cjs/index.js
"use strict";
// MIT License
//
// Copyright (c) 2020 Augustin Husson
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
Object.defineProperty(exports, "__esModule", { value: true });
exports.render = exports.match = exports.filter = exports.Fuzzy = exports.score = void 0;
function escapeHTML(text) {
return text.replace(/[&<>"']/g, (m) => {
switch (m) {
case '&':
return '&amp;';
case '<':
return '&lt;';
case '>':
return '&gt;';
case '"':
return '&quot;';
default:
return '&#039;';
}
});
}
function intervalSize(interval) {
return interval.to - interval.from + 1;
}
function calculatePreviousNotMatchingInterval(intervals, idx) {
const currentInterval = intervals[idx];
let previousNotMatchingInterval = null;
if (idx === 0 && currentInterval.from !== 0) {
previousNotMatchingInterval = { from: 0, to: currentInterval.from - 1 };
}
if (idx > 0) {
previousNotMatchingInterval = { from: intervals[idx - 1].to + 1, to: currentInterval.from - 1 };
}
return previousNotMatchingInterval;
}
// score should be used to calculate the score based on the intervals created during the matching step.
// Here is how the score is determinated:
// 1. Consecutive characters should increase the score more than linearly
// 2. More there is a distance between the characters, higher it reduces the score
// For example, for the pattern 'abc', the following string are sorted by the highest score
// abcdef > defabc > abec > defabec
// Note: this function is exported only for testing purpose.
function score(intervals, strLength) {
let result = 0;
for (let i = 0; i < intervals.length; i++) {
const currentInterval = intervals[i];
const previousNotMatchingInterval = calculatePreviousNotMatchingInterval(intervals, i);
if (previousNotMatchingInterval !== null) {
result = result - intervalSize(previousNotMatchingInterval) / strLength;
}
result = result + intervalSize(currentInterval) ** 2;
}
return result;
}
exports.score = score;
// generateMatchingInterval will iterate other the given text to find the different char that matched the given pattern
function generateMatchingInterval(pattern, text, idxText) {
let patternIdx = 0;
const intervals = [];
for (let i = idxText; i < text.length && patternIdx < pattern.length;) {
if (text[i] === pattern[patternIdx]) {
const interval = { from: i, to: i };
patternIdx++;
i++;
for (let j = i; j < text.length && patternIdx < pattern.length && text[j] === pattern[patternIdx]; j++) {
interval.to = j;
patternIdx++;
i = j;
}
intervals.push(interval);
}
i++;
}
if (intervals.length === 0 || patternIdx !== pattern.length) {
return null;
}
return { score: score(intervals, text.length), intervals: intervals };
}
class Fuzzy {
constructor(conf) {
this.conf = {
caseSensitive: (conf === null || conf === void 0 ? void 0 : conf.caseSensitive) === undefined ? false : conf.caseSensitive,
includeMatches: (conf === null || conf === void 0 ? void 0 : conf.includeMatches) === undefined ? false : conf.includeMatches,
shouldSort: (conf === null || conf === void 0 ? void 0 : conf.shouldSort) === undefined ? false : conf.shouldSort,
escapeHTML: (conf === null || conf === void 0 ? void 0 : conf.escapeHTML) === undefined ? false : conf.escapeHTML,
pre: (conf === null || conf === void 0 ? void 0 : conf.pre) === undefined ? '' : conf.pre,
post: (conf === null || conf === void 0 ? void 0 : conf.post) === undefined ? '' : conf.post,
};
}
// filter is the method to use to filter a string list
// list of result return can be sort if parameter `shouldSort` is set.
filter(pattern, list, conf) {
const shouldSort = (conf === null || conf === void 0 ? void 0 : conf.shouldSort) !== undefined ? conf.shouldSort : this.conf.shouldSort;
let result = [];
for (let i = 0; i < list.length; i++) {
const matchedText = this.match(pattern, list[i], conf);
if (matchedText !== null) {
matchedText.index = i;
result.push(matchedText);
}
}
if (shouldSort) {
result = result.sort((a, b) => {
return b.score - a.score;
});
}
return result;
}
// match will return a result if `pattern` is matching `text`,
match(pattern, text, conf) {
let localPattern = pattern;
let localText = text;
const caseSensitive = (conf === null || conf === void 0 ? void 0 : conf.caseSensitive) !== undefined ? conf.caseSensitive : this.conf.caseSensitive;
const includeMatches = (conf === null || conf === void 0 ? void 0 : conf.includeMatches) !== undefined ? conf.includeMatches : this.conf.includeMatches;
if (!caseSensitive) {
localPattern = localPattern.toLowerCase();
localText = localText.toLowerCase();
}
// in case it's a perfect match, no need to loop to find which char is matching
if (localPattern === localText) {
const intervals = [{ from: 0, to: pattern.length - 1 }];
const result = {
original: text,
rendered: this.render(text, intervals, conf),
score: Infinity,
};
if (includeMatches) {
result.intervals = intervals;
}
return result;
}
// otherwise let's calculate the different indices that will then be used to calculate the score
let intervals = [];
let score = 0;
for (let i = 0; i < localText.length - localPattern.length + 1; i++) {
// Each time a char is matching the first char of the pattern
// loop other the rest of the text to generate the different matching interval.
// Like that we will be able to find the best matching possibility.
// For example: given the pattern `bac` and the text `babac`
// instead of matching `<ba>ba<c>, it will match ba<bac> which has a better score than the previous one.
if (localText[i] === localPattern[0]) {
const matchingResult = generateMatchingInterval(localPattern, localText, i);
if (matchingResult === null) {
break;
}
if (matchingResult.score > score) {
score = matchingResult.score;
intervals = matchingResult.intervals;
}
}
}
if (intervals.length === 0) {
return null;
}
const result = {
original: text,
rendered: this.render(text, intervals, conf),
score: score,
};
if (includeMatches) {
result.intervals = intervals;
}
return result;
}
// render will modify the text according to the different parameter set in the conf.
// If nothing is set, then it will return the text not modified.
render(text, intervals, conf) {
let rendered = '';
const pre = (conf === null || conf === void 0 ? void 0 : conf.pre) ? conf.pre : this.conf.pre;
const post = (conf === null || conf === void 0 ? void 0 : conf.post) ? conf.post : this.conf.post;
for (let i = 0; i < intervals.length; i++) {
const currentInterval = intervals[i];
const previousNotMatchingInterval = calculatePreviousNotMatchingInterval(intervals, i);
let previousStr = '';
if (previousNotMatchingInterval !== null) {
previousStr = this.extractSubString(text, previousNotMatchingInterval, conf);
}
const currentStr = this.extractSubString(text, currentInterval, conf);
rendered = `${rendered}${previousStr}${pre}${currentStr}${post}`;
}
// check if the last interval contains the end of the string. Otherwise add it
const lastInterval = intervals[intervals.length - 1];
if (lastInterval.to < text.length - 1) {
rendered = rendered + this.extractSubString(text, { from: lastInterval.to + 1, to: text.length }, conf);
}
return rendered;
}
extractSubString(text, interval, conf) {
const shouldEscape = (conf === null || conf === void 0 ? void 0 : conf.escapeHTML) !== undefined ? conf.escapeHTML : this.conf.escapeHTML;
let str = text.substr(interval.from, intervalSize(interval));
if (shouldEscape) {
str = escapeHTML(str);
}
return str;
}
}
exports.Fuzzy = Fuzzy;
const fuz = new Fuzzy();
function filter(pattern, list, conf) {
return fuz.filter(pattern, list, conf);
}
exports.filter = filter;
function match(pattern, text, conf) {
return fuz.match(pattern, text, conf);
}
exports.match = match;
function render(text, intervals, conf) {
return fuz.render(text, intervals, conf);
}
exports.render = render;
export declare function score(intervals: FuzzyMatchingInterval[], strLength: number): number;
export interface FuzzyConfiguration {
caseSensitive?: boolean;
includeMatches?: boolean;
shouldSort?: boolean;
escapeHTML?: boolean;
pre?: string;
post?: string;
}
export interface FuzzyMatchingInterval {
from: number;
to: number;
}
export interface FuzzyResult {
rendered: string;
original: string;
index: number;
score: number;
intervals?: FuzzyMatchingInterval[];
}
export declare class Fuzzy {
private readonly conf;
constructor(conf?: FuzzyConfiguration);
filter(pattern: string, list: string[], conf?: FuzzyConfiguration): FuzzyResult[];
match(pattern: string, text: string, conf?: FuzzyConfiguration): FuzzyResult | null;
render(text: string, intervals: FuzzyMatchingInterval[], conf?: FuzzyConfiguration): string;
private extractSubString;
}
export declare function filter(pattern: string, list: string[], conf?: FuzzyConfiguration): FuzzyResult[];
export declare function match(pattern: string, text: string, conf?: FuzzyConfiguration): FuzzyResult | null;
export declare function render(text: string, intervals: FuzzyMatchingInterval[], conf?: FuzzyConfiguration): string;
// MIT License
//
// Copyright (c) 2020 Augustin Husson
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
function escapeHTML(text) {
return text.replace(/[&<>"']/g, (m) => {
switch (m) {
case '&':
return '&amp;';
case '<':
return '&lt;';
case '>':
return '&gt;';
case '"':
return '&quot;';
default:
return '&#039;';
}
});
}
function intervalSize(interval) {
return interval.to - interval.from + 1;
}
function calculatePreviousNotMatchingInterval(intervals, idx) {
const currentInterval = intervals[idx];
let previousNotMatchingInterval = null;
if (idx === 0 && currentInterval.from !== 0) {
previousNotMatchingInterval = { from: 0, to: currentInterval.from - 1 };
}
if (idx > 0) {
previousNotMatchingInterval = { from: intervals[idx - 1].to + 1, to: currentInterval.from - 1 };
}
return previousNotMatchingInterval;
}
// score should be used to calculate the score based on the intervals created during the matching step.
// Here is how the score is determinated:
// 1. Consecutive characters should increase the score more than linearly
// 2. More there is a distance between the characters, higher it reduces the score
// For example, for the pattern 'abc', the following string are sorted by the highest score
// abcdef > defabc > abec > defabec
// Note: this function is exported only for testing purpose.
export function score(intervals, strLength) {
let result = 0;
for (let i = 0; i < intervals.length; i++) {
const currentInterval = intervals[i];
const previousNotMatchingInterval = calculatePreviousNotMatchingInterval(intervals, i);
if (previousNotMatchingInterval !== null) {
result = result - intervalSize(previousNotMatchingInterval) / strLength;
}
result = result + intervalSize(currentInterval) ** 2;
}
return result;
}
// generateMatchingInterval will iterate other the given text to find the different char that matched the given pattern
function generateMatchingInterval(pattern, text, idxText) {
let patternIdx = 0;
const intervals = [];
for (let i = idxText; i < text.length && patternIdx < pattern.length;) {
if (text[i] === pattern[patternIdx]) {
const interval = { from: i, to: i };
patternIdx++;
i++;
for (let j = i; j < text.length && patternIdx < pattern.length && text[j] === pattern[patternIdx]; j++) {
interval.to = j;
patternIdx++;
i = j;
}
intervals.push(interval);
}
i++;
}
if (intervals.length === 0 || patternIdx !== pattern.length) {
return null;
}
return { score: score(intervals, text.length), intervals: intervals };
}
export class Fuzzy {
constructor(conf) {
this.conf = {
caseSensitive: (conf === null || conf === void 0 ? void 0 : conf.caseSensitive) === undefined ? false : conf.caseSensitive,
includeMatches: (conf === null || conf === void 0 ? void 0 : conf.includeMatches) === undefined ? false : conf.includeMatches,
shouldSort: (conf === null || conf === void 0 ? void 0 : conf.shouldSort) === undefined ? false : conf.shouldSort,
escapeHTML: (conf === null || conf === void 0 ? void 0 : conf.escapeHTML) === undefined ? false : conf.escapeHTML,
pre: (conf === null || conf === void 0 ? void 0 : conf.pre) === undefined ? '' : conf.pre,
post: (conf === null || conf === void 0 ? void 0 : conf.post) === undefined ? '' : conf.post,
};
}
// filter is the method to use to filter a string list
// list of result return can be sort if parameter `shouldSort` is set.
filter(pattern, list, conf) {
const shouldSort = (conf === null || conf === void 0 ? void 0 : conf.shouldSort) !== undefined ? conf.shouldSort : this.conf.shouldSort;
let result = [];
for (let i = 0; i < list.length; i++) {
const matchedText = this.match(pattern, list[i], conf);
if (matchedText !== null) {
matchedText.index = i;
result.push(matchedText);
}
}
if (shouldSort) {
result = result.sort((a, b) => {
return b.score - a.score;
});
}
return result;
}
// match will return a result if `pattern` is matching `text`,
match(pattern, text, conf) {
let localPattern = pattern;
let localText = text;
const caseSensitive = (conf === null || conf === void 0 ? void 0 : conf.caseSensitive) !== undefined ? conf.caseSensitive : this.conf.caseSensitive;
const includeMatches = (conf === null || conf === void 0 ? void 0 : conf.includeMatches) !== undefined ? conf.includeMatches : this.conf.includeMatches;
if (!caseSensitive) {
localPattern = localPattern.toLowerCase();
localText = localText.toLowerCase();
}
// in case it's a perfect match, no need to loop to find which char is matching
if (localPattern === localText) {
const intervals = [{ from: 0, to: pattern.length - 1 }];
const result = {
original: text,
rendered: this.render(text, intervals, conf),
score: Infinity,
};
if (includeMatches) {
result.intervals = intervals;
}
return result;
}
// otherwise let's calculate the different indices that will then be used to calculate the score
let intervals = [];
let score = 0;
for (let i = 0; i < localText.length - localPattern.length + 1; i++) {
// Each time a char is matching the first char of the pattern
// loop other the rest of the text to generate the different matching interval.
// Like that we will be able to find the best matching possibility.
// For example: given the pattern `bac` and the text `babac`
// instead of matching `<ba>ba<c>, it will match ba<bac> which has a better score than the previous one.
if (localText[i] === localPattern[0]) {
const matchingResult = generateMatchingInterval(localPattern, localText, i);
if (matchingResult === null) {
break;
}
if (matchingResult.score > score) {
score = matchingResult.score;
intervals = matchingResult.intervals;
}
}
}
if (intervals.length === 0) {
return null;
}
const result = {
original: text,
rendered: this.render(text, intervals, conf),
score: score,
};
if (includeMatches) {
result.intervals = intervals;
}
return result;
}
// render will modify the text according to the different parameter set in the conf.
// If nothing is set, then it will return the text not modified.
render(text, intervals, conf) {
let rendered = '';
const pre = (conf === null || conf === void 0 ? void 0 : conf.pre) ? conf.pre : this.conf.pre;
const post = (conf === null || conf === void 0 ? void 0 : conf.post) ? conf.post : this.conf.post;
for (let i = 0; i < intervals.length; i++) {
const currentInterval = intervals[i];
const previousNotMatchingInterval = calculatePreviousNotMatchingInterval(intervals, i);
let previousStr = '';
if (previousNotMatchingInterval !== null) {
previousStr = this.extractSubString(text, previousNotMatchingInterval, conf);
}
const currentStr = this.extractSubString(text, currentInterval, conf);
rendered = `${rendered}${previousStr}${pre}${currentStr}${post}`;
}
// check if the last interval contains the end of the string. Otherwise add it
const lastInterval = intervals[intervals.length - 1];
if (lastInterval.to < text.length - 1) {
rendered = rendered + this.extractSubString(text, { from: lastInterval.to + 1, to: text.length }, conf);
}
return rendered;
}
extractSubString(text, interval, conf) {
const shouldEscape = (conf === null || conf === void 0 ? void 0 : conf.escapeHTML) !== undefined ? conf.escapeHTML : this.conf.escapeHTML;
let str = text.substr(interval.from, intervalSize(interval));
if (shouldEscape) {
str = escapeHTML(str);
}
return str;
}
}
const fuz = new Fuzzy();
export function filter(pattern, list, conf) {
return fuz.filter(pattern, list, conf);
}
export function match(pattern, text, conf) {
return fuz.match(pattern, text, conf);
}
export function render(text, intervals, conf) {
return fuz.render(text, intervals, conf);
}
MIT License
Copyright (c) 2020 Augustin Husson
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+20
-16
{
"name": "@nexucis/fuzzy",
"version": "0.3.0",
"version": "0.4.0",
"description": "small, standalone fuzzy search / fuzzy filter. browser or node",
"main": "index.js",
"module": "dist/index.js",
"main": "dist/cjs/index.js",
"types": "dist/index.d.ts",
"scripts": {
"build": "tsc",
"test": "mocha -r ts-node/register src/**/*.test.ts",
"test-coverage": "nyc mocha -r ts-node/register src/**/*.test.ts",
"build:cjs": "tsc --project ./tsconfig.cjs.json",
"test": "ts-mocha -n loader=ts-node/esm -p tsconfig.cjs.json src/**/*.test.ts",
"test-coverage": "nyc ts-mocha -n loader=ts-node/esm -p tsconfig.cjs.json src/**/*.test.ts",
"codecov": "nyc report --reporter=text-lcov > coverage.lcov && codecov",

@@ -30,16 +33,17 @@ "lint": "eslint src/ --ext .ts",

"devDependencies": {
"@types/chai": "^4.2.12",
"@types/mocha": "^8.0.2",
"@typescript-eslint/eslint-plugin": "^2.22.0",
"@typescript-eslint/parser": "^2.22.0",
"chai": "^4.2.0",
"codecov": "^3.7.2",
"eslint": "^6.0.0",
"eslint-plugin-flowtype": "^5.2.0",
"eslint-plugin-import": "^2.22.0",
"mocha": "^8.1.1",
"@types/chai": "^4.3.1",
"@types/mocha": "^9.1.1",
"@typescript-eslint/eslint-plugin": "^5.25.0",
"@typescript-eslint/parser": "^5.25.0",
"chai": "^4.3.6",
"codecov": "^3.8.3",
"eslint": "^8.15.0",
"eslint-plugin-flowtype": "^8.0.3",
"eslint-plugin-import": "^2.26.0",
"mocha": "^9.2.2",
"nyc": "^15.1.0",
"ts-node": "^8.10.2",
"typescript": "^3.9.7"
"ts-mocha": "^9.0.2",
"ts-node": "^10.7.0",
"typescript": "^4.6.4"
}
}
export declare function score(intervals: FuzzyMatchingInterval[], strLength: number): number;
export interface FuzzyConfiguration {
caseSensitive?: boolean;
includeMatches?: boolean;
shouldSort?: boolean;
escapeHTML?: boolean;
pre?: string;
post?: string;
}
export interface FuzzyMatchingInterval {
from: number;
to: number;
}
export interface FuzzyResult {
rendered: string;
original: string;
index: number;
score: number;
intervals?: FuzzyMatchingInterval[];
}
export declare class Fuzzy {
private readonly conf;
constructor(conf?: FuzzyConfiguration);
filter(pattern: string, list: string[], conf?: FuzzyConfiguration): FuzzyResult[];
match(pattern: string, text: string, conf?: FuzzyConfiguration): FuzzyResult | null;
render(text: string, intervals: FuzzyMatchingInterval[], conf?: FuzzyConfiguration): string;
private extractSubString;
}
export declare function filter(pattern: string, list: string[], conf?: FuzzyConfiguration): FuzzyResult[];
export declare function match(pattern: string, text: string, conf?: FuzzyConfiguration): FuzzyResult | null;
export declare function render(text: string, intervals: FuzzyMatchingInterval[], conf?: FuzzyConfiguration): string;
"use strict";
// MIT License
//
// Copyright (c) 2020 Augustin Husson
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
Object.defineProperty(exports, "__esModule", { value: true });
exports.render = exports.match = exports.filter = exports.Fuzzy = exports.score = void 0;
function escapeHTML(text) {
return text.replace(/[&<>"']/g, (m) => {
switch (m) {
case '&':
return '&amp;';
case '<':
return '&lt;';
case '>':
return '&gt;';
case '"':
return '&quot;';
default:
return '&#039;';
}
});
}
function intervalSize(interval) {
return interval.to - interval.from + 1;
}
function calculatePreviousNotMatchingInterval(intervals, idx) {
const currentInterval = intervals[idx];
let previousNotMatchingInterval = null;
if (idx === 0 && currentInterval.from !== 0) {
previousNotMatchingInterval = { from: 0, to: currentInterval.from - 1 };
}
if (idx > 0) {
previousNotMatchingInterval = { from: intervals[idx - 1].to + 1, to: currentInterval.from - 1 };
}
return previousNotMatchingInterval;
}
// score should be used to calculate the score based on the intervals created during the matching step.
// Here is how the score is determinated:
// 1. Consecutive characters should increase the score more than linearly
// 2. More there is a distance between the characters, higher it reduces the score
// For example, for the pattern 'abc', the following string are sorted by the highest score
// abcdef > defabc > abec > defabec
// Note: this function is exported only for testing purpose.
function score(intervals, strLength) {
let result = 0;
for (let i = 0; i < intervals.length; i++) {
const currentInterval = intervals[i];
const previousNotMatchingInterval = calculatePreviousNotMatchingInterval(intervals, i);
if (previousNotMatchingInterval !== null) {
result = result - intervalSize(previousNotMatchingInterval) / strLength;
}
result = result + Math.pow(intervalSize(currentInterval), 2);
}
return result;
}
exports.score = score;
// generateMatchingInterval will iterate other the given text to find the different char that matched the given pattern
function generateMatchingInterval(pattern, text, idxText) {
let patternIdx = 0;
const intervals = [];
for (let i = idxText; i < text.length && patternIdx < pattern.length;) {
if (text[i] === pattern[patternIdx]) {
const interval = { from: i, to: i };
patternIdx++;
i++;
for (let j = i; j < text.length && patternIdx < pattern.length && text[j] === pattern[patternIdx]; j++) {
interval.to = j;
patternIdx++;
i = j;
}
intervals.push(interval);
}
i++;
}
if (intervals.length === 0 || patternIdx !== pattern.length) {
return null;
}
return { score: score(intervals, text.length), intervals: intervals };
}
class Fuzzy {
constructor(conf) {
this.conf = {
caseSensitive: (conf === null || conf === void 0 ? void 0 : conf.caseSensitive) === undefined ? false : conf.caseSensitive,
includeMatches: (conf === null || conf === void 0 ? void 0 : conf.includeMatches) === undefined ? false : conf.includeMatches,
shouldSort: (conf === null || conf === void 0 ? void 0 : conf.shouldSort) === undefined ? false : conf.shouldSort,
escapeHTML: (conf === null || conf === void 0 ? void 0 : conf.escapeHTML) === undefined ? false : conf.escapeHTML,
pre: (conf === null || conf === void 0 ? void 0 : conf.pre) === undefined ? '' : conf.pre,
post: (conf === null || conf === void 0 ? void 0 : conf.post) === undefined ? '' : conf.post,
};
}
// filter is the method to use to filter a string list
// list of result return can be sort if parameter `shouldSort` is set.
filter(pattern, list, conf) {
const shouldSort = (conf === null || conf === void 0 ? void 0 : conf.shouldSort) !== undefined ? conf.shouldSort : this.conf.shouldSort;
let result = [];
for (let i = 0; i < list.length; i++) {
const matchedText = this.match(pattern, list[i], conf);
if (matchedText !== null) {
matchedText.index = i;
result.push(matchedText);
}
}
if (shouldSort) {
result = result.sort((a, b) => {
return b.score - a.score;
});
}
return result;
}
// match will return a result if `pattern` is matching `text`,
match(pattern, text, conf) {
let localPattern = pattern;
let localText = text;
const caseSensitive = (conf === null || conf === void 0 ? void 0 : conf.caseSensitive) !== undefined ? conf.caseSensitive : this.conf.caseSensitive;
const includeMatches = (conf === null || conf === void 0 ? void 0 : conf.includeMatches) !== undefined ? conf.includeMatches : this.conf.includeMatches;
if (!caseSensitive) {
localPattern = localPattern.toLowerCase();
localText = localText.toLowerCase();
}
// in case it's a perfect match, no need to loop to find which char is matching
if (localPattern === localText) {
const intervals = [{ from: 0, to: pattern.length - 1 }];
const result = {
original: text,
rendered: this.render(text, intervals, conf),
score: Infinity,
};
if (includeMatches) {
result.intervals = intervals;
}
return result;
}
// otherwise let's calculate the different indices that will then be used to calculate the score
let intervals = [];
let score = 0;
for (let i = 0; i < localText.length - localPattern.length + 1; i++) {
// Each time a char is matching the first char of the pattern
// loop other the rest of the text to generate the different matching interval.
// Like that we will be able to find the best matching possibility.
// For example: given the pattern `bac` and the text `babac`
// instead of matching `<ba>ba<c>, it will match ba<bac> which has a better score than the previous one.
if (localText[i] === localPattern[0]) {
const matchingResult = generateMatchingInterval(localPattern, localText, i);
if (matchingResult === null) {
break;
}
if (matchingResult.score > score) {
score = matchingResult.score;
intervals = matchingResult.intervals;
}
}
}
if (intervals.length === 0) {
return null;
}
const result = {
original: text,
rendered: this.render(text, intervals, conf),
score: score,
};
if (includeMatches) {
result.intervals = intervals;
}
return result;
}
// render will modify the text according to the different parameter set in the conf.
// If nothing is set, then it will return the text not modified.
render(text, intervals, conf) {
let rendered = '';
const pre = (conf === null || conf === void 0 ? void 0 : conf.pre) ? conf.pre : this.conf.pre;
const post = (conf === null || conf === void 0 ? void 0 : conf.post) ? conf.post : this.conf.post;
for (let i = 0; i < intervals.length; i++) {
const currentInterval = intervals[i];
const previousNotMatchingInterval = calculatePreviousNotMatchingInterval(intervals, i);
let previousStr = '';
if (previousNotMatchingInterval !== null) {
previousStr = this.extractSubString(text, previousNotMatchingInterval, conf);
}
const currentStr = this.extractSubString(text, currentInterval, conf);
rendered = `${rendered}${previousStr}${pre}${currentStr}${post}`;
}
// check if the last interval contains the end of the string. Otherwise add it
const lastInterval = intervals[intervals.length - 1];
if (lastInterval.to < text.length - 1) {
rendered = rendered + this.extractSubString(text, { from: lastInterval.to + 1, to: text.length }, conf);
}
return rendered;
}
extractSubString(text, interval, conf) {
const shouldEscape = (conf === null || conf === void 0 ? void 0 : conf.escapeHTML) !== undefined ? conf.escapeHTML : this.conf.escapeHTML;
let str = text.substr(interval.from, intervalSize(interval));
if (shouldEscape) {
str = escapeHTML(str);
}
return str;
}
}
exports.Fuzzy = Fuzzy;
const fuz = new Fuzzy();
function filter(pattern, list, conf) {
return fuz.filter(pattern, list, conf);
}
exports.filter = filter;
function match(pattern, text, conf) {
return fuz.match(pattern, text, conf);
}
exports.match = match;
function render(text, intervals, conf) {
return fuz.render(text, intervals, conf);
}
exports.render = render;
//# sourceMappingURL=index.js.map
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}