Skip to content

Commit efde652

Browse files
committed
feat(plugin-inquirer): add fuzzy match str util funtion
link #22
1 parent 2c9d0d6 commit efde652

1 file changed

Lines changed: 29 additions & 110 deletions

File tree

  • packages/@cz-git/plugin-inquirer/src/shared/utils
Lines changed: 29 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -1,127 +1,46 @@
11
/**
2-
* Powered by Fuzzy
3-
* https://github.com/myork/fuzzy
4-
*
5-
* Copyright (c) 2012 Matt York
6-
* Licensed under the MIT license.
7-
*
8-
* @description: A standalone fuzzy search / fuzzy filter. provide inquirer usage
2+
* @description: provide list and checkBox fuzzy search
93
* @author: @Zhengqbbb (zhengqbbb@gmail.com)
104
* @license: MIT
115
*/
126

13-
import { FilterFucType, MatchOptions, MatchResult } from "../types";
14-
157
/**
16-
* @description: If `pattern` matches `inputString`, wrap each matching character in `opts.pre`
17-
* and `opts.post`. If no match, return null.
18-
* @param {string} pattern inputString
19-
* @param {string} str targetString
8+
* @description: inputString match targetString return match score
9+
* @param {string} input input string
10+
* @param {string} target target string
11+
* @param {boolean} caseSensitive isCaseSensitive, default: false
12+
* @return {number | null} match score. if not match return null
2013
*/
2114
export const fuzzyMatch = (
22-
pattern: string,
23-
str: string,
24-
opts?: MatchOptions
25-
): MatchResult | null => {
26-
opts = opts || {};
27-
const result = [];
28-
const len = str.length;
29-
// prefix
30-
const pre = opts.pre || "";
31-
// suffix
32-
const post = opts.post || "";
33-
// String to compare against. This might be a lowercase version of the
34-
// raw string
35-
const compareString = (opts.caseSensitive && str) || str.toLowerCase();
36-
let patternIdx = 0,
15+
input: string,
16+
target: string,
17+
caseSensitive?: boolean
18+
): number | null => {
19+
if (typeof input !== "string" || typeof target !== "string") return null;
20+
const matchResult = [];
21+
const len = target.length;
22+
const shimTarget = (caseSensitive && target) || target.toLowerCase();
23+
input = (caseSensitive && input) || input.toLowerCase();
24+
let inputIndex = 0,
3725
totalScore = 0,
38-
currScore = 0,
39-
ch;
40-
41-
pattern = (opts.caseSensitive && pattern) || pattern.toLowerCase();
42-
43-
// For each character in the string, either add it to the result
44-
// or wrap in template if it's the next string in the pattern
26+
currentScore = 0,
27+
currentChar;
4528
for (let idx = 0; idx < len; idx++) {
46-
ch = str[idx];
47-
if (compareString[idx] === pattern[patternIdx]) {
48-
ch = pre + ch + post;
49-
patternIdx += 1;
50-
51-
// consecutive characters should increase the score more than linearly
52-
currScore += 1 + currScore;
29+
currentChar = input[idx];
30+
if (shimTarget[idx] === input[inputIndex]) {
31+
// consecutive matches will score higher
32+
inputIndex += 1;
33+
currentScore += 1 + currentScore;
5334
} else {
54-
currScore = 0;
35+
currentScore = 0;
5536
}
56-
totalScore += currScore;
57-
result[result.length] = ch;
37+
totalScore += currentScore;
38+
matchResult[matchResult.length] = currentChar;
5839
}
59-
60-
// return rendered string if we have a match for every char
61-
if (patternIdx === pattern.length) {
62-
// if the string is an exact match with pattern, totalScore should be maxed
63-
totalScore = compareString === pattern ? Infinity : totalScore;
64-
return { rendered: result.join(""), score: totalScore };
40+
if (inputIndex === input.length) {
41+
totalScore = shimTarget === input ? Infinity : totalScore;
42+
return totalScore;
6543
}
6644

6745
return null;
6846
};
69-
70-
/**
71-
* @description: Does `pattern` fuzzy match `inputString`?
72-
* @param {string} pattern inputString
73-
* @param {string} str targetString
74-
* @return {boolean} isMatch
75-
*/
76-
export const fuzzyTest = (pattern: string, str: string): boolean => {
77-
return fuzzyMatch(pattern, str) !== null;
78-
};
79-
80-
/**
81-
* @description: The normal entry point. Filters `arr` for matches against `pattern`.
82-
* @param {*} pattern inputString
83-
* @param {*} arr targetArray
84-
* @param {*} opts FilterOptions
85-
*/
86-
export const fuzzyFilter: FilterFucType<any> = (pattern, arr, opts?) => {
87-
if (!arr || arr.length === 0) {
88-
return [];
89-
}
90-
if (typeof pattern !== "string") {
91-
return arr;
92-
}
93-
opts = opts || {};
94-
return arr
95-
.reduce(function (prev, element, idx) {
96-
let str = element;
97-
if (opts?.extract) {
98-
str = opts?.extract(element);
99-
}
100-
const rendered = fuzzyMatch(pattern, str, opts);
101-
if (rendered != null) {
102-
prev[prev.length] = {
103-
string: rendered.rendered,
104-
score: rendered.score,
105-
index: idx,
106-
original: element
107-
};
108-
}
109-
return prev;
110-
}, [])
111-
.sort(function (a: any, b: any) {
112-
const compare = b.score - a.score;
113-
if (compare) return compare;
114-
return a.index - b.index;
115-
});
116-
};
117-
118-
/**
119-
* @description: Return all elements of `array` that have a fuzzy match against `pattern`.
120-
* @param {string} pattern inputString
121-
* @param {Array<string>} array targetArray
122-
*/
123-
export const fuzzySimpleFilter = (pattern: string, array: string[]): string[] => {
124-
return array.filter(function (str) {
125-
return fuzzyTest(pattern, str);
126-
});
127-
};

0 commit comments

Comments
 (0)