venue-js 1.3.1 → 1.4.0-next.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +93 -37
- package/dist/index.d.ts +93 -37
- package/dist/index.js +1477 -32
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1484 -39
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -447,6 +447,7 @@ var createPopulator = ({
|
|
|
447
447
|
...amenity.properties,
|
|
448
448
|
ordinal: defaultLevel.properties.ordinal,
|
|
449
449
|
level_name: defaultLevel.properties.name.en,
|
|
450
|
+
level: defaultLevel,
|
|
450
451
|
units: populatedUnits,
|
|
451
452
|
venue,
|
|
452
453
|
_experimental_kiosk: kiosk ? await populateKiosk(kiosk) : null
|
|
@@ -455,6 +456,7 @@ var createPopulator = ({
|
|
|
455
456
|
};
|
|
456
457
|
const populateAnchor = async (anchor) => {
|
|
457
458
|
const unit = await internalFindById(anchor.properties.unit_id);
|
|
459
|
+
const venue = await internalFindById(unit.properties.venue_id);
|
|
458
460
|
const level = await internalFindById(unit.properties.level_id);
|
|
459
461
|
const sections = await internalFilterByType("section");
|
|
460
462
|
const section = sections.find((section2) => (0, import_boolean_within.booleanWithin)(anchor, section2));
|
|
@@ -464,7 +466,9 @@ var createPopulator = ({
|
|
|
464
466
|
...anchor.properties,
|
|
465
467
|
level: await populateLevel(level),
|
|
466
468
|
unit: await populateUnit(unit),
|
|
467
|
-
section: section ? await populateSection(section) : null
|
|
469
|
+
section: section ? await populateSection(section) : null,
|
|
470
|
+
venue: await populateVenue(venue),
|
|
471
|
+
ordinal: level.properties.ordinal
|
|
468
472
|
}
|
|
469
473
|
};
|
|
470
474
|
};
|
|
@@ -531,8 +535,8 @@ var createPopulator = ({
|
|
|
531
535
|
anchor_id,
|
|
532
536
|
venue_id,
|
|
533
537
|
local_category_ids,
|
|
534
|
-
promotion_ids,
|
|
535
|
-
privilege_ids,
|
|
538
|
+
promotion_ids = [],
|
|
539
|
+
privilege_ids = [],
|
|
536
540
|
kiosk_id,
|
|
537
541
|
unit_id,
|
|
538
542
|
kiosk_ids = [],
|
|
@@ -629,6 +633,20 @@ var createPopulator = ({
|
|
|
629
633
|
}
|
|
630
634
|
};
|
|
631
635
|
};
|
|
636
|
+
const populateModel3D = async (model3d) => {
|
|
637
|
+
const level = await internalFindById(model3d.properties.level_id);
|
|
638
|
+
try {
|
|
639
|
+
return {
|
|
640
|
+
...model3d,
|
|
641
|
+
properties: {
|
|
642
|
+
...model3d.properties,
|
|
643
|
+
level: await populateLevel(level)
|
|
644
|
+
}
|
|
645
|
+
};
|
|
646
|
+
} catch (err) {
|
|
647
|
+
console.log(`error finding level`, { model3d, level });
|
|
648
|
+
}
|
|
649
|
+
};
|
|
632
650
|
const populateFeature = (feature2) => Promise.resolve(feature2);
|
|
633
651
|
return {
|
|
634
652
|
address: populateAddress,
|
|
@@ -653,12 +671,1378 @@ var createPopulator = ({
|
|
|
653
671
|
section: populateSection,
|
|
654
672
|
unit: populateUnit,
|
|
655
673
|
venue: populateVenue,
|
|
656
|
-
taxonomy: populateTaxonomy
|
|
674
|
+
taxonomy: populateTaxonomy,
|
|
675
|
+
model3d: populateModel3D
|
|
676
|
+
};
|
|
677
|
+
};
|
|
678
|
+
|
|
679
|
+
// ../../node_modules/fuse.js/dist/fuse.mjs
|
|
680
|
+
function isArray(value) {
|
|
681
|
+
return !Array.isArray ? getTag(value) === "[object Array]" : Array.isArray(value);
|
|
682
|
+
}
|
|
683
|
+
var INFINITY = 1 / 0;
|
|
684
|
+
function baseToString(value) {
|
|
685
|
+
if (typeof value == "string") {
|
|
686
|
+
return value;
|
|
687
|
+
}
|
|
688
|
+
let result = value + "";
|
|
689
|
+
return result == "0" && 1 / value == -INFINITY ? "-0" : result;
|
|
690
|
+
}
|
|
691
|
+
function toString(value) {
|
|
692
|
+
return value == null ? "" : baseToString(value);
|
|
693
|
+
}
|
|
694
|
+
function isString(value) {
|
|
695
|
+
return typeof value === "string";
|
|
696
|
+
}
|
|
697
|
+
function isNumber(value) {
|
|
698
|
+
return typeof value === "number";
|
|
699
|
+
}
|
|
700
|
+
function isBoolean(value) {
|
|
701
|
+
return value === true || value === false || isObjectLike(value) && getTag(value) == "[object Boolean]";
|
|
702
|
+
}
|
|
703
|
+
function isObject(value) {
|
|
704
|
+
return typeof value === "object";
|
|
705
|
+
}
|
|
706
|
+
function isObjectLike(value) {
|
|
707
|
+
return isObject(value) && value !== null;
|
|
708
|
+
}
|
|
709
|
+
function isDefined(value) {
|
|
710
|
+
return value !== void 0 && value !== null;
|
|
711
|
+
}
|
|
712
|
+
function isBlank(value) {
|
|
713
|
+
return !value.trim().length;
|
|
714
|
+
}
|
|
715
|
+
function getTag(value) {
|
|
716
|
+
return value == null ? value === void 0 ? "[object Undefined]" : "[object Null]" : Object.prototype.toString.call(value);
|
|
717
|
+
}
|
|
718
|
+
var INCORRECT_INDEX_TYPE = "Incorrect 'index' type";
|
|
719
|
+
var LOGICAL_SEARCH_INVALID_QUERY_FOR_KEY = (key) => `Invalid value for key ${key}`;
|
|
720
|
+
var PATTERN_LENGTH_TOO_LARGE = (max2) => `Pattern length exceeds max of ${max2}.`;
|
|
721
|
+
var MISSING_KEY_PROPERTY = (name) => `Missing ${name} property in key`;
|
|
722
|
+
var INVALID_KEY_WEIGHT_VALUE = (key) => `Property 'weight' in key '${key}' must be a positive integer`;
|
|
723
|
+
var hasOwn = Object.prototype.hasOwnProperty;
|
|
724
|
+
var KeyStore = class {
|
|
725
|
+
constructor(keys) {
|
|
726
|
+
this._keys = [];
|
|
727
|
+
this._keyMap = {};
|
|
728
|
+
let totalWeight = 0;
|
|
729
|
+
keys.forEach((key) => {
|
|
730
|
+
let obj = createKey(key);
|
|
731
|
+
this._keys.push(obj);
|
|
732
|
+
this._keyMap[obj.id] = obj;
|
|
733
|
+
totalWeight += obj.weight;
|
|
734
|
+
});
|
|
735
|
+
this._keys.forEach((key) => {
|
|
736
|
+
key.weight /= totalWeight;
|
|
737
|
+
});
|
|
738
|
+
}
|
|
739
|
+
get(keyId) {
|
|
740
|
+
return this._keyMap[keyId];
|
|
741
|
+
}
|
|
742
|
+
keys() {
|
|
743
|
+
return this._keys;
|
|
744
|
+
}
|
|
745
|
+
toJSON() {
|
|
746
|
+
return JSON.stringify(this._keys);
|
|
747
|
+
}
|
|
748
|
+
};
|
|
749
|
+
function createKey(key) {
|
|
750
|
+
let path = null;
|
|
751
|
+
let id = null;
|
|
752
|
+
let src = null;
|
|
753
|
+
let weight = 1;
|
|
754
|
+
let getFn = null;
|
|
755
|
+
if (isString(key) || isArray(key)) {
|
|
756
|
+
src = key;
|
|
757
|
+
path = createKeyPath(key);
|
|
758
|
+
id = createKeyId(key);
|
|
759
|
+
} else {
|
|
760
|
+
if (!hasOwn.call(key, "name")) {
|
|
761
|
+
throw new Error(MISSING_KEY_PROPERTY("name"));
|
|
762
|
+
}
|
|
763
|
+
const name = key.name;
|
|
764
|
+
src = name;
|
|
765
|
+
if (hasOwn.call(key, "weight")) {
|
|
766
|
+
weight = key.weight;
|
|
767
|
+
if (weight <= 0) {
|
|
768
|
+
throw new Error(INVALID_KEY_WEIGHT_VALUE(name));
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
path = createKeyPath(name);
|
|
772
|
+
id = createKeyId(name);
|
|
773
|
+
getFn = key.getFn;
|
|
774
|
+
}
|
|
775
|
+
return { path, id, weight, src, getFn };
|
|
776
|
+
}
|
|
777
|
+
function createKeyPath(key) {
|
|
778
|
+
return isArray(key) ? key : key.split(".");
|
|
779
|
+
}
|
|
780
|
+
function createKeyId(key) {
|
|
781
|
+
return isArray(key) ? key.join(".") : key;
|
|
782
|
+
}
|
|
783
|
+
function get(obj, path) {
|
|
784
|
+
let list = [];
|
|
785
|
+
let arr = false;
|
|
786
|
+
const deepGet = (obj2, path2, index) => {
|
|
787
|
+
if (!isDefined(obj2)) {
|
|
788
|
+
return;
|
|
789
|
+
}
|
|
790
|
+
if (!path2[index]) {
|
|
791
|
+
list.push(obj2);
|
|
792
|
+
} else {
|
|
793
|
+
let key = path2[index];
|
|
794
|
+
const value = obj2[key];
|
|
795
|
+
if (!isDefined(value)) {
|
|
796
|
+
return;
|
|
797
|
+
}
|
|
798
|
+
if (index === path2.length - 1 && (isString(value) || isNumber(value) || isBoolean(value))) {
|
|
799
|
+
list.push(toString(value));
|
|
800
|
+
} else if (isArray(value)) {
|
|
801
|
+
arr = true;
|
|
802
|
+
for (let i = 0, len = value.length; i < len; i += 1) {
|
|
803
|
+
deepGet(value[i], path2, index + 1);
|
|
804
|
+
}
|
|
805
|
+
} else if (path2.length) {
|
|
806
|
+
deepGet(value, path2, index + 1);
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
};
|
|
810
|
+
deepGet(obj, isString(path) ? path.split(".") : path, 0);
|
|
811
|
+
return arr ? list : list[0];
|
|
812
|
+
}
|
|
813
|
+
var MatchOptions = {
|
|
814
|
+
// Whether the matches should be included in the result set. When `true`, each record in the result
|
|
815
|
+
// set will include the indices of the matched characters.
|
|
816
|
+
// These can consequently be used for highlighting purposes.
|
|
817
|
+
includeMatches: false,
|
|
818
|
+
// When `true`, the matching function will continue to the end of a search pattern even if
|
|
819
|
+
// a perfect match has already been located in the string.
|
|
820
|
+
findAllMatches: false,
|
|
821
|
+
// Minimum number of characters that must be matched before a result is considered a match
|
|
822
|
+
minMatchCharLength: 1
|
|
823
|
+
};
|
|
824
|
+
var BasicOptions = {
|
|
825
|
+
// When `true`, the algorithm continues searching to the end of the input even if a perfect
|
|
826
|
+
// match is found before the end of the same input.
|
|
827
|
+
isCaseSensitive: false,
|
|
828
|
+
// When `true`, the algorithm will ignore diacritics (accents) in comparisons
|
|
829
|
+
ignoreDiacritics: false,
|
|
830
|
+
// When true, the matching function will continue to the end of a search pattern even if
|
|
831
|
+
includeScore: false,
|
|
832
|
+
// List of properties that will be searched. This also supports nested properties.
|
|
833
|
+
keys: [],
|
|
834
|
+
// Whether to sort the result list, by score
|
|
835
|
+
shouldSort: true,
|
|
836
|
+
// Default sort function: sort by ascending score, ascending index
|
|
837
|
+
sortFn: (a, b) => a.score === b.score ? a.idx < b.idx ? -1 : 1 : a.score < b.score ? -1 : 1
|
|
838
|
+
};
|
|
839
|
+
var FuzzyOptions = {
|
|
840
|
+
// Approximately where in the text is the pattern expected to be found?
|
|
841
|
+
location: 0,
|
|
842
|
+
// At what point does the match algorithm give up. A threshold of '0.0' requires a perfect match
|
|
843
|
+
// (of both letters and location), a threshold of '1.0' would match anything.
|
|
844
|
+
threshold: 0.6,
|
|
845
|
+
// Determines how close the match must be to the fuzzy location (specified above).
|
|
846
|
+
// An exact letter match which is 'distance' characters away from the fuzzy location
|
|
847
|
+
// would score as a complete mismatch. A distance of '0' requires the match be at
|
|
848
|
+
// the exact location specified, a threshold of '1000' would require a perfect match
|
|
849
|
+
// to be within 800 characters of the fuzzy location to be found using a 0.8 threshold.
|
|
850
|
+
distance: 100
|
|
851
|
+
};
|
|
852
|
+
var AdvancedOptions = {
|
|
853
|
+
// When `true`, it enables the use of unix-like search commands
|
|
854
|
+
useExtendedSearch: false,
|
|
855
|
+
// The get function to use when fetching an object's properties.
|
|
856
|
+
// The default will search nested paths *ie foo.bar.baz*
|
|
857
|
+
getFn: get,
|
|
858
|
+
// When `true`, search will ignore `location` and `distance`, so it won't matter
|
|
859
|
+
// where in the string the pattern appears.
|
|
860
|
+
// More info: https://fusejs.io/concepts/scoring-theory.html#fuzziness-score
|
|
861
|
+
ignoreLocation: false,
|
|
862
|
+
// When `true`, the calculation for the relevance score (used for sorting) will
|
|
863
|
+
// ignore the field-length norm.
|
|
864
|
+
// More info: https://fusejs.io/concepts/scoring-theory.html#field-length-norm
|
|
865
|
+
ignoreFieldNorm: false,
|
|
866
|
+
// The weight to determine how much field length norm effects scoring.
|
|
867
|
+
fieldNormWeight: 1
|
|
868
|
+
};
|
|
869
|
+
var Config = {
|
|
870
|
+
...BasicOptions,
|
|
871
|
+
...MatchOptions,
|
|
872
|
+
...FuzzyOptions,
|
|
873
|
+
...AdvancedOptions
|
|
874
|
+
};
|
|
875
|
+
var SPACE = /[^ ]+/g;
|
|
876
|
+
function norm(weight = 1, mantissa = 3) {
|
|
877
|
+
const cache = /* @__PURE__ */ new Map();
|
|
878
|
+
const m = Math.pow(10, mantissa);
|
|
879
|
+
return {
|
|
880
|
+
get(value) {
|
|
881
|
+
const numTokens = value.match(SPACE).length;
|
|
882
|
+
if (cache.has(numTokens)) {
|
|
883
|
+
return cache.get(numTokens);
|
|
884
|
+
}
|
|
885
|
+
const norm2 = 1 / Math.pow(numTokens, 0.5 * weight);
|
|
886
|
+
const n = parseFloat(Math.round(norm2 * m) / m);
|
|
887
|
+
cache.set(numTokens, n);
|
|
888
|
+
return n;
|
|
889
|
+
},
|
|
890
|
+
clear() {
|
|
891
|
+
cache.clear();
|
|
892
|
+
}
|
|
893
|
+
};
|
|
894
|
+
}
|
|
895
|
+
var FuseIndex = class {
|
|
896
|
+
constructor({
|
|
897
|
+
getFn = Config.getFn,
|
|
898
|
+
fieldNormWeight = Config.fieldNormWeight
|
|
899
|
+
} = {}) {
|
|
900
|
+
this.norm = norm(fieldNormWeight, 3);
|
|
901
|
+
this.getFn = getFn;
|
|
902
|
+
this.isCreated = false;
|
|
903
|
+
this.setIndexRecords();
|
|
904
|
+
}
|
|
905
|
+
setSources(docs = []) {
|
|
906
|
+
this.docs = docs;
|
|
907
|
+
}
|
|
908
|
+
setIndexRecords(records = []) {
|
|
909
|
+
this.records = records;
|
|
910
|
+
}
|
|
911
|
+
setKeys(keys = []) {
|
|
912
|
+
this.keys = keys;
|
|
913
|
+
this._keysMap = {};
|
|
914
|
+
keys.forEach((key, idx) => {
|
|
915
|
+
this._keysMap[key.id] = idx;
|
|
916
|
+
});
|
|
917
|
+
}
|
|
918
|
+
create() {
|
|
919
|
+
if (this.isCreated || !this.docs.length) {
|
|
920
|
+
return;
|
|
921
|
+
}
|
|
922
|
+
this.isCreated = true;
|
|
923
|
+
if (isString(this.docs[0])) {
|
|
924
|
+
this.docs.forEach((doc, docIndex) => {
|
|
925
|
+
this._addString(doc, docIndex);
|
|
926
|
+
});
|
|
927
|
+
} else {
|
|
928
|
+
this.docs.forEach((doc, docIndex) => {
|
|
929
|
+
this._addObject(doc, docIndex);
|
|
930
|
+
});
|
|
931
|
+
}
|
|
932
|
+
this.norm.clear();
|
|
933
|
+
}
|
|
934
|
+
// Adds a doc to the end of the index
|
|
935
|
+
add(doc) {
|
|
936
|
+
const idx = this.size();
|
|
937
|
+
if (isString(doc)) {
|
|
938
|
+
this._addString(doc, idx);
|
|
939
|
+
} else {
|
|
940
|
+
this._addObject(doc, idx);
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
// Removes the doc at the specified index of the index
|
|
944
|
+
removeAt(idx) {
|
|
945
|
+
this.records.splice(idx, 1);
|
|
946
|
+
for (let i = idx, len = this.size(); i < len; i += 1) {
|
|
947
|
+
this.records[i].i -= 1;
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
getValueForItemAtKeyId(item, keyId) {
|
|
951
|
+
return item[this._keysMap[keyId]];
|
|
952
|
+
}
|
|
953
|
+
size() {
|
|
954
|
+
return this.records.length;
|
|
955
|
+
}
|
|
956
|
+
_addString(doc, docIndex) {
|
|
957
|
+
if (!isDefined(doc) || isBlank(doc)) {
|
|
958
|
+
return;
|
|
959
|
+
}
|
|
960
|
+
let record = {
|
|
961
|
+
v: doc,
|
|
962
|
+
i: docIndex,
|
|
963
|
+
n: this.norm.get(doc)
|
|
964
|
+
};
|
|
965
|
+
this.records.push(record);
|
|
966
|
+
}
|
|
967
|
+
_addObject(doc, docIndex) {
|
|
968
|
+
let record = { i: docIndex, $: {} };
|
|
969
|
+
this.keys.forEach((key, keyIndex) => {
|
|
970
|
+
let value = key.getFn ? key.getFn(doc) : this.getFn(doc, key.path);
|
|
971
|
+
if (!isDefined(value)) {
|
|
972
|
+
return;
|
|
973
|
+
}
|
|
974
|
+
if (isArray(value)) {
|
|
975
|
+
let subRecords = [];
|
|
976
|
+
const stack = [{ nestedArrIndex: -1, value }];
|
|
977
|
+
while (stack.length) {
|
|
978
|
+
const { nestedArrIndex, value: value2 } = stack.pop();
|
|
979
|
+
if (!isDefined(value2)) {
|
|
980
|
+
continue;
|
|
981
|
+
}
|
|
982
|
+
if (isString(value2) && !isBlank(value2)) {
|
|
983
|
+
let subRecord = {
|
|
984
|
+
v: value2,
|
|
985
|
+
i: nestedArrIndex,
|
|
986
|
+
n: this.norm.get(value2)
|
|
987
|
+
};
|
|
988
|
+
subRecords.push(subRecord);
|
|
989
|
+
} else if (isArray(value2)) {
|
|
990
|
+
value2.forEach((item, k) => {
|
|
991
|
+
stack.push({
|
|
992
|
+
nestedArrIndex: k,
|
|
993
|
+
value: item
|
|
994
|
+
});
|
|
995
|
+
});
|
|
996
|
+
} else ;
|
|
997
|
+
}
|
|
998
|
+
record.$[keyIndex] = subRecords;
|
|
999
|
+
} else if (isString(value) && !isBlank(value)) {
|
|
1000
|
+
let subRecord = {
|
|
1001
|
+
v: value,
|
|
1002
|
+
n: this.norm.get(value)
|
|
1003
|
+
};
|
|
1004
|
+
record.$[keyIndex] = subRecord;
|
|
1005
|
+
}
|
|
1006
|
+
});
|
|
1007
|
+
this.records.push(record);
|
|
1008
|
+
}
|
|
1009
|
+
toJSON() {
|
|
1010
|
+
return {
|
|
1011
|
+
keys: this.keys,
|
|
1012
|
+
records: this.records
|
|
1013
|
+
};
|
|
1014
|
+
}
|
|
1015
|
+
};
|
|
1016
|
+
function createIndex(keys, docs, { getFn = Config.getFn, fieldNormWeight = Config.fieldNormWeight } = {}) {
|
|
1017
|
+
const myIndex = new FuseIndex({ getFn, fieldNormWeight });
|
|
1018
|
+
myIndex.setKeys(keys.map(createKey));
|
|
1019
|
+
myIndex.setSources(docs);
|
|
1020
|
+
myIndex.create();
|
|
1021
|
+
return myIndex;
|
|
1022
|
+
}
|
|
1023
|
+
function parseIndex(data, { getFn = Config.getFn, fieldNormWeight = Config.fieldNormWeight } = {}) {
|
|
1024
|
+
const { keys, records } = data;
|
|
1025
|
+
const myIndex = new FuseIndex({ getFn, fieldNormWeight });
|
|
1026
|
+
myIndex.setKeys(keys);
|
|
1027
|
+
myIndex.setIndexRecords(records);
|
|
1028
|
+
return myIndex;
|
|
1029
|
+
}
|
|
1030
|
+
function computeScore$1(pattern, {
|
|
1031
|
+
errors = 0,
|
|
1032
|
+
currentLocation = 0,
|
|
1033
|
+
expectedLocation = 0,
|
|
1034
|
+
distance = Config.distance,
|
|
1035
|
+
ignoreLocation = Config.ignoreLocation
|
|
1036
|
+
} = {}) {
|
|
1037
|
+
const accuracy = errors / pattern.length;
|
|
1038
|
+
if (ignoreLocation) {
|
|
1039
|
+
return accuracy;
|
|
1040
|
+
}
|
|
1041
|
+
const proximity = Math.abs(expectedLocation - currentLocation);
|
|
1042
|
+
if (!distance) {
|
|
1043
|
+
return proximity ? 1 : accuracy;
|
|
1044
|
+
}
|
|
1045
|
+
return accuracy + proximity / distance;
|
|
1046
|
+
}
|
|
1047
|
+
function convertMaskToIndices(matchmask = [], minMatchCharLength = Config.minMatchCharLength) {
|
|
1048
|
+
let indices = [];
|
|
1049
|
+
let start = -1;
|
|
1050
|
+
let end = -1;
|
|
1051
|
+
let i = 0;
|
|
1052
|
+
for (let len = matchmask.length; i < len; i += 1) {
|
|
1053
|
+
let match = matchmask[i];
|
|
1054
|
+
if (match && start === -1) {
|
|
1055
|
+
start = i;
|
|
1056
|
+
} else if (!match && start !== -1) {
|
|
1057
|
+
end = i - 1;
|
|
1058
|
+
if (end - start + 1 >= minMatchCharLength) {
|
|
1059
|
+
indices.push([start, end]);
|
|
1060
|
+
}
|
|
1061
|
+
start = -1;
|
|
1062
|
+
}
|
|
1063
|
+
}
|
|
1064
|
+
if (matchmask[i - 1] && i - start >= minMatchCharLength) {
|
|
1065
|
+
indices.push([start, i - 1]);
|
|
1066
|
+
}
|
|
1067
|
+
return indices;
|
|
1068
|
+
}
|
|
1069
|
+
var MAX_BITS = 32;
|
|
1070
|
+
function search(text, pattern, patternAlphabet, {
|
|
1071
|
+
location = Config.location,
|
|
1072
|
+
distance = Config.distance,
|
|
1073
|
+
threshold = Config.threshold,
|
|
1074
|
+
findAllMatches = Config.findAllMatches,
|
|
1075
|
+
minMatchCharLength = Config.minMatchCharLength,
|
|
1076
|
+
includeMatches = Config.includeMatches,
|
|
1077
|
+
ignoreLocation = Config.ignoreLocation
|
|
1078
|
+
} = {}) {
|
|
1079
|
+
if (pattern.length > MAX_BITS) {
|
|
1080
|
+
throw new Error(PATTERN_LENGTH_TOO_LARGE(MAX_BITS));
|
|
1081
|
+
}
|
|
1082
|
+
const patternLen = pattern.length;
|
|
1083
|
+
const textLen = text.length;
|
|
1084
|
+
const expectedLocation = Math.max(0, Math.min(location, textLen));
|
|
1085
|
+
let currentThreshold = threshold;
|
|
1086
|
+
let bestLocation = expectedLocation;
|
|
1087
|
+
const computeMatches = minMatchCharLength > 1 || includeMatches;
|
|
1088
|
+
const matchMask = computeMatches ? Array(textLen) : [];
|
|
1089
|
+
let index;
|
|
1090
|
+
while ((index = text.indexOf(pattern, bestLocation)) > -1) {
|
|
1091
|
+
let score = computeScore$1(pattern, {
|
|
1092
|
+
currentLocation: index,
|
|
1093
|
+
expectedLocation,
|
|
1094
|
+
distance,
|
|
1095
|
+
ignoreLocation
|
|
1096
|
+
});
|
|
1097
|
+
currentThreshold = Math.min(score, currentThreshold);
|
|
1098
|
+
bestLocation = index + patternLen;
|
|
1099
|
+
if (computeMatches) {
|
|
1100
|
+
let i = 0;
|
|
1101
|
+
while (i < patternLen) {
|
|
1102
|
+
matchMask[index + i] = 1;
|
|
1103
|
+
i += 1;
|
|
1104
|
+
}
|
|
1105
|
+
}
|
|
1106
|
+
}
|
|
1107
|
+
bestLocation = -1;
|
|
1108
|
+
let lastBitArr = [];
|
|
1109
|
+
let finalScore = 1;
|
|
1110
|
+
let binMax = patternLen + textLen;
|
|
1111
|
+
const mask = 1 << patternLen - 1;
|
|
1112
|
+
for (let i = 0; i < patternLen; i += 1) {
|
|
1113
|
+
let binMin = 0;
|
|
1114
|
+
let binMid = binMax;
|
|
1115
|
+
while (binMin < binMid) {
|
|
1116
|
+
const score2 = computeScore$1(pattern, {
|
|
1117
|
+
errors: i,
|
|
1118
|
+
currentLocation: expectedLocation + binMid,
|
|
1119
|
+
expectedLocation,
|
|
1120
|
+
distance,
|
|
1121
|
+
ignoreLocation
|
|
1122
|
+
});
|
|
1123
|
+
if (score2 <= currentThreshold) {
|
|
1124
|
+
binMin = binMid;
|
|
1125
|
+
} else {
|
|
1126
|
+
binMax = binMid;
|
|
1127
|
+
}
|
|
1128
|
+
binMid = Math.floor((binMax - binMin) / 2 + binMin);
|
|
1129
|
+
}
|
|
1130
|
+
binMax = binMid;
|
|
1131
|
+
let start = Math.max(1, expectedLocation - binMid + 1);
|
|
1132
|
+
let finish = findAllMatches ? textLen : Math.min(expectedLocation + binMid, textLen) + patternLen;
|
|
1133
|
+
let bitArr = Array(finish + 2);
|
|
1134
|
+
bitArr[finish + 1] = (1 << i) - 1;
|
|
1135
|
+
for (let j = finish; j >= start; j -= 1) {
|
|
1136
|
+
let currentLocation = j - 1;
|
|
1137
|
+
let charMatch = patternAlphabet[text.charAt(currentLocation)];
|
|
1138
|
+
if (computeMatches) {
|
|
1139
|
+
matchMask[currentLocation] = +!!charMatch;
|
|
1140
|
+
}
|
|
1141
|
+
bitArr[j] = (bitArr[j + 1] << 1 | 1) & charMatch;
|
|
1142
|
+
if (i) {
|
|
1143
|
+
bitArr[j] |= (lastBitArr[j + 1] | lastBitArr[j]) << 1 | 1 | lastBitArr[j + 1];
|
|
1144
|
+
}
|
|
1145
|
+
if (bitArr[j] & mask) {
|
|
1146
|
+
finalScore = computeScore$1(pattern, {
|
|
1147
|
+
errors: i,
|
|
1148
|
+
currentLocation,
|
|
1149
|
+
expectedLocation,
|
|
1150
|
+
distance,
|
|
1151
|
+
ignoreLocation
|
|
1152
|
+
});
|
|
1153
|
+
if (finalScore <= currentThreshold) {
|
|
1154
|
+
currentThreshold = finalScore;
|
|
1155
|
+
bestLocation = currentLocation;
|
|
1156
|
+
if (bestLocation <= expectedLocation) {
|
|
1157
|
+
break;
|
|
1158
|
+
}
|
|
1159
|
+
start = Math.max(1, 2 * expectedLocation - bestLocation);
|
|
1160
|
+
}
|
|
1161
|
+
}
|
|
1162
|
+
}
|
|
1163
|
+
const score = computeScore$1(pattern, {
|
|
1164
|
+
errors: i + 1,
|
|
1165
|
+
currentLocation: expectedLocation,
|
|
1166
|
+
expectedLocation,
|
|
1167
|
+
distance,
|
|
1168
|
+
ignoreLocation
|
|
1169
|
+
});
|
|
1170
|
+
if (score > currentThreshold) {
|
|
1171
|
+
break;
|
|
1172
|
+
}
|
|
1173
|
+
lastBitArr = bitArr;
|
|
1174
|
+
}
|
|
1175
|
+
const result = {
|
|
1176
|
+
isMatch: bestLocation >= 0,
|
|
1177
|
+
// Count exact matches (those with a score of 0) to be "almost" exact
|
|
1178
|
+
score: Math.max(1e-3, finalScore)
|
|
1179
|
+
};
|
|
1180
|
+
if (computeMatches) {
|
|
1181
|
+
const indices = convertMaskToIndices(matchMask, minMatchCharLength);
|
|
1182
|
+
if (!indices.length) {
|
|
1183
|
+
result.isMatch = false;
|
|
1184
|
+
} else if (includeMatches) {
|
|
1185
|
+
result.indices = indices;
|
|
1186
|
+
}
|
|
1187
|
+
}
|
|
1188
|
+
return result;
|
|
1189
|
+
}
|
|
1190
|
+
function createPatternAlphabet(pattern) {
|
|
1191
|
+
let mask = {};
|
|
1192
|
+
for (let i = 0, len = pattern.length; i < len; i += 1) {
|
|
1193
|
+
const char = pattern.charAt(i);
|
|
1194
|
+
mask[char] = (mask[char] || 0) | 1 << len - i - 1;
|
|
1195
|
+
}
|
|
1196
|
+
return mask;
|
|
1197
|
+
}
|
|
1198
|
+
var stripDiacritics = String.prototype.normalize ? ((str) => str.normalize("NFD").replace(/[\u0300-\u036F\u0483-\u0489\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7\u0610-\u061A\u064B-\u065F\u0670\u06D6-\u06DC\u06DF-\u06E4\u06E7\u06E8\u06EA-\u06ED\u0711\u0730-\u074A\u07A6-\u07B0\u07EB-\u07F3\u07FD\u0816-\u0819\u081B-\u0823\u0825-\u0827\u0829-\u082D\u0859-\u085B\u08D3-\u08E1\u08E3-\u0903\u093A-\u093C\u093E-\u094F\u0951-\u0957\u0962\u0963\u0981-\u0983\u09BC\u09BE-\u09C4\u09C7\u09C8\u09CB-\u09CD\u09D7\u09E2\u09E3\u09FE\u0A01-\u0A03\u0A3C\u0A3E-\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A70\u0A71\u0A75\u0A81-\u0A83\u0ABC\u0ABE-\u0AC5\u0AC7-\u0AC9\u0ACB-\u0ACD\u0AE2\u0AE3\u0AFA-\u0AFF\u0B01-\u0B03\u0B3C\u0B3E-\u0B44\u0B47\u0B48\u0B4B-\u0B4D\u0B56\u0B57\u0B62\u0B63\u0B82\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD7\u0C00-\u0C04\u0C3E-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C62\u0C63\u0C81-\u0C83\u0CBC\u0CBE-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCD\u0CD5\u0CD6\u0CE2\u0CE3\u0D00-\u0D03\u0D3B\u0D3C\u0D3E-\u0D44\u0D46-\u0D48\u0D4A-\u0D4D\u0D57\u0D62\u0D63\u0D82\u0D83\u0DCA\u0DCF-\u0DD4\u0DD6\u0DD8-\u0DDF\u0DF2\u0DF3\u0E31\u0E34-\u0E3A\u0E47-\u0E4E\u0EB1\u0EB4-\u0EB9\u0EBB\u0EBC\u0EC8-\u0ECD\u0F18\u0F19\u0F35\u0F37\u0F39\u0F3E\u0F3F\u0F71-\u0F84\u0F86\u0F87\u0F8D-\u0F97\u0F99-\u0FBC\u0FC6\u102B-\u103E\u1056-\u1059\u105E-\u1060\u1062-\u1064\u1067-\u106D\u1071-\u1074\u1082-\u108D\u108F\u109A-\u109D\u135D-\u135F\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17B4-\u17D3\u17DD\u180B-\u180D\u1885\u1886\u18A9\u1920-\u192B\u1930-\u193B\u1A17-\u1A1B\u1A55-\u1A5E\u1A60-\u1A7C\u1A7F\u1AB0-\u1ABE\u1B00-\u1B04\u1B34-\u1B44\u1B6B-\u1B73\u1B80-\u1B82\u1BA1-\u1BAD\u1BE6-\u1BF3\u1C24-\u1C37\u1CD0-\u1CD2\u1CD4-\u1CE8\u1CED\u1CF2-\u1CF4\u1CF7-\u1CF9\u1DC0-\u1DF9\u1DFB-\u1DFF\u20D0-\u20F0\u2CEF-\u2CF1\u2D7F\u2DE0-\u2DFF\u302A-\u302F\u3099\u309A\uA66F-\uA672\uA674-\uA67D\uA69E\uA69F\uA6F0\uA6F1\uA802\uA806\uA80B\uA823-\uA827\uA880\uA881\uA8B4-\uA8C5\uA8E0-\uA8F1\uA8FF\uA926-\uA92D\uA947-\uA953\uA980-\uA983\uA9B3-\uA9C0\uA9E5\uAA29-\uAA36\uAA43\uAA4C\uAA4D\uAA7B-\uAA7D\uAAB0\uAAB2-\uAAB4\uAAB7\uAAB8\uAABE\uAABF\uAAC1\uAAEB-\uAAEF\uAAF5\uAAF6\uABE3-\uABEA\uABEC\uABED\uFB1E\uFE00-\uFE0F\uFE20-\uFE2F]/g, "")) : ((str) => str);
|
|
1199
|
+
var BitapSearch = class {
|
|
1200
|
+
constructor(pattern, {
|
|
1201
|
+
location = Config.location,
|
|
1202
|
+
threshold = Config.threshold,
|
|
1203
|
+
distance = Config.distance,
|
|
1204
|
+
includeMatches = Config.includeMatches,
|
|
1205
|
+
findAllMatches = Config.findAllMatches,
|
|
1206
|
+
minMatchCharLength = Config.minMatchCharLength,
|
|
1207
|
+
isCaseSensitive = Config.isCaseSensitive,
|
|
1208
|
+
ignoreDiacritics = Config.ignoreDiacritics,
|
|
1209
|
+
ignoreLocation = Config.ignoreLocation
|
|
1210
|
+
} = {}) {
|
|
1211
|
+
this.options = {
|
|
1212
|
+
location,
|
|
1213
|
+
threshold,
|
|
1214
|
+
distance,
|
|
1215
|
+
includeMatches,
|
|
1216
|
+
findAllMatches,
|
|
1217
|
+
minMatchCharLength,
|
|
1218
|
+
isCaseSensitive,
|
|
1219
|
+
ignoreDiacritics,
|
|
1220
|
+
ignoreLocation
|
|
1221
|
+
};
|
|
1222
|
+
pattern = isCaseSensitive ? pattern : pattern.toLowerCase();
|
|
1223
|
+
pattern = ignoreDiacritics ? stripDiacritics(pattern) : pattern;
|
|
1224
|
+
this.pattern = pattern;
|
|
1225
|
+
this.chunks = [];
|
|
1226
|
+
if (!this.pattern.length) {
|
|
1227
|
+
return;
|
|
1228
|
+
}
|
|
1229
|
+
const addChunk = (pattern2, startIndex) => {
|
|
1230
|
+
this.chunks.push({
|
|
1231
|
+
pattern: pattern2,
|
|
1232
|
+
alphabet: createPatternAlphabet(pattern2),
|
|
1233
|
+
startIndex
|
|
1234
|
+
});
|
|
1235
|
+
};
|
|
1236
|
+
const len = this.pattern.length;
|
|
1237
|
+
if (len > MAX_BITS) {
|
|
1238
|
+
let i = 0;
|
|
1239
|
+
const remainder = len % MAX_BITS;
|
|
1240
|
+
const end = len - remainder;
|
|
1241
|
+
while (i < end) {
|
|
1242
|
+
addChunk(this.pattern.substr(i, MAX_BITS), i);
|
|
1243
|
+
i += MAX_BITS;
|
|
1244
|
+
}
|
|
1245
|
+
if (remainder) {
|
|
1246
|
+
const startIndex = len - MAX_BITS;
|
|
1247
|
+
addChunk(this.pattern.substr(startIndex), startIndex);
|
|
1248
|
+
}
|
|
1249
|
+
} else {
|
|
1250
|
+
addChunk(this.pattern, 0);
|
|
1251
|
+
}
|
|
1252
|
+
}
|
|
1253
|
+
searchIn(text) {
|
|
1254
|
+
const { isCaseSensitive, ignoreDiacritics, includeMatches } = this.options;
|
|
1255
|
+
text = isCaseSensitive ? text : text.toLowerCase();
|
|
1256
|
+
text = ignoreDiacritics ? stripDiacritics(text) : text;
|
|
1257
|
+
if (this.pattern === text) {
|
|
1258
|
+
let result2 = {
|
|
1259
|
+
isMatch: true,
|
|
1260
|
+
score: 0
|
|
1261
|
+
};
|
|
1262
|
+
if (includeMatches) {
|
|
1263
|
+
result2.indices = [[0, text.length - 1]];
|
|
1264
|
+
}
|
|
1265
|
+
return result2;
|
|
1266
|
+
}
|
|
1267
|
+
const {
|
|
1268
|
+
location,
|
|
1269
|
+
distance,
|
|
1270
|
+
threshold,
|
|
1271
|
+
findAllMatches,
|
|
1272
|
+
minMatchCharLength,
|
|
1273
|
+
ignoreLocation
|
|
1274
|
+
} = this.options;
|
|
1275
|
+
let allIndices = [];
|
|
1276
|
+
let totalScore = 0;
|
|
1277
|
+
let hasMatches = false;
|
|
1278
|
+
this.chunks.forEach(({ pattern, alphabet, startIndex }) => {
|
|
1279
|
+
const { isMatch, score, indices } = search(text, pattern, alphabet, {
|
|
1280
|
+
location: location + startIndex,
|
|
1281
|
+
distance,
|
|
1282
|
+
threshold,
|
|
1283
|
+
findAllMatches,
|
|
1284
|
+
minMatchCharLength,
|
|
1285
|
+
includeMatches,
|
|
1286
|
+
ignoreLocation
|
|
1287
|
+
});
|
|
1288
|
+
if (isMatch) {
|
|
1289
|
+
hasMatches = true;
|
|
1290
|
+
}
|
|
1291
|
+
totalScore += score;
|
|
1292
|
+
if (isMatch && indices) {
|
|
1293
|
+
allIndices = [...allIndices, ...indices];
|
|
1294
|
+
}
|
|
1295
|
+
});
|
|
1296
|
+
let result = {
|
|
1297
|
+
isMatch: hasMatches,
|
|
1298
|
+
score: hasMatches ? totalScore / this.chunks.length : 1
|
|
1299
|
+
};
|
|
1300
|
+
if (hasMatches && includeMatches) {
|
|
1301
|
+
result.indices = allIndices;
|
|
1302
|
+
}
|
|
1303
|
+
return result;
|
|
1304
|
+
}
|
|
1305
|
+
};
|
|
1306
|
+
var BaseMatch = class {
|
|
1307
|
+
constructor(pattern) {
|
|
1308
|
+
this.pattern = pattern;
|
|
1309
|
+
}
|
|
1310
|
+
static isMultiMatch(pattern) {
|
|
1311
|
+
return getMatch(pattern, this.multiRegex);
|
|
1312
|
+
}
|
|
1313
|
+
static isSingleMatch(pattern) {
|
|
1314
|
+
return getMatch(pattern, this.singleRegex);
|
|
1315
|
+
}
|
|
1316
|
+
search() {
|
|
1317
|
+
}
|
|
1318
|
+
};
|
|
1319
|
+
function getMatch(pattern, exp) {
|
|
1320
|
+
const matches = pattern.match(exp);
|
|
1321
|
+
return matches ? matches[1] : null;
|
|
1322
|
+
}
|
|
1323
|
+
var ExactMatch = class extends BaseMatch {
|
|
1324
|
+
constructor(pattern) {
|
|
1325
|
+
super(pattern);
|
|
1326
|
+
}
|
|
1327
|
+
static get type() {
|
|
1328
|
+
return "exact";
|
|
1329
|
+
}
|
|
1330
|
+
static get multiRegex() {
|
|
1331
|
+
return /^="(.*)"$/;
|
|
1332
|
+
}
|
|
1333
|
+
static get singleRegex() {
|
|
1334
|
+
return /^=(.*)$/;
|
|
1335
|
+
}
|
|
1336
|
+
search(text) {
|
|
1337
|
+
const isMatch = text === this.pattern;
|
|
1338
|
+
return {
|
|
1339
|
+
isMatch,
|
|
1340
|
+
score: isMatch ? 0 : 1,
|
|
1341
|
+
indices: [0, this.pattern.length - 1]
|
|
1342
|
+
};
|
|
1343
|
+
}
|
|
1344
|
+
};
|
|
1345
|
+
var InverseExactMatch = class extends BaseMatch {
|
|
1346
|
+
constructor(pattern) {
|
|
1347
|
+
super(pattern);
|
|
1348
|
+
}
|
|
1349
|
+
static get type() {
|
|
1350
|
+
return "inverse-exact";
|
|
1351
|
+
}
|
|
1352
|
+
static get multiRegex() {
|
|
1353
|
+
return /^!"(.*)"$/;
|
|
1354
|
+
}
|
|
1355
|
+
static get singleRegex() {
|
|
1356
|
+
return /^!(.*)$/;
|
|
1357
|
+
}
|
|
1358
|
+
search(text) {
|
|
1359
|
+
const index = text.indexOf(this.pattern);
|
|
1360
|
+
const isMatch = index === -1;
|
|
1361
|
+
return {
|
|
1362
|
+
isMatch,
|
|
1363
|
+
score: isMatch ? 0 : 1,
|
|
1364
|
+
indices: [0, text.length - 1]
|
|
1365
|
+
};
|
|
1366
|
+
}
|
|
1367
|
+
};
|
|
1368
|
+
var PrefixExactMatch = class extends BaseMatch {
|
|
1369
|
+
constructor(pattern) {
|
|
1370
|
+
super(pattern);
|
|
1371
|
+
}
|
|
1372
|
+
static get type() {
|
|
1373
|
+
return "prefix-exact";
|
|
1374
|
+
}
|
|
1375
|
+
static get multiRegex() {
|
|
1376
|
+
return /^\^"(.*)"$/;
|
|
1377
|
+
}
|
|
1378
|
+
static get singleRegex() {
|
|
1379
|
+
return /^\^(.*)$/;
|
|
1380
|
+
}
|
|
1381
|
+
search(text) {
|
|
1382
|
+
const isMatch = text.startsWith(this.pattern);
|
|
1383
|
+
return {
|
|
1384
|
+
isMatch,
|
|
1385
|
+
score: isMatch ? 0 : 1,
|
|
1386
|
+
indices: [0, this.pattern.length - 1]
|
|
1387
|
+
};
|
|
1388
|
+
}
|
|
1389
|
+
};
|
|
1390
|
+
var InversePrefixExactMatch = class extends BaseMatch {
|
|
1391
|
+
constructor(pattern) {
|
|
1392
|
+
super(pattern);
|
|
1393
|
+
}
|
|
1394
|
+
static get type() {
|
|
1395
|
+
return "inverse-prefix-exact";
|
|
1396
|
+
}
|
|
1397
|
+
static get multiRegex() {
|
|
1398
|
+
return /^!\^"(.*)"$/;
|
|
1399
|
+
}
|
|
1400
|
+
static get singleRegex() {
|
|
1401
|
+
return /^!\^(.*)$/;
|
|
1402
|
+
}
|
|
1403
|
+
search(text) {
|
|
1404
|
+
const isMatch = !text.startsWith(this.pattern);
|
|
1405
|
+
return {
|
|
1406
|
+
isMatch,
|
|
1407
|
+
score: isMatch ? 0 : 1,
|
|
1408
|
+
indices: [0, text.length - 1]
|
|
1409
|
+
};
|
|
1410
|
+
}
|
|
1411
|
+
};
|
|
1412
|
+
var SuffixExactMatch = class extends BaseMatch {
|
|
1413
|
+
constructor(pattern) {
|
|
1414
|
+
super(pattern);
|
|
1415
|
+
}
|
|
1416
|
+
static get type() {
|
|
1417
|
+
return "suffix-exact";
|
|
1418
|
+
}
|
|
1419
|
+
static get multiRegex() {
|
|
1420
|
+
return /^"(.*)"\$$/;
|
|
1421
|
+
}
|
|
1422
|
+
static get singleRegex() {
|
|
1423
|
+
return /^(.*)\$$/;
|
|
1424
|
+
}
|
|
1425
|
+
search(text) {
|
|
1426
|
+
const isMatch = text.endsWith(this.pattern);
|
|
1427
|
+
return {
|
|
1428
|
+
isMatch,
|
|
1429
|
+
score: isMatch ? 0 : 1,
|
|
1430
|
+
indices: [text.length - this.pattern.length, text.length - 1]
|
|
1431
|
+
};
|
|
1432
|
+
}
|
|
1433
|
+
};
|
|
1434
|
+
var InverseSuffixExactMatch = class extends BaseMatch {
|
|
1435
|
+
constructor(pattern) {
|
|
1436
|
+
super(pattern);
|
|
1437
|
+
}
|
|
1438
|
+
static get type() {
|
|
1439
|
+
return "inverse-suffix-exact";
|
|
1440
|
+
}
|
|
1441
|
+
static get multiRegex() {
|
|
1442
|
+
return /^!"(.*)"\$$/;
|
|
1443
|
+
}
|
|
1444
|
+
static get singleRegex() {
|
|
1445
|
+
return /^!(.*)\$$/;
|
|
1446
|
+
}
|
|
1447
|
+
search(text) {
|
|
1448
|
+
const isMatch = !text.endsWith(this.pattern);
|
|
1449
|
+
return {
|
|
1450
|
+
isMatch,
|
|
1451
|
+
score: isMatch ? 0 : 1,
|
|
1452
|
+
indices: [0, text.length - 1]
|
|
1453
|
+
};
|
|
1454
|
+
}
|
|
1455
|
+
};
|
|
1456
|
+
var FuzzyMatch = class extends BaseMatch {
|
|
1457
|
+
constructor(pattern, {
|
|
1458
|
+
location = Config.location,
|
|
1459
|
+
threshold = Config.threshold,
|
|
1460
|
+
distance = Config.distance,
|
|
1461
|
+
includeMatches = Config.includeMatches,
|
|
1462
|
+
findAllMatches = Config.findAllMatches,
|
|
1463
|
+
minMatchCharLength = Config.minMatchCharLength,
|
|
1464
|
+
isCaseSensitive = Config.isCaseSensitive,
|
|
1465
|
+
ignoreDiacritics = Config.ignoreDiacritics,
|
|
1466
|
+
ignoreLocation = Config.ignoreLocation
|
|
1467
|
+
} = {}) {
|
|
1468
|
+
super(pattern);
|
|
1469
|
+
this._bitapSearch = new BitapSearch(pattern, {
|
|
1470
|
+
location,
|
|
1471
|
+
threshold,
|
|
1472
|
+
distance,
|
|
1473
|
+
includeMatches,
|
|
1474
|
+
findAllMatches,
|
|
1475
|
+
minMatchCharLength,
|
|
1476
|
+
isCaseSensitive,
|
|
1477
|
+
ignoreDiacritics,
|
|
1478
|
+
ignoreLocation
|
|
1479
|
+
});
|
|
1480
|
+
}
|
|
1481
|
+
static get type() {
|
|
1482
|
+
return "fuzzy";
|
|
1483
|
+
}
|
|
1484
|
+
static get multiRegex() {
|
|
1485
|
+
return /^"(.*)"$/;
|
|
1486
|
+
}
|
|
1487
|
+
static get singleRegex() {
|
|
1488
|
+
return /^(.*)$/;
|
|
1489
|
+
}
|
|
1490
|
+
search(text) {
|
|
1491
|
+
return this._bitapSearch.searchIn(text);
|
|
1492
|
+
}
|
|
1493
|
+
};
|
|
1494
|
+
var IncludeMatch = class extends BaseMatch {
|
|
1495
|
+
constructor(pattern) {
|
|
1496
|
+
super(pattern);
|
|
1497
|
+
}
|
|
1498
|
+
static get type() {
|
|
1499
|
+
return "include";
|
|
1500
|
+
}
|
|
1501
|
+
static get multiRegex() {
|
|
1502
|
+
return /^'"(.*)"$/;
|
|
1503
|
+
}
|
|
1504
|
+
static get singleRegex() {
|
|
1505
|
+
return /^'(.*)$/;
|
|
1506
|
+
}
|
|
1507
|
+
search(text) {
|
|
1508
|
+
let location = 0;
|
|
1509
|
+
let index;
|
|
1510
|
+
const indices = [];
|
|
1511
|
+
const patternLen = this.pattern.length;
|
|
1512
|
+
while ((index = text.indexOf(this.pattern, location)) > -1) {
|
|
1513
|
+
location = index + patternLen;
|
|
1514
|
+
indices.push([index, location - 1]);
|
|
1515
|
+
}
|
|
1516
|
+
const isMatch = !!indices.length;
|
|
1517
|
+
return {
|
|
1518
|
+
isMatch,
|
|
1519
|
+
score: isMatch ? 0 : 1,
|
|
1520
|
+
indices
|
|
1521
|
+
};
|
|
1522
|
+
}
|
|
1523
|
+
};
|
|
1524
|
+
var searchers = [
|
|
1525
|
+
ExactMatch,
|
|
1526
|
+
IncludeMatch,
|
|
1527
|
+
PrefixExactMatch,
|
|
1528
|
+
InversePrefixExactMatch,
|
|
1529
|
+
InverseSuffixExactMatch,
|
|
1530
|
+
SuffixExactMatch,
|
|
1531
|
+
InverseExactMatch,
|
|
1532
|
+
FuzzyMatch
|
|
1533
|
+
];
|
|
1534
|
+
var searchersLen = searchers.length;
|
|
1535
|
+
var SPACE_RE = / +(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)/;
|
|
1536
|
+
var OR_TOKEN = "|";
|
|
1537
|
+
function parseQuery(pattern, options = {}) {
|
|
1538
|
+
return pattern.split(OR_TOKEN).map((item) => {
|
|
1539
|
+
let query = item.trim().split(SPACE_RE).filter((item2) => item2 && !!item2.trim());
|
|
1540
|
+
let results = [];
|
|
1541
|
+
for (let i = 0, len = query.length; i < len; i += 1) {
|
|
1542
|
+
const queryItem = query[i];
|
|
1543
|
+
let found = false;
|
|
1544
|
+
let idx = -1;
|
|
1545
|
+
while (!found && ++idx < searchersLen) {
|
|
1546
|
+
const searcher = searchers[idx];
|
|
1547
|
+
let token = searcher.isMultiMatch(queryItem);
|
|
1548
|
+
if (token) {
|
|
1549
|
+
results.push(new searcher(token, options));
|
|
1550
|
+
found = true;
|
|
1551
|
+
}
|
|
1552
|
+
}
|
|
1553
|
+
if (found) {
|
|
1554
|
+
continue;
|
|
1555
|
+
}
|
|
1556
|
+
idx = -1;
|
|
1557
|
+
while (++idx < searchersLen) {
|
|
1558
|
+
const searcher = searchers[idx];
|
|
1559
|
+
let token = searcher.isSingleMatch(queryItem);
|
|
1560
|
+
if (token) {
|
|
1561
|
+
results.push(new searcher(token, options));
|
|
1562
|
+
break;
|
|
1563
|
+
}
|
|
1564
|
+
}
|
|
1565
|
+
}
|
|
1566
|
+
return results;
|
|
1567
|
+
});
|
|
1568
|
+
}
|
|
1569
|
+
var MultiMatchSet = /* @__PURE__ */ new Set([FuzzyMatch.type, IncludeMatch.type]);
|
|
1570
|
+
var ExtendedSearch = class {
|
|
1571
|
+
constructor(pattern, {
|
|
1572
|
+
isCaseSensitive = Config.isCaseSensitive,
|
|
1573
|
+
ignoreDiacritics = Config.ignoreDiacritics,
|
|
1574
|
+
includeMatches = Config.includeMatches,
|
|
1575
|
+
minMatchCharLength = Config.minMatchCharLength,
|
|
1576
|
+
ignoreLocation = Config.ignoreLocation,
|
|
1577
|
+
findAllMatches = Config.findAllMatches,
|
|
1578
|
+
location = Config.location,
|
|
1579
|
+
threshold = Config.threshold,
|
|
1580
|
+
distance = Config.distance
|
|
1581
|
+
} = {}) {
|
|
1582
|
+
this.query = null;
|
|
1583
|
+
this.options = {
|
|
1584
|
+
isCaseSensitive,
|
|
1585
|
+
ignoreDiacritics,
|
|
1586
|
+
includeMatches,
|
|
1587
|
+
minMatchCharLength,
|
|
1588
|
+
findAllMatches,
|
|
1589
|
+
ignoreLocation,
|
|
1590
|
+
location,
|
|
1591
|
+
threshold,
|
|
1592
|
+
distance
|
|
1593
|
+
};
|
|
1594
|
+
pattern = isCaseSensitive ? pattern : pattern.toLowerCase();
|
|
1595
|
+
pattern = ignoreDiacritics ? stripDiacritics(pattern) : pattern;
|
|
1596
|
+
this.pattern = pattern;
|
|
1597
|
+
this.query = parseQuery(this.pattern, this.options);
|
|
1598
|
+
}
|
|
1599
|
+
static condition(_6, options) {
|
|
1600
|
+
return options.useExtendedSearch;
|
|
1601
|
+
}
|
|
1602
|
+
searchIn(text) {
|
|
1603
|
+
const query = this.query;
|
|
1604
|
+
if (!query) {
|
|
1605
|
+
return {
|
|
1606
|
+
isMatch: false,
|
|
1607
|
+
score: 1
|
|
1608
|
+
};
|
|
1609
|
+
}
|
|
1610
|
+
const { includeMatches, isCaseSensitive, ignoreDiacritics } = this.options;
|
|
1611
|
+
text = isCaseSensitive ? text : text.toLowerCase();
|
|
1612
|
+
text = ignoreDiacritics ? stripDiacritics(text) : text;
|
|
1613
|
+
let numMatches = 0;
|
|
1614
|
+
let allIndices = [];
|
|
1615
|
+
let totalScore = 0;
|
|
1616
|
+
for (let i = 0, qLen = query.length; i < qLen; i += 1) {
|
|
1617
|
+
const searchers2 = query[i];
|
|
1618
|
+
allIndices.length = 0;
|
|
1619
|
+
numMatches = 0;
|
|
1620
|
+
for (let j = 0, pLen = searchers2.length; j < pLen; j += 1) {
|
|
1621
|
+
const searcher = searchers2[j];
|
|
1622
|
+
const { isMatch, indices, score } = searcher.search(text);
|
|
1623
|
+
if (isMatch) {
|
|
1624
|
+
numMatches += 1;
|
|
1625
|
+
totalScore += score;
|
|
1626
|
+
if (includeMatches) {
|
|
1627
|
+
const type = searcher.constructor.type;
|
|
1628
|
+
if (MultiMatchSet.has(type)) {
|
|
1629
|
+
allIndices = [...allIndices, ...indices];
|
|
1630
|
+
} else {
|
|
1631
|
+
allIndices.push(indices);
|
|
1632
|
+
}
|
|
1633
|
+
}
|
|
1634
|
+
} else {
|
|
1635
|
+
totalScore = 0;
|
|
1636
|
+
numMatches = 0;
|
|
1637
|
+
allIndices.length = 0;
|
|
1638
|
+
break;
|
|
1639
|
+
}
|
|
1640
|
+
}
|
|
1641
|
+
if (numMatches) {
|
|
1642
|
+
let result = {
|
|
1643
|
+
isMatch: true,
|
|
1644
|
+
score: totalScore / numMatches
|
|
1645
|
+
};
|
|
1646
|
+
if (includeMatches) {
|
|
1647
|
+
result.indices = allIndices;
|
|
1648
|
+
}
|
|
1649
|
+
return result;
|
|
1650
|
+
}
|
|
1651
|
+
}
|
|
1652
|
+
return {
|
|
1653
|
+
isMatch: false,
|
|
1654
|
+
score: 1
|
|
1655
|
+
};
|
|
1656
|
+
}
|
|
1657
|
+
};
|
|
1658
|
+
var registeredSearchers = [];
|
|
1659
|
+
function register(...args) {
|
|
1660
|
+
registeredSearchers.push(...args);
|
|
1661
|
+
}
|
|
1662
|
+
function createSearcher(pattern, options) {
|
|
1663
|
+
for (let i = 0, len = registeredSearchers.length; i < len; i += 1) {
|
|
1664
|
+
let searcherClass = registeredSearchers[i];
|
|
1665
|
+
if (searcherClass.condition(pattern, options)) {
|
|
1666
|
+
return new searcherClass(pattern, options);
|
|
1667
|
+
}
|
|
1668
|
+
}
|
|
1669
|
+
return new BitapSearch(pattern, options);
|
|
1670
|
+
}
|
|
1671
|
+
var LogicalOperator = {
|
|
1672
|
+
AND: "$and",
|
|
1673
|
+
OR: "$or"
|
|
1674
|
+
};
|
|
1675
|
+
var KeyType = {
|
|
1676
|
+
PATH: "$path",
|
|
1677
|
+
PATTERN: "$val"
|
|
1678
|
+
};
|
|
1679
|
+
var isExpression = (query) => !!(query[LogicalOperator.AND] || query[LogicalOperator.OR]);
|
|
1680
|
+
var isPath = (query) => !!query[KeyType.PATH];
|
|
1681
|
+
var isLeaf = (query) => !isArray(query) && isObject(query) && !isExpression(query);
|
|
1682
|
+
var convertToExplicit = (query) => ({
|
|
1683
|
+
[LogicalOperator.AND]: Object.keys(query).map((key) => ({
|
|
1684
|
+
[key]: query[key]
|
|
1685
|
+
}))
|
|
1686
|
+
});
|
|
1687
|
+
function parse(query, options, { auto = true } = {}) {
|
|
1688
|
+
const next = (query2) => {
|
|
1689
|
+
let keys = Object.keys(query2);
|
|
1690
|
+
const isQueryPath = isPath(query2);
|
|
1691
|
+
if (!isQueryPath && keys.length > 1 && !isExpression(query2)) {
|
|
1692
|
+
return next(convertToExplicit(query2));
|
|
1693
|
+
}
|
|
1694
|
+
if (isLeaf(query2)) {
|
|
1695
|
+
const key = isQueryPath ? query2[KeyType.PATH] : keys[0];
|
|
1696
|
+
const pattern = isQueryPath ? query2[KeyType.PATTERN] : query2[key];
|
|
1697
|
+
if (!isString(pattern)) {
|
|
1698
|
+
throw new Error(LOGICAL_SEARCH_INVALID_QUERY_FOR_KEY(key));
|
|
1699
|
+
}
|
|
1700
|
+
const obj = {
|
|
1701
|
+
keyId: createKeyId(key),
|
|
1702
|
+
pattern
|
|
1703
|
+
};
|
|
1704
|
+
if (auto) {
|
|
1705
|
+
obj.searcher = createSearcher(pattern, options);
|
|
1706
|
+
}
|
|
1707
|
+
return obj;
|
|
1708
|
+
}
|
|
1709
|
+
let node = {
|
|
1710
|
+
children: [],
|
|
1711
|
+
operator: keys[0]
|
|
1712
|
+
};
|
|
1713
|
+
keys.forEach((key) => {
|
|
1714
|
+
const value = query2[key];
|
|
1715
|
+
if (isArray(value)) {
|
|
1716
|
+
value.forEach((item) => {
|
|
1717
|
+
node.children.push(next(item));
|
|
1718
|
+
});
|
|
1719
|
+
}
|
|
1720
|
+
});
|
|
1721
|
+
return node;
|
|
1722
|
+
};
|
|
1723
|
+
if (!isExpression(query)) {
|
|
1724
|
+
query = convertToExplicit(query);
|
|
1725
|
+
}
|
|
1726
|
+
return next(query);
|
|
1727
|
+
}
|
|
1728
|
+
function computeScore(results, { ignoreFieldNorm = Config.ignoreFieldNorm }) {
|
|
1729
|
+
results.forEach((result) => {
|
|
1730
|
+
let totalScore = 1;
|
|
1731
|
+
result.matches.forEach(({ key, norm: norm2, score }) => {
|
|
1732
|
+
const weight = key ? key.weight : null;
|
|
1733
|
+
totalScore *= Math.pow(
|
|
1734
|
+
score === 0 && weight ? Number.EPSILON : score,
|
|
1735
|
+
(weight || 1) * (ignoreFieldNorm ? 1 : norm2)
|
|
1736
|
+
);
|
|
1737
|
+
});
|
|
1738
|
+
result.score = totalScore;
|
|
1739
|
+
});
|
|
1740
|
+
}
|
|
1741
|
+
function transformMatches(result, data) {
|
|
1742
|
+
const matches = result.matches;
|
|
1743
|
+
data.matches = [];
|
|
1744
|
+
if (!isDefined(matches)) {
|
|
1745
|
+
return;
|
|
1746
|
+
}
|
|
1747
|
+
matches.forEach((match) => {
|
|
1748
|
+
if (!isDefined(match.indices) || !match.indices.length) {
|
|
1749
|
+
return;
|
|
1750
|
+
}
|
|
1751
|
+
const { indices, value } = match;
|
|
1752
|
+
let obj = {
|
|
1753
|
+
indices,
|
|
1754
|
+
value
|
|
1755
|
+
};
|
|
1756
|
+
if (match.key) {
|
|
1757
|
+
obj.key = match.key.src;
|
|
1758
|
+
}
|
|
1759
|
+
if (match.idx > -1) {
|
|
1760
|
+
obj.refIndex = match.idx;
|
|
1761
|
+
}
|
|
1762
|
+
data.matches.push(obj);
|
|
1763
|
+
});
|
|
1764
|
+
}
|
|
1765
|
+
function transformScore(result, data) {
|
|
1766
|
+
data.score = result.score;
|
|
1767
|
+
}
|
|
1768
|
+
function format(results, docs, {
|
|
1769
|
+
includeMatches = Config.includeMatches,
|
|
1770
|
+
includeScore = Config.includeScore
|
|
1771
|
+
} = {}) {
|
|
1772
|
+
const transformers = [];
|
|
1773
|
+
if (includeMatches) transformers.push(transformMatches);
|
|
1774
|
+
if (includeScore) transformers.push(transformScore);
|
|
1775
|
+
return results.map((result) => {
|
|
1776
|
+
const { idx } = result;
|
|
1777
|
+
const data = {
|
|
1778
|
+
item: docs[idx],
|
|
1779
|
+
refIndex: idx
|
|
1780
|
+
};
|
|
1781
|
+
if (transformers.length) {
|
|
1782
|
+
transformers.forEach((transformer) => {
|
|
1783
|
+
transformer(result, data);
|
|
1784
|
+
});
|
|
1785
|
+
}
|
|
1786
|
+
return data;
|
|
1787
|
+
});
|
|
1788
|
+
}
|
|
1789
|
+
var Fuse = class {
|
|
1790
|
+
constructor(docs, options = {}, index) {
|
|
1791
|
+
this.options = { ...Config, ...options };
|
|
1792
|
+
if (this.options.useExtendedSearch && false) {
|
|
1793
|
+
throw new Error(EXTENDED_SEARCH_UNAVAILABLE);
|
|
1794
|
+
}
|
|
1795
|
+
this._keyStore = new KeyStore(this.options.keys);
|
|
1796
|
+
this.setCollection(docs, index);
|
|
1797
|
+
}
|
|
1798
|
+
setCollection(docs, index) {
|
|
1799
|
+
this._docs = docs;
|
|
1800
|
+
if (index && !(index instanceof FuseIndex)) {
|
|
1801
|
+
throw new Error(INCORRECT_INDEX_TYPE);
|
|
1802
|
+
}
|
|
1803
|
+
this._myIndex = index || createIndex(this.options.keys, this._docs, {
|
|
1804
|
+
getFn: this.options.getFn,
|
|
1805
|
+
fieldNormWeight: this.options.fieldNormWeight
|
|
1806
|
+
});
|
|
1807
|
+
}
|
|
1808
|
+
add(doc) {
|
|
1809
|
+
if (!isDefined(doc)) {
|
|
1810
|
+
return;
|
|
1811
|
+
}
|
|
1812
|
+
this._docs.push(doc);
|
|
1813
|
+
this._myIndex.add(doc);
|
|
1814
|
+
}
|
|
1815
|
+
remove(predicate = () => false) {
|
|
1816
|
+
const results = [];
|
|
1817
|
+
for (let i = 0, len = this._docs.length; i < len; i += 1) {
|
|
1818
|
+
const doc = this._docs[i];
|
|
1819
|
+
if (predicate(doc, i)) {
|
|
1820
|
+
this.removeAt(i);
|
|
1821
|
+
i -= 1;
|
|
1822
|
+
len -= 1;
|
|
1823
|
+
results.push(doc);
|
|
1824
|
+
}
|
|
1825
|
+
}
|
|
1826
|
+
return results;
|
|
1827
|
+
}
|
|
1828
|
+
removeAt(idx) {
|
|
1829
|
+
this._docs.splice(idx, 1);
|
|
1830
|
+
this._myIndex.removeAt(idx);
|
|
1831
|
+
}
|
|
1832
|
+
getIndex() {
|
|
1833
|
+
return this._myIndex;
|
|
1834
|
+
}
|
|
1835
|
+
search(query, { limit = -1 } = {}) {
|
|
1836
|
+
const {
|
|
1837
|
+
includeMatches,
|
|
1838
|
+
includeScore,
|
|
1839
|
+
shouldSort,
|
|
1840
|
+
sortFn,
|
|
1841
|
+
ignoreFieldNorm
|
|
1842
|
+
} = this.options;
|
|
1843
|
+
let results = isString(query) ? isString(this._docs[0]) ? this._searchStringList(query) : this._searchObjectList(query) : this._searchLogical(query);
|
|
1844
|
+
computeScore(results, { ignoreFieldNorm });
|
|
1845
|
+
if (shouldSort) {
|
|
1846
|
+
results.sort(sortFn);
|
|
1847
|
+
}
|
|
1848
|
+
if (isNumber(limit) && limit > -1) {
|
|
1849
|
+
results = results.slice(0, limit);
|
|
1850
|
+
}
|
|
1851
|
+
return format(results, this._docs, {
|
|
1852
|
+
includeMatches,
|
|
1853
|
+
includeScore
|
|
1854
|
+
});
|
|
1855
|
+
}
|
|
1856
|
+
_searchStringList(query) {
|
|
1857
|
+
const searcher = createSearcher(query, this.options);
|
|
1858
|
+
const { records } = this._myIndex;
|
|
1859
|
+
const results = [];
|
|
1860
|
+
records.forEach(({ v: text, i: idx, n: norm2 }) => {
|
|
1861
|
+
if (!isDefined(text)) {
|
|
1862
|
+
return;
|
|
1863
|
+
}
|
|
1864
|
+
const { isMatch, score, indices } = searcher.searchIn(text);
|
|
1865
|
+
if (isMatch) {
|
|
1866
|
+
results.push({
|
|
1867
|
+
item: text,
|
|
1868
|
+
idx,
|
|
1869
|
+
matches: [{ score, value: text, norm: norm2, indices }]
|
|
1870
|
+
});
|
|
1871
|
+
}
|
|
1872
|
+
});
|
|
1873
|
+
return results;
|
|
1874
|
+
}
|
|
1875
|
+
_searchLogical(query) {
|
|
1876
|
+
const expression = parse(query, this.options);
|
|
1877
|
+
const evaluate = (node, item, idx) => {
|
|
1878
|
+
if (!node.children) {
|
|
1879
|
+
const { keyId, searcher } = node;
|
|
1880
|
+
const matches = this._findMatches({
|
|
1881
|
+
key: this._keyStore.get(keyId),
|
|
1882
|
+
value: this._myIndex.getValueForItemAtKeyId(item, keyId),
|
|
1883
|
+
searcher
|
|
1884
|
+
});
|
|
1885
|
+
if (matches && matches.length) {
|
|
1886
|
+
return [
|
|
1887
|
+
{
|
|
1888
|
+
idx,
|
|
1889
|
+
item,
|
|
1890
|
+
matches
|
|
1891
|
+
}
|
|
1892
|
+
];
|
|
1893
|
+
}
|
|
1894
|
+
return [];
|
|
1895
|
+
}
|
|
1896
|
+
const res = [];
|
|
1897
|
+
for (let i = 0, len = node.children.length; i < len; i += 1) {
|
|
1898
|
+
const child = node.children[i];
|
|
1899
|
+
const result = evaluate(child, item, idx);
|
|
1900
|
+
if (result.length) {
|
|
1901
|
+
res.push(...result);
|
|
1902
|
+
} else if (node.operator === LogicalOperator.AND) {
|
|
1903
|
+
return [];
|
|
1904
|
+
}
|
|
1905
|
+
}
|
|
1906
|
+
return res;
|
|
1907
|
+
};
|
|
1908
|
+
const records = this._myIndex.records;
|
|
1909
|
+
const resultMap = {};
|
|
1910
|
+
const results = [];
|
|
1911
|
+
records.forEach(({ $: item, i: idx }) => {
|
|
1912
|
+
if (isDefined(item)) {
|
|
1913
|
+
let expResults = evaluate(expression, item, idx);
|
|
1914
|
+
if (expResults.length) {
|
|
1915
|
+
if (!resultMap[idx]) {
|
|
1916
|
+
resultMap[idx] = { idx, item, matches: [] };
|
|
1917
|
+
results.push(resultMap[idx]);
|
|
1918
|
+
}
|
|
1919
|
+
expResults.forEach(({ matches }) => {
|
|
1920
|
+
resultMap[idx].matches.push(...matches);
|
|
1921
|
+
});
|
|
1922
|
+
}
|
|
1923
|
+
}
|
|
1924
|
+
});
|
|
1925
|
+
return results;
|
|
1926
|
+
}
|
|
1927
|
+
_searchObjectList(query) {
|
|
1928
|
+
const searcher = createSearcher(query, this.options);
|
|
1929
|
+
const { keys, records } = this._myIndex;
|
|
1930
|
+
const results = [];
|
|
1931
|
+
records.forEach(({ $: item, i: idx }) => {
|
|
1932
|
+
if (!isDefined(item)) {
|
|
1933
|
+
return;
|
|
1934
|
+
}
|
|
1935
|
+
let matches = [];
|
|
1936
|
+
keys.forEach((key, keyIndex) => {
|
|
1937
|
+
matches.push(
|
|
1938
|
+
...this._findMatches({
|
|
1939
|
+
key,
|
|
1940
|
+
value: item[keyIndex],
|
|
1941
|
+
searcher
|
|
1942
|
+
})
|
|
1943
|
+
);
|
|
1944
|
+
});
|
|
1945
|
+
if (matches.length) {
|
|
1946
|
+
results.push({
|
|
1947
|
+
idx,
|
|
1948
|
+
item,
|
|
1949
|
+
matches
|
|
1950
|
+
});
|
|
1951
|
+
}
|
|
1952
|
+
});
|
|
1953
|
+
return results;
|
|
1954
|
+
}
|
|
1955
|
+
_findMatches({ key, value, searcher }) {
|
|
1956
|
+
if (!isDefined(value)) {
|
|
1957
|
+
return [];
|
|
1958
|
+
}
|
|
1959
|
+
let matches = [];
|
|
1960
|
+
if (isArray(value)) {
|
|
1961
|
+
value.forEach(({ v: text, i: idx, n: norm2 }) => {
|
|
1962
|
+
if (!isDefined(text)) {
|
|
1963
|
+
return;
|
|
1964
|
+
}
|
|
1965
|
+
const { isMatch, score, indices } = searcher.searchIn(text);
|
|
1966
|
+
if (isMatch) {
|
|
1967
|
+
matches.push({
|
|
1968
|
+
score,
|
|
1969
|
+
key,
|
|
1970
|
+
value: text,
|
|
1971
|
+
idx,
|
|
1972
|
+
norm: norm2,
|
|
1973
|
+
indices
|
|
1974
|
+
});
|
|
1975
|
+
}
|
|
1976
|
+
});
|
|
1977
|
+
} else {
|
|
1978
|
+
const { v: text, n: norm2 } = value;
|
|
1979
|
+
const { isMatch, score, indices } = searcher.searchIn(text);
|
|
1980
|
+
if (isMatch) {
|
|
1981
|
+
matches.push({ score, key, value: text, norm: norm2, indices });
|
|
1982
|
+
}
|
|
1983
|
+
}
|
|
1984
|
+
return matches;
|
|
1985
|
+
}
|
|
1986
|
+
};
|
|
1987
|
+
Fuse.version = "7.1.0";
|
|
1988
|
+
Fuse.createIndex = createIndex;
|
|
1989
|
+
Fuse.parseIndex = parseIndex;
|
|
1990
|
+
Fuse.config = Config;
|
|
1991
|
+
{
|
|
1992
|
+
Fuse.parseQuery = parse;
|
|
1993
|
+
}
|
|
1994
|
+
{
|
|
1995
|
+
register(ExtendedSearch);
|
|
1996
|
+
}
|
|
1997
|
+
|
|
1998
|
+
// src/data/search/utils/sanitizeInput.ts
|
|
1999
|
+
var sanitizeInput = (str) => str.replace(/[\u200E\u200F\u202A-\u202E\u2066-\u2069]/g, "").replace(/[\-–—_./()]+/g, "").normalize("NFC").trim();
|
|
2000
|
+
|
|
2001
|
+
// src/data/search/getSearchClient.ts
|
|
2002
|
+
var getSearchClient = ({ occupants, amenities }) => {
|
|
2003
|
+
const fuseAmenities = new Fuse(amenities, { threshold: 0.2 });
|
|
2004
|
+
const fuseOccupants = new Fuse(occupants, {
|
|
2005
|
+
threshold: 0.3,
|
|
2006
|
+
// 0.2 is too strict (can't find Mo-Mo Paradise with "momo" search string)
|
|
2007
|
+
includeScore: true,
|
|
2008
|
+
keys: [
|
|
2009
|
+
{ name: "properties.name", "weight": 4, getFn: (obj) => Object.values(obj.properties.name) },
|
|
2010
|
+
{ name: "properties.category", "weight": 0.25 },
|
|
2011
|
+
{
|
|
2012
|
+
name: "properties.local_categories",
|
|
2013
|
+
"weight": 0.25,
|
|
2014
|
+
getFn: (occ) => occ.properties.local_categories.map((cat3) => Object.values(cat3.properties.name)).flat()
|
|
2015
|
+
},
|
|
2016
|
+
{ name: "properties.keywords", "weight": 0.25 },
|
|
2017
|
+
{ name: "properties.description", "weight": 0.25, getFn: (occ) => Object.values(occ.properties.description || {}) },
|
|
2018
|
+
{ name: "properties.unit.properties.name", "weight": 0.25, getFn: (obj) => Object.values(obj.properties.unit?.properties.name || {}) },
|
|
2019
|
+
{ name: "properties.kiosk.properties.name", "weight": 0.25, getFn: (obj) => Object.values(obj.properties.kiosk?.properties.name || {}) }
|
|
2020
|
+
]
|
|
2021
|
+
});
|
|
2022
|
+
const fuseFuzzyAmenities = new Fuse(amenities, {
|
|
2023
|
+
threshold: 0.2,
|
|
2024
|
+
keys: [
|
|
2025
|
+
{ name: "properties.category", weight: 4 }
|
|
2026
|
+
]
|
|
2027
|
+
});
|
|
2028
|
+
const search2 = (value) => {
|
|
2029
|
+
const sanitizedValue = sanitizeInput(value);
|
|
2030
|
+
const matchedAmenities = fuseAmenities.search(sanitizedValue);
|
|
2031
|
+
if (matchedAmenities.length > 0) return matchedAmenities;
|
|
2032
|
+
const matchedOccupants = fuseOccupants.search(sanitizedValue);
|
|
2033
|
+
if (matchedOccupants.length > 0) return matchedOccupants;
|
|
2034
|
+
const matchedFuzzyAmenities = fuseFuzzyAmenities.search(sanitizedValue);
|
|
2035
|
+
if (matchedFuzzyAmenities.length > 0) return matchedFuzzyAmenities;
|
|
2036
|
+
return [];
|
|
2037
|
+
};
|
|
2038
|
+
return {
|
|
2039
|
+
search: search2
|
|
657
2040
|
};
|
|
658
2041
|
};
|
|
659
2042
|
|
|
660
2043
|
// src/data/getDataClient.ts
|
|
661
2044
|
var getDataClient = (options) => {
|
|
2045
|
+
let searchClient;
|
|
662
2046
|
const observers = /* @__PURE__ */ new Map();
|
|
663
2047
|
const queryClient = options.queryClient ?? new import_query_core.QueryClient();
|
|
664
2048
|
const { mode = "delivery", projectId, apiKey, baseUrl, previewToken } = options;
|
|
@@ -687,7 +2071,7 @@ var getDataClient = (options) => {
|
|
|
687
2071
|
}
|
|
688
2072
|
};
|
|
689
2073
|
const internalFindById = async (id) => {
|
|
690
|
-
if (id === null) return null;
|
|
2074
|
+
if (id === null || id === void 0) return null;
|
|
691
2075
|
const featureType = id.slice(0, id.lastIndexOf("-"));
|
|
692
2076
|
const feature2 = await queryClient.ensureQueryData({
|
|
693
2077
|
queryKey: ["_deliveryapi", featureType, id],
|
|
@@ -770,6 +2154,17 @@ var getDataClient = (options) => {
|
|
|
770
2154
|
const feature2 = await queryClient.ensureQueryData(findQueryOptions);
|
|
771
2155
|
return feature2;
|
|
772
2156
|
}
|
|
2157
|
+
const searchFn = async (txt) => {
|
|
2158
|
+
if (!searchClient) {
|
|
2159
|
+
const [occupants, amenities] = await Promise.all([
|
|
2160
|
+
filterByType("occupant", { populate: true }),
|
|
2161
|
+
filterByType("amenity")
|
|
2162
|
+
]);
|
|
2163
|
+
const haystack = { occupants, amenities };
|
|
2164
|
+
searchClient = getSearchClient(haystack);
|
|
2165
|
+
}
|
|
2166
|
+
return searchClient.search(txt);
|
|
2167
|
+
};
|
|
773
2168
|
return {
|
|
774
2169
|
projectId,
|
|
775
2170
|
queryClient,
|
|
@@ -779,7 +2174,8 @@ var getDataClient = (options) => {
|
|
|
779
2174
|
createFilterByTypeQueryOptions,
|
|
780
2175
|
createFindByIdQueryOptions,
|
|
781
2176
|
filterByType,
|
|
782
|
-
findById
|
|
2177
|
+
findById,
|
|
2178
|
+
search: searchFn
|
|
783
2179
|
};
|
|
784
2180
|
};
|
|
785
2181
|
|
|
@@ -830,7 +2226,7 @@ function point(coordinates, properties, options = {}) {
|
|
|
830
2226
|
if (coordinates.length < 2) {
|
|
831
2227
|
throw new Error("coordinates must be at least 2 numbers long");
|
|
832
2228
|
}
|
|
833
|
-
if (!
|
|
2229
|
+
if (!isNumber2(coordinates[0]) || !isNumber2(coordinates[1])) {
|
|
834
2230
|
throw new Error("coordinates must contain numbers");
|
|
835
2231
|
}
|
|
836
2232
|
const geom = {
|
|
@@ -889,7 +2285,7 @@ function multiPoint(coordinates, properties, options = {}) {
|
|
|
889
2285
|
};
|
|
890
2286
|
return feature(geom, properties, options);
|
|
891
2287
|
}
|
|
892
|
-
function
|
|
2288
|
+
function isNumber2(num) {
|
|
893
2289
|
return !isNaN(num) && num !== null && !Array.isArray(num);
|
|
894
2290
|
}
|
|
895
2291
|
|
|
@@ -2739,7 +4135,7 @@ var CameraManager = class {
|
|
|
2739
4135
|
// src/IndoorMap/renderer/RendererManager.ts
|
|
2740
4136
|
var import_lodash_es4 = require("lodash-es");
|
|
2741
4137
|
var import_center3 = require("@turf/center");
|
|
2742
|
-
var
|
|
4138
|
+
var THREE4 = __toESM(require("three"));
|
|
2743
4139
|
|
|
2744
4140
|
// src/IndoorMap/renderer/3d/Element3DRenderer.ts
|
|
2745
4141
|
var maptalks4 = __toESM(require("maptalks-gl"));
|
|
@@ -3084,7 +4480,7 @@ var DEFAULT_POLYGON_OPTION = {
|
|
|
3084
4480
|
offset: 0,
|
|
3085
4481
|
altitude: 0
|
|
3086
4482
|
};
|
|
3087
|
-
var get3DRendererOption = (featureType, category, options) => {
|
|
4483
|
+
var get3DRendererOption = (featureType, category, options = {}) => {
|
|
3088
4484
|
try {
|
|
3089
4485
|
const option = options[featureType] ?? element3DRendererOptions[featureType];
|
|
3090
4486
|
return (category && option.byCategory?.[category]) ?? option?.default ?? DEFAULT_POLYGON_OPTION;
|
|
@@ -3545,6 +4941,12 @@ var Marker2DRenderer = class extends EventTarget {
|
|
|
3545
4941
|
marker.addTo(this.map);
|
|
3546
4942
|
return marker;
|
|
3547
4943
|
};
|
|
4944
|
+
createTextMarker = (position, label, options) => {
|
|
4945
|
+
return null;
|
|
4946
|
+
};
|
|
4947
|
+
createImageMarker = (position, src, options) => {
|
|
4948
|
+
return null;
|
|
4949
|
+
};
|
|
3548
4950
|
removeMarker = (marker) => {
|
|
3549
4951
|
marker.remove();
|
|
3550
4952
|
};
|
|
@@ -3556,6 +4958,7 @@ var Marker2DRenderer = class extends EventTarget {
|
|
|
3556
4958
|
|
|
3557
4959
|
// src/IndoorMap/renderer/3d/Marker3DRenderer.ts
|
|
3558
4960
|
var maptalks7 = __toESM(require("maptalks-gl"));
|
|
4961
|
+
var THREE3 = __toESM(require("three"));
|
|
3559
4962
|
|
|
3560
4963
|
// src/IndoorMap/renderer/3d/objects/TextSpriteMarker.ts
|
|
3561
4964
|
var import_maptalks8 = require("maptalks");
|
|
@@ -3755,21 +5158,35 @@ var TextSpriteMarker = class extends import_maptalks9.BaseObject {
|
|
|
3755
5158
|
};
|
|
3756
5159
|
|
|
3757
5160
|
// src/IndoorMap/renderer/3d/Marker3DRenderer.ts
|
|
3758
|
-
var HEIGHT_METER2 = 4;
|
|
3759
|
-
var MULTIORDINAL_HEIGHT_METER3 = 9;
|
|
3760
5161
|
var Marker3DRenderer = class extends EventTarget {
|
|
3761
5162
|
isReady = false;
|
|
3762
5163
|
threeLayer;
|
|
3763
5164
|
map;
|
|
3764
|
-
materialByKey;
|
|
3765
5165
|
constructor(map, options, layer) {
|
|
3766
5166
|
super();
|
|
3767
5167
|
this.map = map;
|
|
3768
5168
|
this.threeLayer = layer;
|
|
3769
5169
|
}
|
|
3770
|
-
|
|
5170
|
+
createPointMaterialFromSvg(svgPath, size = 40) {
|
|
5171
|
+
return new THREE3.PointsMaterial({
|
|
5172
|
+
size,
|
|
5173
|
+
sizeAttenuation: false,
|
|
5174
|
+
// Always same size in screen pixels (Screen pixel)
|
|
5175
|
+
// color: fillStyle,
|
|
5176
|
+
alphaTest: 0.5,
|
|
5177
|
+
// vertexColors: THREE.VertexColors,
|
|
5178
|
+
// color: 0xffffff,
|
|
5179
|
+
transparent: true,
|
|
5180
|
+
blending: THREE3.NormalBlending,
|
|
5181
|
+
depthTest: true,
|
|
5182
|
+
// POI is hidden behind building
|
|
5183
|
+
depthWrite: true,
|
|
5184
|
+
map: new THREE3.TextureLoader().load(svgPath)
|
|
5185
|
+
});
|
|
5186
|
+
}
|
|
5187
|
+
createTextMarker = (position, label, options) => {
|
|
3771
5188
|
const combinedOptions = {
|
|
3772
|
-
altitude:
|
|
5189
|
+
altitude: 0,
|
|
3773
5190
|
text: label,
|
|
3774
5191
|
...options ?? {}
|
|
3775
5192
|
};
|
|
@@ -3778,17 +5195,37 @@ var Marker3DRenderer = class extends EventTarget {
|
|
|
3778
5195
|
this.threeLayer.addMesh([marker]);
|
|
3779
5196
|
return marker;
|
|
3780
5197
|
};
|
|
3781
|
-
createImageMarker = () => {
|
|
3782
|
-
|
|
3783
|
-
|
|
3784
|
-
|
|
5198
|
+
createImageMarker = (position, src, options) => {
|
|
5199
|
+
const [lng, lat] = position;
|
|
5200
|
+
let meshes = [];
|
|
5201
|
+
const height = options.height ?? 0;
|
|
5202
|
+
const { leg, ...markerOptions } = options;
|
|
5203
|
+
const { color: legColor = "#000000", ...legOptions } = leg ?? {};
|
|
5204
|
+
const material = this.createPointMaterialFromSvg(src, 40);
|
|
5205
|
+
const marker = this.threeLayer.toPoint(new maptalks7.Coordinate(lng, lat), { height, ...markerOptions }, material);
|
|
5206
|
+
marker.getObject3d().renderOrder = 10;
|
|
5207
|
+
meshes.push(marker);
|
|
5208
|
+
if (options.leg) {
|
|
5209
|
+
const legMaterial = new THREE3.MeshLambertMaterial({ color: legColor, transparent: true });
|
|
5210
|
+
const leg2 = this.threeLayer.toBar(new maptalks7.Coordinate(lng, lat), { ...legOptions, height }, legMaterial);
|
|
5211
|
+
const legObj = leg2.getObject3d();
|
|
5212
|
+
legObj.traverse((o) => {
|
|
5213
|
+
if (o.isMesh && o.material) {
|
|
5214
|
+
o.material.depthWrite = false;
|
|
5215
|
+
o.material.depthTest = true;
|
|
5216
|
+
o.renderOrder = 0;
|
|
5217
|
+
}
|
|
5218
|
+
});
|
|
5219
|
+
meshes = [leg2, ...meshes];
|
|
5220
|
+
}
|
|
5221
|
+
this.threeLayer.addMesh(meshes);
|
|
5222
|
+
return meshes;
|
|
3785
5223
|
};
|
|
3786
5224
|
removeMarker = (marker) => {
|
|
3787
5225
|
marker.remove();
|
|
3788
5226
|
};
|
|
3789
5227
|
showMarkers(elements, ordinalDiff = 0) {
|
|
3790
5228
|
elements.forEach((element) => {
|
|
3791
|
-
element.setAltitude(ordinalDiff * MULTIORDINAL_HEIGHT_METER3);
|
|
3792
5229
|
element.show();
|
|
3793
5230
|
});
|
|
3794
5231
|
}
|
|
@@ -4327,7 +5764,11 @@ function inBBox(pt, bbox2) {
|
|
|
4327
5764
|
|
|
4328
5765
|
// src/IndoorMap/renderer/utils/findUnitOnPoint.ts
|
|
4329
5766
|
var findUnitOnPoint = (units, point2) => {
|
|
4330
|
-
|
|
5767
|
+
try {
|
|
5768
|
+
return units.find((unit) => booleanPointInPolygon(point2, polygon(unit.geometry.coordinates)));
|
|
5769
|
+
} catch (err) {
|
|
5770
|
+
return null;
|
|
5771
|
+
}
|
|
4331
5772
|
};
|
|
4332
5773
|
|
|
4333
5774
|
// src/IndoorMap/renderer/RendererManager.ts
|
|
@@ -4397,13 +5838,13 @@ var RendererManager = class extends EventTarget {
|
|
|
4397
5838
|
}
|
|
4398
5839
|
return bad;
|
|
4399
5840
|
}
|
|
4400
|
-
const ambientLight = new
|
|
5841
|
+
const ambientLight = new THREE4.AmbientLight(16777215, 0.3);
|
|
4401
5842
|
scene.add(ambientLight);
|
|
4402
5843
|
const dirColor = 16777215;
|
|
4403
|
-
const dllight = new
|
|
5844
|
+
const dllight = new THREE4.DirectionalLight(dirColor, 0.8);
|
|
4404
5845
|
dllight.position.set(0, -10, 20).normalize();
|
|
4405
5846
|
scene.add(dllight);
|
|
4406
|
-
const hemi = new
|
|
5847
|
+
const hemi = new THREE4.HemisphereLight(16777215, 4473924, 0.4);
|
|
4407
5848
|
scene.add(hemi);
|
|
4408
5849
|
_this.elementRenderer = new Element3DRenderer(map, options.elements);
|
|
4409
5850
|
_this.markerRenderer = new Marker3DRenderer(map, {}, threeLayer);
|
|
@@ -4486,7 +5927,7 @@ var RendererManager = class extends EventTarget {
|
|
|
4486
5927
|
return openings.find((o) => o.id === openingId);
|
|
4487
5928
|
}));
|
|
4488
5929
|
const innerElements = this.elementRenderer.createGeometry(unit);
|
|
4489
|
-
const wallElements =
|
|
5930
|
+
const wallElements = [];
|
|
4490
5931
|
if (innerElements || wallElements) {
|
|
4491
5932
|
const _innerElements = Array.isArray(innerElements) ? innerElements : [innerElements];
|
|
4492
5933
|
const _wallElements = Array.isArray(wallElements) ? wallElements : [wallElements];
|
|
@@ -4541,10 +5982,12 @@ var RendererManager = class extends EventTarget {
|
|
|
4541
5982
|
for (const label of groundLabels) {
|
|
4542
5983
|
const center2 = (0, import_center3.center)(polygon(label.geometry.coordinates)).geometry.coordinates;
|
|
4543
5984
|
const unit = findUnitOnPoint(units, center2);
|
|
4544
|
-
|
|
4545
|
-
|
|
4546
|
-
|
|
4547
|
-
|
|
5985
|
+
if (unit) {
|
|
5986
|
+
const element = this.elementRenderer.createGroundLabel(label, unit);
|
|
5987
|
+
if (element) {
|
|
5988
|
+
const _elements = Array.isArray(element) ? element : [element];
|
|
5989
|
+
this.addElementsToManager(label.id, _elements, label.properties.ordinal);
|
|
5990
|
+
}
|
|
4548
5991
|
}
|
|
4549
5992
|
}
|
|
4550
5993
|
if (this.options.type === "3D") {
|
|
@@ -4626,10 +6069,11 @@ var RendererManager = class extends EventTarget {
|
|
|
4626
6069
|
this.markerRenderer.hideMarkers(markers, ordinal);
|
|
4627
6070
|
}
|
|
4628
6071
|
};
|
|
4629
|
-
createMarker(coordinate, ordinal,
|
|
4630
|
-
const
|
|
6072
|
+
createMarker(type, coordinate, ordinal, textOrPath, options) {
|
|
6073
|
+
const meshes = type === "text" ? this.markerRenderer.createTextMarker(coordinate, textOrPath, options) : this.markerRenderer.createImageMarker(coordinate, textOrPath, options);
|
|
4631
6074
|
const markerId = `${this.markersMap.size + 1}`;
|
|
4632
|
-
|
|
6075
|
+
const markerMeshes = Array.isArray(meshes) ? meshes : [meshes];
|
|
6076
|
+
this._addMarkersToManager(markerId, markerMeshes, ordinal);
|
|
4633
6077
|
}
|
|
4634
6078
|
clearMarkers() {
|
|
4635
6079
|
for (const [markerId, marker] of this.markersMap) {
|
|
@@ -4769,6 +6213,7 @@ var IndoorMap = class extends EventTarget {
|
|
|
4769
6213
|
this.#dataClient = value;
|
|
4770
6214
|
if (!this.options.camera?.defaultView?.center) {
|
|
4771
6215
|
this.#dataClient.filterByType("venue").then((venues) => {
|
|
6216
|
+
this.#venues = venues;
|
|
4772
6217
|
const venueCenters = (0, import_center4.default)(featureCollection(venues));
|
|
4773
6218
|
const [x, y] = venueCenters.geometry.coordinates;
|
|
4774
6219
|
const center2 = new import_maptalks_gl.Coordinate(x, y);
|