Support enabling/disable fuse via build feature flag in favor of a simple prefix search

ie running;
npm run js:build-dev -- --environment SEARCH_FUSE:null
This commit is contained in:
Xon 2024-08-08 13:36:00 +08:00
commit 9108736808
18 changed files with 184 additions and 72 deletions

View file

@ -566,7 +566,7 @@ function convertMaskToIndices(matchmask = [], minMatchCharLength = Config.minMat
// Machine word size
const MAX_BITS = 32;
function search(text, pattern, patternAlphabet, {
function search$2(text, pattern, patternAlphabet, {
location = Config.location,
distance = Config.distance,
threshold = Config.threshold,
@ -820,7 +820,7 @@ class BitapSearch {
isMatch,
score,
indices
} = search(text, pattern, alphabet, {
} = search$2(text, pattern, alphabet, {
location: location + startIndex,
distance,
threshold,
@ -1686,6 +1686,22 @@ Fuse.config = Config;
register(ExtendedSearch);
}
function searchByFuse(config, haystack, needle) {
// todo figure out how to use; `"full" === 'full'` to control how it imports from 'fuse.mjs' or 'fuse.basic.mjs'
// Need to use an object literal for options argument
// see https://github.com/krisk/Fuse/issues/303#issuecomment-506940824
var fuse = new Fuse(haystack, __assign(__assign({}, config.fuseOptions), { keys: __spreadArray([], config.searchFields, true), includeMatches: true }));
var results = fuse.search(needle);
return results;
}
// eslint-disable-next-line import/no-mutable-exports
var search;
{
search = searchByFuse;
}
var search$1 = search;
var addChoice = function (choice) { return ({
type: "ADD_CHOICE" /* ActionType.ADD_CHOICE */,
choice: choice,
@ -4751,13 +4767,7 @@ var Choices = /** @class */ (function () {
}
// If new value matches the desired length and is not the same as the current value with a space
var haystack = this._store.searchableChoices;
var needle = newValue;
var options = Object.assign(this.config.fuseOptions, {
keys: __spreadArray([], this.config.searchFields, true),
includeMatches: true,
});
var fuse = new Fuse(haystack, options);
var results = fuse.search(needle); // see https://github.com/krisk/Fuse/issues/303
var results = search$1(this.config, haystack, newValue);
this._currentValue = newValue;
this._highlightPosition = 0;
this._isSearching = true;

View file

@ -570,7 +570,7 @@
// Machine word size
const MAX_BITS = 32;
function search(text, pattern, patternAlphabet, {
function search$2(text, pattern, patternAlphabet, {
location = Config.location,
distance = Config.distance,
threshold = Config.threshold,
@ -824,7 +824,7 @@
isMatch,
score,
indices
} = search(text, pattern, alphabet, {
} = search$2(text, pattern, alphabet, {
location: location + startIndex,
distance,
threshold,
@ -1690,6 +1690,22 @@
register(ExtendedSearch);
}
function searchByFuse(config, haystack, needle) {
// todo figure out how to use; `"full" === 'full'` to control how it imports from 'fuse.mjs' or 'fuse.basic.mjs'
// Need to use an object literal for options argument
// see https://github.com/krisk/Fuse/issues/303#issuecomment-506940824
var fuse = new Fuse(haystack, __assign(__assign({}, config.fuseOptions), { keys: __spreadArray([], config.searchFields, true), includeMatches: true }));
var results = fuse.search(needle);
return results;
}
// eslint-disable-next-line import/no-mutable-exports
var search;
{
search = searchByFuse;
}
var search$1 = search;
var addChoice = function (choice) { return ({
type: "ADD_CHOICE" /* ActionType.ADD_CHOICE */,
choice: choice,
@ -4755,13 +4771,7 @@
}
// If new value matches the desired length and is not the same as the current value with a space
var haystack = this._store.searchableChoices;
var needle = newValue;
var options = Object.assign(this.config.fuseOptions, {
keys: __spreadArray([], this.config.searchFields, true),
includeMatches: true,
});
var fuse = new Fuse(haystack, options);
var results = fuse.search(needle); // see https://github.com/krisk/Fuse/issues/303
var results = search$1(this.config, haystack, newValue);
this._currentValue = newValue;
this._highlightPosition = 0;
this._isSearching = true;

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -564,7 +564,7 @@ function convertMaskToIndices(matchmask = [], minMatchCharLength = Config.minMat
// Machine word size
const MAX_BITS = 32;
function search(text, pattern, patternAlphabet, {
function search$2(text, pattern, patternAlphabet, {
location = Config.location,
distance = Config.distance,
threshold = Config.threshold,
@ -818,7 +818,7 @@ class BitapSearch {
isMatch,
score,
indices
} = search(text, pattern, alphabet, {
} = search$2(text, pattern, alphabet, {
location: location + startIndex,
distance,
threshold,
@ -1684,6 +1684,22 @@ Fuse.config = Config;
register(ExtendedSearch);
}
function searchByFuse(config, haystack, needle) {
// todo figure out how to use; `"full" === 'full'` to control how it imports from 'fuse.mjs' or 'fuse.basic.mjs'
// Need to use an object literal for options argument
// see https://github.com/krisk/Fuse/issues/303#issuecomment-506940824
var fuse = new Fuse(haystack, __assign(__assign({}, config.fuseOptions), { keys: __spreadArray([], config.searchFields, true), includeMatches: true }));
var results = fuse.search(needle);
return results;
}
// eslint-disable-next-line import/no-mutable-exports
var search;
{
search = searchByFuse;
}
var search$1 = search;
var addChoice = function (choice) { return ({
type: "ADD_CHOICE" /* ActionType.ADD_CHOICE */,
choice: choice,
@ -4749,13 +4765,7 @@ var Choices = /** @class */ (function () {
}
// If new value matches the desired length and is not the same as the current value with a space
var haystack = this._store.searchableChoices;
var needle = newValue;
var options = Object.assign(this.config.fuseOptions, {
keys: __spreadArray([], this.config.searchFields, true),
includeMatches: true,
});
var fuse = new Fuse(haystack, options);
var results = fuse.search(needle); // see https://github.com/krisk/Fuse/issues/303
var results = search$1(this.config, haystack, newValue);
this._currentValue = newValue;
this._highlightPosition = 0;
this._isSearching = true;

View file

@ -1,5 +1,6 @@
import { ChoiceFull } from '../interfaces/choice-full';
import { ActionType } from '../interfaces';
import { SearchResult } from '../search/search-results';
export interface AddChoiceAction {
type: ActionType.ADD_CHOICE;
choice: ChoiceFull;
@ -8,13 +9,9 @@ export interface RemoveChoiceAction {
type: ActionType.REMOVE_CHOICE;
choice: ChoiceFull;
}
export interface Result<T> {
item: T;
score: number;
}
export interface FilterChoicesAction {
type: ActionType.FILTER_CHOICES;
results: Result<ChoiceFull>[];
results: SearchResult<ChoiceFull>[];
}
export interface ActivateChoicesAction {
type: ActionType.ACTIVATE_CHOICES;
@ -25,6 +22,6 @@ export interface ClearChoicesAction {
}
export declare const addChoice: (choice: ChoiceFull) => AddChoiceAction;
export declare const removeChoice: (choice: ChoiceFull) => RemoveChoiceAction;
export declare const filterChoices: (results: Result<ChoiceFull>[]) => FilterChoicesAction;
export declare const filterChoices: (results: SearchResult<ChoiceFull>[]) => FilterChoicesAction;
export declare const activateChoices: (active?: boolean) => ActivateChoicesAction;
export declare const clearChoices: () => ClearChoicesAction;

View file

@ -0,0 +1,3 @@
import { Options } from '../interfaces/options';
import { SearchResult } from './search-results';
export declare function searchByFuse<T extends object>(config: Options, haystack: T[], needle: string): SearchResult<T>[];

View file

@ -0,0 +1,4 @@
import { Options } from '../interfaces';
import { SearchResult } from './search-results';
declare let search: <T extends object>(config: Options, haystack: T[], needle: string) => SearchResult<T>[];
export default search;

View file

@ -0,0 +1,3 @@
import { Options } from '../interfaces';
import { SearchResult } from './search-results';
export declare function searchByPrefixFilter<T extends object>(config: Options, _haystack: T[], _needle: string): SearchResult<T>[];

View file

@ -0,0 +1,4 @@
export interface SearchResult<T extends object> {
item: T;
score: number;
}

View file

@ -9,6 +9,24 @@ import server from './server.mjs';
// @ts-ignore
const pckg = require('../package.json');
const buildFeatures = {
SEARCH_FUSE: "full", // "basic" / "null"
}
// Allow the following to manual set feature flags;
// npm run js:build-dev -- --environment SEARCH_FUSE:null
let defaultBuild = {};
Object.keys(buildFeatures).forEach((k) => {
defaultBuild[k] = process.env[k] || buildFeatures[k];
})
const builds = [
{
name: ".",
features: defaultBuild
},
];
const outputTypes = {
js : {
prefix: 'iife',
@ -54,23 +72,6 @@ if (withDeclarations) {
});
}
const buildFeatures = {
SEARCH: "fuse-full", // "fuse-basic" / ""
}
const builds = [
{
name: ".",
features: {
...buildFeatures,
// ... {
// SEARCH: "fuse-full"
// }
}
},
];
const candidateBuilds = process.env.TARGET
? builds.filter((build) => build.name === process.env.TARGET)
: builds;
@ -87,9 +88,13 @@ function genConfig(buildConfig) {
'process.env.NODE_ENV': JSON.stringify('production')
}
if ('featureFlags' in buildConfig) {
Object.keys(buildConfig.featureFlags).forEach((key) => {
vars[`process.env.${key}`] = JSON.stringify(buildConfig.featureFlags[key])
if ('features' in buildConfig) {
Object.keys(buildConfig.features).forEach((key) => {
if (buildConfig.features[key] === 'undefined' || buildConfig.features[key] === 'null') {
vars[`process.env.${key}`] = false;
} else {
vars[`process.env.${key}`] = JSON.stringify(buildConfig.features[key])
}
})
}

View file

@ -1,5 +1,6 @@
import { ChoiceFull } from '../interfaces/choice-full';
import { ActionType } from '../interfaces';
import { SearchResult } from '../search/search-results';
export interface AddChoiceAction {
type: ActionType.ADD_CHOICE;
@ -11,14 +12,9 @@ export interface RemoveChoiceAction {
choice: ChoiceFull;
}
export interface Result<T> {
item: T;
score: number;
}
export interface FilterChoicesAction {
type: ActionType.FILTER_CHOICES;
results: Result<ChoiceFull>[];
results: SearchResult<ChoiceFull>[];
}
export interface ActivateChoicesAction {
@ -41,7 +37,7 @@ export const removeChoice = (choice: ChoiceFull): RemoveChoiceAction => ({
});
export const filterChoices = (
results: Result<ChoiceFull>[],
results: SearchResult<ChoiceFull>[],
): FilterChoicesAction => ({
type: ActionType.FILTER_CHOICES,
results,

View file

@ -1,5 +1,5 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import Fuse, { IFuseOptions } from 'fuse.js';
import search from './search';
import {
activateChoices,
@ -7,7 +7,6 @@ import {
removeChoice,
clearChoices,
filterChoices,
Result,
} from './actions/choices';
import { addGroup } from './actions/groups';
import { addItem, highlightItem, removeItem } from './actions/items';
@ -1627,13 +1626,7 @@ class Choices implements ChoicesInterface {
// If new value matches the desired length and is not the same as the current value with a space
const haystack = this._store.searchableChoices;
const needle = newValue;
const options = Object.assign(this.config.fuseOptions, {
keys: [...this.config.searchFields],
includeMatches: true,
}) as IFuseOptions<ChoiceFull>;
const fuse = new Fuse(haystack, options);
const results: Result<ChoiceFull>[] = fuse.search(needle) as any[]; // see https://github.com/krisk/Fuse/issues/303
const results = search<ChoiceFull>(this.config, haystack, newValue);
this._currentValue = newValue;
this._highlightPosition = 0;

View file

@ -0,0 +1,22 @@
import Fuse from 'fuse.js';
import { Options } from '../interfaces/options';
import { SearchResult } from './search-results';
export function searchByFuse<T extends object>(
config: Options,
haystack: T[],
needle: string,
): SearchResult<T>[] {
// todo figure out how to use; `process.env.SEARCH_FUSE === 'full'` to control how it imports from 'fuse.mjs' or 'fuse.basic.mjs'
// Need to use an object literal for options argument
// see https://github.com/krisk/Fuse/issues/303#issuecomment-506940824
const fuse = new Fuse<T>(haystack, {
...config.fuseOptions,
keys: [...config.searchFields],
includeMatches: true,
});
const results = fuse.search(needle);
return results as SearchResult<T>[];
}

View file

@ -0,0 +1,19 @@
import { searchByFuse } from './fuse';
import { searchByPrefixFilter } from './prefix-filter';
import { Options } from '../interfaces';
import { SearchResult } from './search-results';
// eslint-disable-next-line import/no-mutable-exports
let search: <T extends object>(
config: Options,
haystack: T[],
needle: string,
) => SearchResult<T>[];
if (process.env.SEARCH_FUSE) {
search = searchByFuse;
} else {
search = searchByPrefixFilter;
}
export default search;

View file

@ -0,0 +1,32 @@
import { Options } from '../interfaces';
import { SearchResult } from './search-results';
export function searchByPrefixFilter<T extends object>(
config: Options,
_haystack: T[],
_needle: string,
): SearchResult<T>[] {
const fields = config.searchFields;
if (!fields || fields.length === 0) {
return [];
}
let haystack = _haystack;
if (_needle !== '') {
const needle = _needle.toLowerCase();
haystack = haystack.filter((obj) =>
fields.some(
(field) =>
field in obj &&
(obj[field] as string).toLowerCase().startsWith(needle),
),
);
}
return haystack.map((value, index): SearchResult<T> => {
return {
item: value,
score: index,
};
});
}

View file

@ -0,0 +1,4 @@
export interface SearchResult<T extends object> {
item: T;
score: number;
}