mirror of
https://github.com/Choices-js/Choices.git
synced 2026-03-14 22:55:46 +01:00
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:
parent
cdb94986a7
commit
9108736808
18 changed files with 184 additions and 72 deletions
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
2
public/assets/scripts/choices.min.js
vendored
2
public/assets/scripts/choices.min.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
3
public/types/src/scripts/search/fuse.d.ts
vendored
Normal file
3
public/types/src/scripts/search/fuse.d.ts
vendored
Normal 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>[];
|
||||
4
public/types/src/scripts/search/index.d.ts
vendored
Normal file
4
public/types/src/scripts/search/index.d.ts
vendored
Normal 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;
|
||||
3
public/types/src/scripts/search/prefix-filter.d.ts
vendored
Normal file
3
public/types/src/scripts/search/prefix-filter.d.ts
vendored
Normal 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>[];
|
||||
4
public/types/src/scripts/search/search-results.d.ts
vendored
Normal file
4
public/types/src/scripts/search/search-results.d.ts
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
export interface SearchResult<T extends object> {
|
||||
item: T;
|
||||
score: number;
|
||||
}
|
||||
|
|
@ -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])
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
22
src/scripts/search/fuse.ts
Normal file
22
src/scripts/search/fuse.ts
Normal 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>[];
|
||||
}
|
||||
19
src/scripts/search/index.ts
Normal file
19
src/scripts/search/index.ts
Normal 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;
|
||||
32
src/scripts/search/prefix-filter.ts
Normal file
32
src/scripts/search/prefix-filter.ts
Normal 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,
|
||||
};
|
||||
});
|
||||
}
|
||||
4
src/scripts/search/search-results.ts
Normal file
4
src/scripts/search/search-results.ts
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
export interface SearchResult<T extends object> {
|
||||
item: T;
|
||||
score: number;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue