UNPKG

fuzzyjs

Version:
228 lines (217 loc) 6.64 kB
var __defProp = Object.defineProperty; var __markAsModule = (target) => __defProp(target, "__esModule", { value: true }); var __export = (target, all) => { __markAsModule(target); for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; // src/index.ts __export(exports, { filter: () => filter, match: () => match, sort: () => sort, surround: () => surround, test: () => test }); // src/utils/prepare.ts function reshapeInput(query, source, opts) { if (typeof query !== "string") { throw new TypeError("Expecting query to be a string"); } if (typeof source !== "string") { throw new TypeError("Expecting source to be a string"); } let reshapedQuery = query.normalize("NFD").replace(/[\u0300-\u036f]/g, ""); let reshapedSource = source.normalize("NFD").replace(/[\u0300-\u036f]/g, ""); if (!opts.caseSensitive) { reshapedQuery = reshapedQuery.toLowerCase(); reshapedSource = reshapedSource.toLowerCase(); } return [reshapedQuery, reshapedSource]; } // src/test.ts function test(query, source, opts = {}) { const [reshapedQuery, reshapedSource] = reshapeInput(query, source, opts); if (!reshapedSource.length) { return !query.length; } if (!reshapedQuery.length) { return true; } if (reshapedQuery.length > reshapedSource.length) { return false; } let queryPos = 0; let sourcePos = 0; while (sourcePos < source.length) { const actualSourceCharacter = reshapedSource[sourcePos]; const queryCharacterWaitingForMatch = reshapedQuery[queryPos]; if (actualSourceCharacter === queryCharacterWaitingForMatch) { queryPos += 1; } sourcePos += 1; } return queryPos === reshapedQuery.length; } // src/utils/range.ts function pushRange(ranges, sourcePos) { const lastRange = ranges[ranges.length - 1]; if (lastRange && lastRange.stop === sourcePos) { return [ ...ranges.slice(0, -1), { start: lastRange.start, stop: sourcePos + 1 } ]; } else { return [...ranges, { start: sourcePos, stop: sourcePos + 1 }]; } } // src/score/defaultStrategy.ts function pushScore(previousContext, context) { if (!context) { throw new TypeError("Expecting context to be defined"); } if (!context.match) { return context.currentScore - 1; } let increment = 0; if (previousContext && previousContext.match) { increment += 5; } if (context.leading) { increment += 10; } return context.currentScore + increment; } // src/utils/toLatin.ts function toLatin(str) { return str.normalize("NFD").replace(/[\u0300-\u036f]/g, ""); } // src/utils/isLeading.ts function isLeading(prevChar, char) { const precededBySeparator = prevChar === "-" || prevChar === "_" || prevChar === " " || prevChar === "." || prevChar === "/" || prevChar === "\\"; const isCharLeading = char.toUpperCase() === char && /\w/.test(toLatin(char)); return precededBySeparator || isCharLeading; } // src/match.ts function match(query, source, opts = { withScore: true }) { const [reshapedQuery, reshapedSource] = reshapeInput(query, source, opts); const withScore = !(opts?.withScore === false); if (reshapedSource.length === 0 || reshapedQuery.length === 0) { return { match: query.length === 0, ranges: query.length === 0 ? [{ start: 0, stop: reshapedSource.length }] : [], score: withScore ? query.length === 0 ? 1 : 0 : void 0 }; } if (reshapedQuery.length > reshapedSource.length) { return { match: false, ranges: [], score: withScore ? 0 : void 0 }; } let queryPos = 0; let sourcePos = 0; let score = 0; let lastContext; let ranges = []; while (sourcePos < source.length) { const actualSourceCharacter = reshapedSource[sourcePos]; const queryCharacterWaitingForMatch = reshapedQuery[queryPos]; const match2 = actualSourceCharacter === queryCharacterWaitingForMatch; if (withScore) { const previousCharacter = sourcePos > 0 ? source[sourcePos - 1] : ""; const newContext = { currentScore: score, character: source[sourcePos], match: match2, leading: isLeading(previousCharacter, source[sourcePos]) }; score = pushScore(lastContext, newContext); lastContext = newContext; } if (match2) { ranges = pushRange(ranges, sourcePos); queryPos += 1; } sourcePos += 1; } if (queryPos === reshapedQuery.length) { return { match: true, ranges, score: withScore ? score : void 0 }; } return { match: false, ranges: [], score: withScore ? 0 : void 0 }; } // src/array.ts function filter(query, options) { return function(item) { const source = options.iterator(item); return test(query, source, options); }; } function sort(query, options) { const cacheMap = new Map(); return (leftItem, rightItem) => { const leftSource = options.iterator(leftItem); const rightSource = options.iterator(rightItem); const cachedLeftMatch = cacheMap.get(leftSource); const cachedRightMatch = cacheMap.get(rightSource); const leftScore = cachedLeftMatch ? cachedLeftMatch : match(query, leftSource, { withScore: true, caseSensitive: options.caseSensitive }).score; const rightScore = cachedRightMatch ? cachedRightMatch : match(query, rightSource, { withScore: true, caseSensitive: options.caseSensitive }).score; if (!cacheMap.has(leftSource)) { cacheMap.set(leftSource, leftScore); } if (!cacheMap.has(rightSource)) { cacheMap.set(rightSource, rightScore); } if (rightScore === leftScore) { return 0; } return rightScore > leftScore ? 1 : -1; }; } // src/surround.ts function surround(source, options) { if (typeof source !== "string") { throw new TypeError("Expecting source to be a string"); } if (source.length === 0) { return ""; } if (!options?.result?.ranges?.length) { return source; } let result = source; let accumulator = 0; for (const range of options.result.ranges) { result = insertAt(result, range.start + accumulator, options.prefix); accumulator += (options.prefix ?? "").length; result = insertAt(result, range.stop + accumulator, options.suffix); accumulator += (options.suffix ?? "").length; } return result; } function insertAt(input, index, patch = "") { return input.slice(0, index) + patch + input.slice(index); } // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { filter, match, sort, surround, test }); //# sourceMappingURL=index.js.map