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.mjs
CHANGED
|
@@ -364,6 +364,7 @@ var createPopulator = ({
|
|
|
364
364
|
...amenity.properties,
|
|
365
365
|
ordinal: defaultLevel.properties.ordinal,
|
|
366
366
|
level_name: defaultLevel.properties.name.en,
|
|
367
|
+
level: defaultLevel,
|
|
367
368
|
units: populatedUnits,
|
|
368
369
|
venue,
|
|
369
370
|
_experimental_kiosk: kiosk ? await populateKiosk(kiosk) : null
|
|
@@ -372,6 +373,7 @@ var createPopulator = ({
|
|
|
372
373
|
};
|
|
373
374
|
const populateAnchor = async (anchor) => {
|
|
374
375
|
const unit = await internalFindById(anchor.properties.unit_id);
|
|
376
|
+
const venue = await internalFindById(unit.properties.venue_id);
|
|
375
377
|
const level = await internalFindById(unit.properties.level_id);
|
|
376
378
|
const sections = await internalFilterByType("section");
|
|
377
379
|
const section = sections.find((section2) => booleanWithin(anchor, section2));
|
|
@@ -381,7 +383,9 @@ var createPopulator = ({
|
|
|
381
383
|
...anchor.properties,
|
|
382
384
|
level: await populateLevel(level),
|
|
383
385
|
unit: await populateUnit(unit),
|
|
384
|
-
section: section ? await populateSection(section) : null
|
|
386
|
+
section: section ? await populateSection(section) : null,
|
|
387
|
+
venue: await populateVenue(venue),
|
|
388
|
+
ordinal: level.properties.ordinal
|
|
385
389
|
}
|
|
386
390
|
};
|
|
387
391
|
};
|
|
@@ -448,8 +452,8 @@ var createPopulator = ({
|
|
|
448
452
|
anchor_id,
|
|
449
453
|
venue_id,
|
|
450
454
|
local_category_ids,
|
|
451
|
-
promotion_ids,
|
|
452
|
-
privilege_ids,
|
|
455
|
+
promotion_ids = [],
|
|
456
|
+
privilege_ids = [],
|
|
453
457
|
kiosk_id,
|
|
454
458
|
unit_id,
|
|
455
459
|
kiosk_ids = [],
|
|
@@ -546,6 +550,20 @@ var createPopulator = ({
|
|
|
546
550
|
}
|
|
547
551
|
};
|
|
548
552
|
};
|
|
553
|
+
const populateModel3D = async (model3d) => {
|
|
554
|
+
const level = await internalFindById(model3d.properties.level_id);
|
|
555
|
+
try {
|
|
556
|
+
return {
|
|
557
|
+
...model3d,
|
|
558
|
+
properties: {
|
|
559
|
+
...model3d.properties,
|
|
560
|
+
level: await populateLevel(level)
|
|
561
|
+
}
|
|
562
|
+
};
|
|
563
|
+
} catch (err) {
|
|
564
|
+
console.log(`error finding level`, { model3d, level });
|
|
565
|
+
}
|
|
566
|
+
};
|
|
549
567
|
const populateFeature = (feature2) => Promise.resolve(feature2);
|
|
550
568
|
return {
|
|
551
569
|
address: populateAddress,
|
|
@@ -570,12 +588,1378 @@ var createPopulator = ({
|
|
|
570
588
|
section: populateSection,
|
|
571
589
|
unit: populateUnit,
|
|
572
590
|
venue: populateVenue,
|
|
573
|
-
taxonomy: populateTaxonomy
|
|
591
|
+
taxonomy: populateTaxonomy,
|
|
592
|
+
model3d: populateModel3D
|
|
593
|
+
};
|
|
594
|
+
};
|
|
595
|
+
|
|
596
|
+
// ../../node_modules/fuse.js/dist/fuse.mjs
|
|
597
|
+
function isArray(value) {
|
|
598
|
+
return !Array.isArray ? getTag(value) === "[object Array]" : Array.isArray(value);
|
|
599
|
+
}
|
|
600
|
+
var INFINITY = 1 / 0;
|
|
601
|
+
function baseToString(value) {
|
|
602
|
+
if (typeof value == "string") {
|
|
603
|
+
return value;
|
|
604
|
+
}
|
|
605
|
+
let result = value + "";
|
|
606
|
+
return result == "0" && 1 / value == -INFINITY ? "-0" : result;
|
|
607
|
+
}
|
|
608
|
+
function toString(value) {
|
|
609
|
+
return value == null ? "" : baseToString(value);
|
|
610
|
+
}
|
|
611
|
+
function isString(value) {
|
|
612
|
+
return typeof value === "string";
|
|
613
|
+
}
|
|
614
|
+
function isNumber(value) {
|
|
615
|
+
return typeof value === "number";
|
|
616
|
+
}
|
|
617
|
+
function isBoolean(value) {
|
|
618
|
+
return value === true || value === false || isObjectLike(value) && getTag(value) == "[object Boolean]";
|
|
619
|
+
}
|
|
620
|
+
function isObject(value) {
|
|
621
|
+
return typeof value === "object";
|
|
622
|
+
}
|
|
623
|
+
function isObjectLike(value) {
|
|
624
|
+
return isObject(value) && value !== null;
|
|
625
|
+
}
|
|
626
|
+
function isDefined(value) {
|
|
627
|
+
return value !== void 0 && value !== null;
|
|
628
|
+
}
|
|
629
|
+
function isBlank(value) {
|
|
630
|
+
return !value.trim().length;
|
|
631
|
+
}
|
|
632
|
+
function getTag(value) {
|
|
633
|
+
return value == null ? value === void 0 ? "[object Undefined]" : "[object Null]" : Object.prototype.toString.call(value);
|
|
634
|
+
}
|
|
635
|
+
var INCORRECT_INDEX_TYPE = "Incorrect 'index' type";
|
|
636
|
+
var LOGICAL_SEARCH_INVALID_QUERY_FOR_KEY = (key) => `Invalid value for key ${key}`;
|
|
637
|
+
var PATTERN_LENGTH_TOO_LARGE = (max2) => `Pattern length exceeds max of ${max2}.`;
|
|
638
|
+
var MISSING_KEY_PROPERTY = (name) => `Missing ${name} property in key`;
|
|
639
|
+
var INVALID_KEY_WEIGHT_VALUE = (key) => `Property 'weight' in key '${key}' must be a positive integer`;
|
|
640
|
+
var hasOwn = Object.prototype.hasOwnProperty;
|
|
641
|
+
var KeyStore = class {
|
|
642
|
+
constructor(keys) {
|
|
643
|
+
this._keys = [];
|
|
644
|
+
this._keyMap = {};
|
|
645
|
+
let totalWeight = 0;
|
|
646
|
+
keys.forEach((key) => {
|
|
647
|
+
let obj = createKey(key);
|
|
648
|
+
this._keys.push(obj);
|
|
649
|
+
this._keyMap[obj.id] = obj;
|
|
650
|
+
totalWeight += obj.weight;
|
|
651
|
+
});
|
|
652
|
+
this._keys.forEach((key) => {
|
|
653
|
+
key.weight /= totalWeight;
|
|
654
|
+
});
|
|
655
|
+
}
|
|
656
|
+
get(keyId) {
|
|
657
|
+
return this._keyMap[keyId];
|
|
658
|
+
}
|
|
659
|
+
keys() {
|
|
660
|
+
return this._keys;
|
|
661
|
+
}
|
|
662
|
+
toJSON() {
|
|
663
|
+
return JSON.stringify(this._keys);
|
|
664
|
+
}
|
|
665
|
+
};
|
|
666
|
+
function createKey(key) {
|
|
667
|
+
let path = null;
|
|
668
|
+
let id = null;
|
|
669
|
+
let src = null;
|
|
670
|
+
let weight = 1;
|
|
671
|
+
let getFn = null;
|
|
672
|
+
if (isString(key) || isArray(key)) {
|
|
673
|
+
src = key;
|
|
674
|
+
path = createKeyPath(key);
|
|
675
|
+
id = createKeyId(key);
|
|
676
|
+
} else {
|
|
677
|
+
if (!hasOwn.call(key, "name")) {
|
|
678
|
+
throw new Error(MISSING_KEY_PROPERTY("name"));
|
|
679
|
+
}
|
|
680
|
+
const name = key.name;
|
|
681
|
+
src = name;
|
|
682
|
+
if (hasOwn.call(key, "weight")) {
|
|
683
|
+
weight = key.weight;
|
|
684
|
+
if (weight <= 0) {
|
|
685
|
+
throw new Error(INVALID_KEY_WEIGHT_VALUE(name));
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
path = createKeyPath(name);
|
|
689
|
+
id = createKeyId(name);
|
|
690
|
+
getFn = key.getFn;
|
|
691
|
+
}
|
|
692
|
+
return { path, id, weight, src, getFn };
|
|
693
|
+
}
|
|
694
|
+
function createKeyPath(key) {
|
|
695
|
+
return isArray(key) ? key : key.split(".");
|
|
696
|
+
}
|
|
697
|
+
function createKeyId(key) {
|
|
698
|
+
return isArray(key) ? key.join(".") : key;
|
|
699
|
+
}
|
|
700
|
+
function get(obj, path) {
|
|
701
|
+
let list = [];
|
|
702
|
+
let arr = false;
|
|
703
|
+
const deepGet = (obj2, path2, index) => {
|
|
704
|
+
if (!isDefined(obj2)) {
|
|
705
|
+
return;
|
|
706
|
+
}
|
|
707
|
+
if (!path2[index]) {
|
|
708
|
+
list.push(obj2);
|
|
709
|
+
} else {
|
|
710
|
+
let key = path2[index];
|
|
711
|
+
const value = obj2[key];
|
|
712
|
+
if (!isDefined(value)) {
|
|
713
|
+
return;
|
|
714
|
+
}
|
|
715
|
+
if (index === path2.length - 1 && (isString(value) || isNumber(value) || isBoolean(value))) {
|
|
716
|
+
list.push(toString(value));
|
|
717
|
+
} else if (isArray(value)) {
|
|
718
|
+
arr = true;
|
|
719
|
+
for (let i = 0, len = value.length; i < len; i += 1) {
|
|
720
|
+
deepGet(value[i], path2, index + 1);
|
|
721
|
+
}
|
|
722
|
+
} else if (path2.length) {
|
|
723
|
+
deepGet(value, path2, index + 1);
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
};
|
|
727
|
+
deepGet(obj, isString(path) ? path.split(".") : path, 0);
|
|
728
|
+
return arr ? list : list[0];
|
|
729
|
+
}
|
|
730
|
+
var MatchOptions = {
|
|
731
|
+
// Whether the matches should be included in the result set. When `true`, each record in the result
|
|
732
|
+
// set will include the indices of the matched characters.
|
|
733
|
+
// These can consequently be used for highlighting purposes.
|
|
734
|
+
includeMatches: false,
|
|
735
|
+
// When `true`, the matching function will continue to the end of a search pattern even if
|
|
736
|
+
// a perfect match has already been located in the string.
|
|
737
|
+
findAllMatches: false,
|
|
738
|
+
// Minimum number of characters that must be matched before a result is considered a match
|
|
739
|
+
minMatchCharLength: 1
|
|
740
|
+
};
|
|
741
|
+
var BasicOptions = {
|
|
742
|
+
// When `true`, the algorithm continues searching to the end of the input even if a perfect
|
|
743
|
+
// match is found before the end of the same input.
|
|
744
|
+
isCaseSensitive: false,
|
|
745
|
+
// When `true`, the algorithm will ignore diacritics (accents) in comparisons
|
|
746
|
+
ignoreDiacritics: false,
|
|
747
|
+
// When true, the matching function will continue to the end of a search pattern even if
|
|
748
|
+
includeScore: false,
|
|
749
|
+
// List of properties that will be searched. This also supports nested properties.
|
|
750
|
+
keys: [],
|
|
751
|
+
// Whether to sort the result list, by score
|
|
752
|
+
shouldSort: true,
|
|
753
|
+
// Default sort function: sort by ascending score, ascending index
|
|
754
|
+
sortFn: (a, b) => a.score === b.score ? a.idx < b.idx ? -1 : 1 : a.score < b.score ? -1 : 1
|
|
755
|
+
};
|
|
756
|
+
var FuzzyOptions = {
|
|
757
|
+
// Approximately where in the text is the pattern expected to be found?
|
|
758
|
+
location: 0,
|
|
759
|
+
// At what point does the match algorithm give up. A threshold of '0.0' requires a perfect match
|
|
760
|
+
// (of both letters and location), a threshold of '1.0' would match anything.
|
|
761
|
+
threshold: 0.6,
|
|
762
|
+
// Determines how close the match must be to the fuzzy location (specified above).
|
|
763
|
+
// An exact letter match which is 'distance' characters away from the fuzzy location
|
|
764
|
+
// would score as a complete mismatch. A distance of '0' requires the match be at
|
|
765
|
+
// the exact location specified, a threshold of '1000' would require a perfect match
|
|
766
|
+
// to be within 800 characters of the fuzzy location to be found using a 0.8 threshold.
|
|
767
|
+
distance: 100
|
|
768
|
+
};
|
|
769
|
+
var AdvancedOptions = {
|
|
770
|
+
// When `true`, it enables the use of unix-like search commands
|
|
771
|
+
useExtendedSearch: false,
|
|
772
|
+
// The get function to use when fetching an object's properties.
|
|
773
|
+
// The default will search nested paths *ie foo.bar.baz*
|
|
774
|
+
getFn: get,
|
|
775
|
+
// When `true`, search will ignore `location` and `distance`, so it won't matter
|
|
776
|
+
// where in the string the pattern appears.
|
|
777
|
+
// More info: https://fusejs.io/concepts/scoring-theory.html#fuzziness-score
|
|
778
|
+
ignoreLocation: false,
|
|
779
|
+
// When `true`, the calculation for the relevance score (used for sorting) will
|
|
780
|
+
// ignore the field-length norm.
|
|
781
|
+
// More info: https://fusejs.io/concepts/scoring-theory.html#field-length-norm
|
|
782
|
+
ignoreFieldNorm: false,
|
|
783
|
+
// The weight to determine how much field length norm effects scoring.
|
|
784
|
+
fieldNormWeight: 1
|
|
785
|
+
};
|
|
786
|
+
var Config = {
|
|
787
|
+
...BasicOptions,
|
|
788
|
+
...MatchOptions,
|
|
789
|
+
...FuzzyOptions,
|
|
790
|
+
...AdvancedOptions
|
|
791
|
+
};
|
|
792
|
+
var SPACE = /[^ ]+/g;
|
|
793
|
+
function norm(weight = 1, mantissa = 3) {
|
|
794
|
+
const cache = /* @__PURE__ */ new Map();
|
|
795
|
+
const m = Math.pow(10, mantissa);
|
|
796
|
+
return {
|
|
797
|
+
get(value) {
|
|
798
|
+
const numTokens = value.match(SPACE).length;
|
|
799
|
+
if (cache.has(numTokens)) {
|
|
800
|
+
return cache.get(numTokens);
|
|
801
|
+
}
|
|
802
|
+
const norm2 = 1 / Math.pow(numTokens, 0.5 * weight);
|
|
803
|
+
const n = parseFloat(Math.round(norm2 * m) / m);
|
|
804
|
+
cache.set(numTokens, n);
|
|
805
|
+
return n;
|
|
806
|
+
},
|
|
807
|
+
clear() {
|
|
808
|
+
cache.clear();
|
|
809
|
+
}
|
|
810
|
+
};
|
|
811
|
+
}
|
|
812
|
+
var FuseIndex = class {
|
|
813
|
+
constructor({
|
|
814
|
+
getFn = Config.getFn,
|
|
815
|
+
fieldNormWeight = Config.fieldNormWeight
|
|
816
|
+
} = {}) {
|
|
817
|
+
this.norm = norm(fieldNormWeight, 3);
|
|
818
|
+
this.getFn = getFn;
|
|
819
|
+
this.isCreated = false;
|
|
820
|
+
this.setIndexRecords();
|
|
821
|
+
}
|
|
822
|
+
setSources(docs = []) {
|
|
823
|
+
this.docs = docs;
|
|
824
|
+
}
|
|
825
|
+
setIndexRecords(records = []) {
|
|
826
|
+
this.records = records;
|
|
827
|
+
}
|
|
828
|
+
setKeys(keys = []) {
|
|
829
|
+
this.keys = keys;
|
|
830
|
+
this._keysMap = {};
|
|
831
|
+
keys.forEach((key, idx) => {
|
|
832
|
+
this._keysMap[key.id] = idx;
|
|
833
|
+
});
|
|
834
|
+
}
|
|
835
|
+
create() {
|
|
836
|
+
if (this.isCreated || !this.docs.length) {
|
|
837
|
+
return;
|
|
838
|
+
}
|
|
839
|
+
this.isCreated = true;
|
|
840
|
+
if (isString(this.docs[0])) {
|
|
841
|
+
this.docs.forEach((doc, docIndex) => {
|
|
842
|
+
this._addString(doc, docIndex);
|
|
843
|
+
});
|
|
844
|
+
} else {
|
|
845
|
+
this.docs.forEach((doc, docIndex) => {
|
|
846
|
+
this._addObject(doc, docIndex);
|
|
847
|
+
});
|
|
848
|
+
}
|
|
849
|
+
this.norm.clear();
|
|
850
|
+
}
|
|
851
|
+
// Adds a doc to the end of the index
|
|
852
|
+
add(doc) {
|
|
853
|
+
const idx = this.size();
|
|
854
|
+
if (isString(doc)) {
|
|
855
|
+
this._addString(doc, idx);
|
|
856
|
+
} else {
|
|
857
|
+
this._addObject(doc, idx);
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
// Removes the doc at the specified index of the index
|
|
861
|
+
removeAt(idx) {
|
|
862
|
+
this.records.splice(idx, 1);
|
|
863
|
+
for (let i = idx, len = this.size(); i < len; i += 1) {
|
|
864
|
+
this.records[i].i -= 1;
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
getValueForItemAtKeyId(item, keyId) {
|
|
868
|
+
return item[this._keysMap[keyId]];
|
|
869
|
+
}
|
|
870
|
+
size() {
|
|
871
|
+
return this.records.length;
|
|
872
|
+
}
|
|
873
|
+
_addString(doc, docIndex) {
|
|
874
|
+
if (!isDefined(doc) || isBlank(doc)) {
|
|
875
|
+
return;
|
|
876
|
+
}
|
|
877
|
+
let record = {
|
|
878
|
+
v: doc,
|
|
879
|
+
i: docIndex,
|
|
880
|
+
n: this.norm.get(doc)
|
|
881
|
+
};
|
|
882
|
+
this.records.push(record);
|
|
883
|
+
}
|
|
884
|
+
_addObject(doc, docIndex) {
|
|
885
|
+
let record = { i: docIndex, $: {} };
|
|
886
|
+
this.keys.forEach((key, keyIndex) => {
|
|
887
|
+
let value = key.getFn ? key.getFn(doc) : this.getFn(doc, key.path);
|
|
888
|
+
if (!isDefined(value)) {
|
|
889
|
+
return;
|
|
890
|
+
}
|
|
891
|
+
if (isArray(value)) {
|
|
892
|
+
let subRecords = [];
|
|
893
|
+
const stack = [{ nestedArrIndex: -1, value }];
|
|
894
|
+
while (stack.length) {
|
|
895
|
+
const { nestedArrIndex, value: value2 } = stack.pop();
|
|
896
|
+
if (!isDefined(value2)) {
|
|
897
|
+
continue;
|
|
898
|
+
}
|
|
899
|
+
if (isString(value2) && !isBlank(value2)) {
|
|
900
|
+
let subRecord = {
|
|
901
|
+
v: value2,
|
|
902
|
+
i: nestedArrIndex,
|
|
903
|
+
n: this.norm.get(value2)
|
|
904
|
+
};
|
|
905
|
+
subRecords.push(subRecord);
|
|
906
|
+
} else if (isArray(value2)) {
|
|
907
|
+
value2.forEach((item, k) => {
|
|
908
|
+
stack.push({
|
|
909
|
+
nestedArrIndex: k,
|
|
910
|
+
value: item
|
|
911
|
+
});
|
|
912
|
+
});
|
|
913
|
+
} else ;
|
|
914
|
+
}
|
|
915
|
+
record.$[keyIndex] = subRecords;
|
|
916
|
+
} else if (isString(value) && !isBlank(value)) {
|
|
917
|
+
let subRecord = {
|
|
918
|
+
v: value,
|
|
919
|
+
n: this.norm.get(value)
|
|
920
|
+
};
|
|
921
|
+
record.$[keyIndex] = subRecord;
|
|
922
|
+
}
|
|
923
|
+
});
|
|
924
|
+
this.records.push(record);
|
|
925
|
+
}
|
|
926
|
+
toJSON() {
|
|
927
|
+
return {
|
|
928
|
+
keys: this.keys,
|
|
929
|
+
records: this.records
|
|
930
|
+
};
|
|
931
|
+
}
|
|
932
|
+
};
|
|
933
|
+
function createIndex(keys, docs, { getFn = Config.getFn, fieldNormWeight = Config.fieldNormWeight } = {}) {
|
|
934
|
+
const myIndex = new FuseIndex({ getFn, fieldNormWeight });
|
|
935
|
+
myIndex.setKeys(keys.map(createKey));
|
|
936
|
+
myIndex.setSources(docs);
|
|
937
|
+
myIndex.create();
|
|
938
|
+
return myIndex;
|
|
939
|
+
}
|
|
940
|
+
function parseIndex(data, { getFn = Config.getFn, fieldNormWeight = Config.fieldNormWeight } = {}) {
|
|
941
|
+
const { keys, records } = data;
|
|
942
|
+
const myIndex = new FuseIndex({ getFn, fieldNormWeight });
|
|
943
|
+
myIndex.setKeys(keys);
|
|
944
|
+
myIndex.setIndexRecords(records);
|
|
945
|
+
return myIndex;
|
|
946
|
+
}
|
|
947
|
+
function computeScore$1(pattern, {
|
|
948
|
+
errors = 0,
|
|
949
|
+
currentLocation = 0,
|
|
950
|
+
expectedLocation = 0,
|
|
951
|
+
distance = Config.distance,
|
|
952
|
+
ignoreLocation = Config.ignoreLocation
|
|
953
|
+
} = {}) {
|
|
954
|
+
const accuracy = errors / pattern.length;
|
|
955
|
+
if (ignoreLocation) {
|
|
956
|
+
return accuracy;
|
|
957
|
+
}
|
|
958
|
+
const proximity = Math.abs(expectedLocation - currentLocation);
|
|
959
|
+
if (!distance) {
|
|
960
|
+
return proximity ? 1 : accuracy;
|
|
961
|
+
}
|
|
962
|
+
return accuracy + proximity / distance;
|
|
963
|
+
}
|
|
964
|
+
function convertMaskToIndices(matchmask = [], minMatchCharLength = Config.minMatchCharLength) {
|
|
965
|
+
let indices = [];
|
|
966
|
+
let start = -1;
|
|
967
|
+
let end = -1;
|
|
968
|
+
let i = 0;
|
|
969
|
+
for (let len = matchmask.length; i < len; i += 1) {
|
|
970
|
+
let match = matchmask[i];
|
|
971
|
+
if (match && start === -1) {
|
|
972
|
+
start = i;
|
|
973
|
+
} else if (!match && start !== -1) {
|
|
974
|
+
end = i - 1;
|
|
975
|
+
if (end - start + 1 >= minMatchCharLength) {
|
|
976
|
+
indices.push([start, end]);
|
|
977
|
+
}
|
|
978
|
+
start = -1;
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
if (matchmask[i - 1] && i - start >= minMatchCharLength) {
|
|
982
|
+
indices.push([start, i - 1]);
|
|
983
|
+
}
|
|
984
|
+
return indices;
|
|
985
|
+
}
|
|
986
|
+
var MAX_BITS = 32;
|
|
987
|
+
function search(text, pattern, patternAlphabet, {
|
|
988
|
+
location = Config.location,
|
|
989
|
+
distance = Config.distance,
|
|
990
|
+
threshold = Config.threshold,
|
|
991
|
+
findAllMatches = Config.findAllMatches,
|
|
992
|
+
minMatchCharLength = Config.minMatchCharLength,
|
|
993
|
+
includeMatches = Config.includeMatches,
|
|
994
|
+
ignoreLocation = Config.ignoreLocation
|
|
995
|
+
} = {}) {
|
|
996
|
+
if (pattern.length > MAX_BITS) {
|
|
997
|
+
throw new Error(PATTERN_LENGTH_TOO_LARGE(MAX_BITS));
|
|
998
|
+
}
|
|
999
|
+
const patternLen = pattern.length;
|
|
1000
|
+
const textLen = text.length;
|
|
1001
|
+
const expectedLocation = Math.max(0, Math.min(location, textLen));
|
|
1002
|
+
let currentThreshold = threshold;
|
|
1003
|
+
let bestLocation = expectedLocation;
|
|
1004
|
+
const computeMatches = minMatchCharLength > 1 || includeMatches;
|
|
1005
|
+
const matchMask = computeMatches ? Array(textLen) : [];
|
|
1006
|
+
let index;
|
|
1007
|
+
while ((index = text.indexOf(pattern, bestLocation)) > -1) {
|
|
1008
|
+
let score = computeScore$1(pattern, {
|
|
1009
|
+
currentLocation: index,
|
|
1010
|
+
expectedLocation,
|
|
1011
|
+
distance,
|
|
1012
|
+
ignoreLocation
|
|
1013
|
+
});
|
|
1014
|
+
currentThreshold = Math.min(score, currentThreshold);
|
|
1015
|
+
bestLocation = index + patternLen;
|
|
1016
|
+
if (computeMatches) {
|
|
1017
|
+
let i = 0;
|
|
1018
|
+
while (i < patternLen) {
|
|
1019
|
+
matchMask[index + i] = 1;
|
|
1020
|
+
i += 1;
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
1023
|
+
}
|
|
1024
|
+
bestLocation = -1;
|
|
1025
|
+
let lastBitArr = [];
|
|
1026
|
+
let finalScore = 1;
|
|
1027
|
+
let binMax = patternLen + textLen;
|
|
1028
|
+
const mask = 1 << patternLen - 1;
|
|
1029
|
+
for (let i = 0; i < patternLen; i += 1) {
|
|
1030
|
+
let binMin = 0;
|
|
1031
|
+
let binMid = binMax;
|
|
1032
|
+
while (binMin < binMid) {
|
|
1033
|
+
const score2 = computeScore$1(pattern, {
|
|
1034
|
+
errors: i,
|
|
1035
|
+
currentLocation: expectedLocation + binMid,
|
|
1036
|
+
expectedLocation,
|
|
1037
|
+
distance,
|
|
1038
|
+
ignoreLocation
|
|
1039
|
+
});
|
|
1040
|
+
if (score2 <= currentThreshold) {
|
|
1041
|
+
binMin = binMid;
|
|
1042
|
+
} else {
|
|
1043
|
+
binMax = binMid;
|
|
1044
|
+
}
|
|
1045
|
+
binMid = Math.floor((binMax - binMin) / 2 + binMin);
|
|
1046
|
+
}
|
|
1047
|
+
binMax = binMid;
|
|
1048
|
+
let start = Math.max(1, expectedLocation - binMid + 1);
|
|
1049
|
+
let finish = findAllMatches ? textLen : Math.min(expectedLocation + binMid, textLen) + patternLen;
|
|
1050
|
+
let bitArr = Array(finish + 2);
|
|
1051
|
+
bitArr[finish + 1] = (1 << i) - 1;
|
|
1052
|
+
for (let j = finish; j >= start; j -= 1) {
|
|
1053
|
+
let currentLocation = j - 1;
|
|
1054
|
+
let charMatch = patternAlphabet[text.charAt(currentLocation)];
|
|
1055
|
+
if (computeMatches) {
|
|
1056
|
+
matchMask[currentLocation] = +!!charMatch;
|
|
1057
|
+
}
|
|
1058
|
+
bitArr[j] = (bitArr[j + 1] << 1 | 1) & charMatch;
|
|
1059
|
+
if (i) {
|
|
1060
|
+
bitArr[j] |= (lastBitArr[j + 1] | lastBitArr[j]) << 1 | 1 | lastBitArr[j + 1];
|
|
1061
|
+
}
|
|
1062
|
+
if (bitArr[j] & mask) {
|
|
1063
|
+
finalScore = computeScore$1(pattern, {
|
|
1064
|
+
errors: i,
|
|
1065
|
+
currentLocation,
|
|
1066
|
+
expectedLocation,
|
|
1067
|
+
distance,
|
|
1068
|
+
ignoreLocation
|
|
1069
|
+
});
|
|
1070
|
+
if (finalScore <= currentThreshold) {
|
|
1071
|
+
currentThreshold = finalScore;
|
|
1072
|
+
bestLocation = currentLocation;
|
|
1073
|
+
if (bestLocation <= expectedLocation) {
|
|
1074
|
+
break;
|
|
1075
|
+
}
|
|
1076
|
+
start = Math.max(1, 2 * expectedLocation - bestLocation);
|
|
1077
|
+
}
|
|
1078
|
+
}
|
|
1079
|
+
}
|
|
1080
|
+
const score = computeScore$1(pattern, {
|
|
1081
|
+
errors: i + 1,
|
|
1082
|
+
currentLocation: expectedLocation,
|
|
1083
|
+
expectedLocation,
|
|
1084
|
+
distance,
|
|
1085
|
+
ignoreLocation
|
|
1086
|
+
});
|
|
1087
|
+
if (score > currentThreshold) {
|
|
1088
|
+
break;
|
|
1089
|
+
}
|
|
1090
|
+
lastBitArr = bitArr;
|
|
1091
|
+
}
|
|
1092
|
+
const result = {
|
|
1093
|
+
isMatch: bestLocation >= 0,
|
|
1094
|
+
// Count exact matches (those with a score of 0) to be "almost" exact
|
|
1095
|
+
score: Math.max(1e-3, finalScore)
|
|
1096
|
+
};
|
|
1097
|
+
if (computeMatches) {
|
|
1098
|
+
const indices = convertMaskToIndices(matchMask, minMatchCharLength);
|
|
1099
|
+
if (!indices.length) {
|
|
1100
|
+
result.isMatch = false;
|
|
1101
|
+
} else if (includeMatches) {
|
|
1102
|
+
result.indices = indices;
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
1105
|
+
return result;
|
|
1106
|
+
}
|
|
1107
|
+
function createPatternAlphabet(pattern) {
|
|
1108
|
+
let mask = {};
|
|
1109
|
+
for (let i = 0, len = pattern.length; i < len; i += 1) {
|
|
1110
|
+
const char = pattern.charAt(i);
|
|
1111
|
+
mask[char] = (mask[char] || 0) | 1 << len - i - 1;
|
|
1112
|
+
}
|
|
1113
|
+
return mask;
|
|
1114
|
+
}
|
|
1115
|
+
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);
|
|
1116
|
+
var BitapSearch = class {
|
|
1117
|
+
constructor(pattern, {
|
|
1118
|
+
location = Config.location,
|
|
1119
|
+
threshold = Config.threshold,
|
|
1120
|
+
distance = Config.distance,
|
|
1121
|
+
includeMatches = Config.includeMatches,
|
|
1122
|
+
findAllMatches = Config.findAllMatches,
|
|
1123
|
+
minMatchCharLength = Config.minMatchCharLength,
|
|
1124
|
+
isCaseSensitive = Config.isCaseSensitive,
|
|
1125
|
+
ignoreDiacritics = Config.ignoreDiacritics,
|
|
1126
|
+
ignoreLocation = Config.ignoreLocation
|
|
1127
|
+
} = {}) {
|
|
1128
|
+
this.options = {
|
|
1129
|
+
location,
|
|
1130
|
+
threshold,
|
|
1131
|
+
distance,
|
|
1132
|
+
includeMatches,
|
|
1133
|
+
findAllMatches,
|
|
1134
|
+
minMatchCharLength,
|
|
1135
|
+
isCaseSensitive,
|
|
1136
|
+
ignoreDiacritics,
|
|
1137
|
+
ignoreLocation
|
|
1138
|
+
};
|
|
1139
|
+
pattern = isCaseSensitive ? pattern : pattern.toLowerCase();
|
|
1140
|
+
pattern = ignoreDiacritics ? stripDiacritics(pattern) : pattern;
|
|
1141
|
+
this.pattern = pattern;
|
|
1142
|
+
this.chunks = [];
|
|
1143
|
+
if (!this.pattern.length) {
|
|
1144
|
+
return;
|
|
1145
|
+
}
|
|
1146
|
+
const addChunk = (pattern2, startIndex) => {
|
|
1147
|
+
this.chunks.push({
|
|
1148
|
+
pattern: pattern2,
|
|
1149
|
+
alphabet: createPatternAlphabet(pattern2),
|
|
1150
|
+
startIndex
|
|
1151
|
+
});
|
|
1152
|
+
};
|
|
1153
|
+
const len = this.pattern.length;
|
|
1154
|
+
if (len > MAX_BITS) {
|
|
1155
|
+
let i = 0;
|
|
1156
|
+
const remainder = len % MAX_BITS;
|
|
1157
|
+
const end = len - remainder;
|
|
1158
|
+
while (i < end) {
|
|
1159
|
+
addChunk(this.pattern.substr(i, MAX_BITS), i);
|
|
1160
|
+
i += MAX_BITS;
|
|
1161
|
+
}
|
|
1162
|
+
if (remainder) {
|
|
1163
|
+
const startIndex = len - MAX_BITS;
|
|
1164
|
+
addChunk(this.pattern.substr(startIndex), startIndex);
|
|
1165
|
+
}
|
|
1166
|
+
} else {
|
|
1167
|
+
addChunk(this.pattern, 0);
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1170
|
+
searchIn(text) {
|
|
1171
|
+
const { isCaseSensitive, ignoreDiacritics, includeMatches } = this.options;
|
|
1172
|
+
text = isCaseSensitive ? text : text.toLowerCase();
|
|
1173
|
+
text = ignoreDiacritics ? stripDiacritics(text) : text;
|
|
1174
|
+
if (this.pattern === text) {
|
|
1175
|
+
let result2 = {
|
|
1176
|
+
isMatch: true,
|
|
1177
|
+
score: 0
|
|
1178
|
+
};
|
|
1179
|
+
if (includeMatches) {
|
|
1180
|
+
result2.indices = [[0, text.length - 1]];
|
|
1181
|
+
}
|
|
1182
|
+
return result2;
|
|
1183
|
+
}
|
|
1184
|
+
const {
|
|
1185
|
+
location,
|
|
1186
|
+
distance,
|
|
1187
|
+
threshold,
|
|
1188
|
+
findAllMatches,
|
|
1189
|
+
minMatchCharLength,
|
|
1190
|
+
ignoreLocation
|
|
1191
|
+
} = this.options;
|
|
1192
|
+
let allIndices = [];
|
|
1193
|
+
let totalScore = 0;
|
|
1194
|
+
let hasMatches = false;
|
|
1195
|
+
this.chunks.forEach(({ pattern, alphabet, startIndex }) => {
|
|
1196
|
+
const { isMatch, score, indices } = search(text, pattern, alphabet, {
|
|
1197
|
+
location: location + startIndex,
|
|
1198
|
+
distance,
|
|
1199
|
+
threshold,
|
|
1200
|
+
findAllMatches,
|
|
1201
|
+
minMatchCharLength,
|
|
1202
|
+
includeMatches,
|
|
1203
|
+
ignoreLocation
|
|
1204
|
+
});
|
|
1205
|
+
if (isMatch) {
|
|
1206
|
+
hasMatches = true;
|
|
1207
|
+
}
|
|
1208
|
+
totalScore += score;
|
|
1209
|
+
if (isMatch && indices) {
|
|
1210
|
+
allIndices = [...allIndices, ...indices];
|
|
1211
|
+
}
|
|
1212
|
+
});
|
|
1213
|
+
let result = {
|
|
1214
|
+
isMatch: hasMatches,
|
|
1215
|
+
score: hasMatches ? totalScore / this.chunks.length : 1
|
|
1216
|
+
};
|
|
1217
|
+
if (hasMatches && includeMatches) {
|
|
1218
|
+
result.indices = allIndices;
|
|
1219
|
+
}
|
|
1220
|
+
return result;
|
|
1221
|
+
}
|
|
1222
|
+
};
|
|
1223
|
+
var BaseMatch = class {
|
|
1224
|
+
constructor(pattern) {
|
|
1225
|
+
this.pattern = pattern;
|
|
1226
|
+
}
|
|
1227
|
+
static isMultiMatch(pattern) {
|
|
1228
|
+
return getMatch(pattern, this.multiRegex);
|
|
1229
|
+
}
|
|
1230
|
+
static isSingleMatch(pattern) {
|
|
1231
|
+
return getMatch(pattern, this.singleRegex);
|
|
1232
|
+
}
|
|
1233
|
+
search() {
|
|
1234
|
+
}
|
|
1235
|
+
};
|
|
1236
|
+
function getMatch(pattern, exp) {
|
|
1237
|
+
const matches = pattern.match(exp);
|
|
1238
|
+
return matches ? matches[1] : null;
|
|
1239
|
+
}
|
|
1240
|
+
var ExactMatch = class extends BaseMatch {
|
|
1241
|
+
constructor(pattern) {
|
|
1242
|
+
super(pattern);
|
|
1243
|
+
}
|
|
1244
|
+
static get type() {
|
|
1245
|
+
return "exact";
|
|
1246
|
+
}
|
|
1247
|
+
static get multiRegex() {
|
|
1248
|
+
return /^="(.*)"$/;
|
|
1249
|
+
}
|
|
1250
|
+
static get singleRegex() {
|
|
1251
|
+
return /^=(.*)$/;
|
|
1252
|
+
}
|
|
1253
|
+
search(text) {
|
|
1254
|
+
const isMatch = text === this.pattern;
|
|
1255
|
+
return {
|
|
1256
|
+
isMatch,
|
|
1257
|
+
score: isMatch ? 0 : 1,
|
|
1258
|
+
indices: [0, this.pattern.length - 1]
|
|
1259
|
+
};
|
|
1260
|
+
}
|
|
1261
|
+
};
|
|
1262
|
+
var InverseExactMatch = class extends BaseMatch {
|
|
1263
|
+
constructor(pattern) {
|
|
1264
|
+
super(pattern);
|
|
1265
|
+
}
|
|
1266
|
+
static get type() {
|
|
1267
|
+
return "inverse-exact";
|
|
1268
|
+
}
|
|
1269
|
+
static get multiRegex() {
|
|
1270
|
+
return /^!"(.*)"$/;
|
|
1271
|
+
}
|
|
1272
|
+
static get singleRegex() {
|
|
1273
|
+
return /^!(.*)$/;
|
|
1274
|
+
}
|
|
1275
|
+
search(text) {
|
|
1276
|
+
const index = text.indexOf(this.pattern);
|
|
1277
|
+
const isMatch = index === -1;
|
|
1278
|
+
return {
|
|
1279
|
+
isMatch,
|
|
1280
|
+
score: isMatch ? 0 : 1,
|
|
1281
|
+
indices: [0, text.length - 1]
|
|
1282
|
+
};
|
|
1283
|
+
}
|
|
1284
|
+
};
|
|
1285
|
+
var PrefixExactMatch = class extends BaseMatch {
|
|
1286
|
+
constructor(pattern) {
|
|
1287
|
+
super(pattern);
|
|
1288
|
+
}
|
|
1289
|
+
static get type() {
|
|
1290
|
+
return "prefix-exact";
|
|
1291
|
+
}
|
|
1292
|
+
static get multiRegex() {
|
|
1293
|
+
return /^\^"(.*)"$/;
|
|
1294
|
+
}
|
|
1295
|
+
static get singleRegex() {
|
|
1296
|
+
return /^\^(.*)$/;
|
|
1297
|
+
}
|
|
1298
|
+
search(text) {
|
|
1299
|
+
const isMatch = text.startsWith(this.pattern);
|
|
1300
|
+
return {
|
|
1301
|
+
isMatch,
|
|
1302
|
+
score: isMatch ? 0 : 1,
|
|
1303
|
+
indices: [0, this.pattern.length - 1]
|
|
1304
|
+
};
|
|
1305
|
+
}
|
|
1306
|
+
};
|
|
1307
|
+
var InversePrefixExactMatch = class extends BaseMatch {
|
|
1308
|
+
constructor(pattern) {
|
|
1309
|
+
super(pattern);
|
|
1310
|
+
}
|
|
1311
|
+
static get type() {
|
|
1312
|
+
return "inverse-prefix-exact";
|
|
1313
|
+
}
|
|
1314
|
+
static get multiRegex() {
|
|
1315
|
+
return /^!\^"(.*)"$/;
|
|
1316
|
+
}
|
|
1317
|
+
static get singleRegex() {
|
|
1318
|
+
return /^!\^(.*)$/;
|
|
1319
|
+
}
|
|
1320
|
+
search(text) {
|
|
1321
|
+
const isMatch = !text.startsWith(this.pattern);
|
|
1322
|
+
return {
|
|
1323
|
+
isMatch,
|
|
1324
|
+
score: isMatch ? 0 : 1,
|
|
1325
|
+
indices: [0, text.length - 1]
|
|
1326
|
+
};
|
|
1327
|
+
}
|
|
1328
|
+
};
|
|
1329
|
+
var SuffixExactMatch = class extends BaseMatch {
|
|
1330
|
+
constructor(pattern) {
|
|
1331
|
+
super(pattern);
|
|
1332
|
+
}
|
|
1333
|
+
static get type() {
|
|
1334
|
+
return "suffix-exact";
|
|
1335
|
+
}
|
|
1336
|
+
static get multiRegex() {
|
|
1337
|
+
return /^"(.*)"\$$/;
|
|
1338
|
+
}
|
|
1339
|
+
static get singleRegex() {
|
|
1340
|
+
return /^(.*)\$$/;
|
|
1341
|
+
}
|
|
1342
|
+
search(text) {
|
|
1343
|
+
const isMatch = text.endsWith(this.pattern);
|
|
1344
|
+
return {
|
|
1345
|
+
isMatch,
|
|
1346
|
+
score: isMatch ? 0 : 1,
|
|
1347
|
+
indices: [text.length - this.pattern.length, text.length - 1]
|
|
1348
|
+
};
|
|
1349
|
+
}
|
|
1350
|
+
};
|
|
1351
|
+
var InverseSuffixExactMatch = class extends BaseMatch {
|
|
1352
|
+
constructor(pattern) {
|
|
1353
|
+
super(pattern);
|
|
1354
|
+
}
|
|
1355
|
+
static get type() {
|
|
1356
|
+
return "inverse-suffix-exact";
|
|
1357
|
+
}
|
|
1358
|
+
static get multiRegex() {
|
|
1359
|
+
return /^!"(.*)"\$$/;
|
|
1360
|
+
}
|
|
1361
|
+
static get singleRegex() {
|
|
1362
|
+
return /^!(.*)\$$/;
|
|
1363
|
+
}
|
|
1364
|
+
search(text) {
|
|
1365
|
+
const isMatch = !text.endsWith(this.pattern);
|
|
1366
|
+
return {
|
|
1367
|
+
isMatch,
|
|
1368
|
+
score: isMatch ? 0 : 1,
|
|
1369
|
+
indices: [0, text.length - 1]
|
|
1370
|
+
};
|
|
1371
|
+
}
|
|
1372
|
+
};
|
|
1373
|
+
var FuzzyMatch = class extends BaseMatch {
|
|
1374
|
+
constructor(pattern, {
|
|
1375
|
+
location = Config.location,
|
|
1376
|
+
threshold = Config.threshold,
|
|
1377
|
+
distance = Config.distance,
|
|
1378
|
+
includeMatches = Config.includeMatches,
|
|
1379
|
+
findAllMatches = Config.findAllMatches,
|
|
1380
|
+
minMatchCharLength = Config.minMatchCharLength,
|
|
1381
|
+
isCaseSensitive = Config.isCaseSensitive,
|
|
1382
|
+
ignoreDiacritics = Config.ignoreDiacritics,
|
|
1383
|
+
ignoreLocation = Config.ignoreLocation
|
|
1384
|
+
} = {}) {
|
|
1385
|
+
super(pattern);
|
|
1386
|
+
this._bitapSearch = new BitapSearch(pattern, {
|
|
1387
|
+
location,
|
|
1388
|
+
threshold,
|
|
1389
|
+
distance,
|
|
1390
|
+
includeMatches,
|
|
1391
|
+
findAllMatches,
|
|
1392
|
+
minMatchCharLength,
|
|
1393
|
+
isCaseSensitive,
|
|
1394
|
+
ignoreDiacritics,
|
|
1395
|
+
ignoreLocation
|
|
1396
|
+
});
|
|
1397
|
+
}
|
|
1398
|
+
static get type() {
|
|
1399
|
+
return "fuzzy";
|
|
1400
|
+
}
|
|
1401
|
+
static get multiRegex() {
|
|
1402
|
+
return /^"(.*)"$/;
|
|
1403
|
+
}
|
|
1404
|
+
static get singleRegex() {
|
|
1405
|
+
return /^(.*)$/;
|
|
1406
|
+
}
|
|
1407
|
+
search(text) {
|
|
1408
|
+
return this._bitapSearch.searchIn(text);
|
|
1409
|
+
}
|
|
1410
|
+
};
|
|
1411
|
+
var IncludeMatch = class extends BaseMatch {
|
|
1412
|
+
constructor(pattern) {
|
|
1413
|
+
super(pattern);
|
|
1414
|
+
}
|
|
1415
|
+
static get type() {
|
|
1416
|
+
return "include";
|
|
1417
|
+
}
|
|
1418
|
+
static get multiRegex() {
|
|
1419
|
+
return /^'"(.*)"$/;
|
|
1420
|
+
}
|
|
1421
|
+
static get singleRegex() {
|
|
1422
|
+
return /^'(.*)$/;
|
|
1423
|
+
}
|
|
1424
|
+
search(text) {
|
|
1425
|
+
let location = 0;
|
|
1426
|
+
let index;
|
|
1427
|
+
const indices = [];
|
|
1428
|
+
const patternLen = this.pattern.length;
|
|
1429
|
+
while ((index = text.indexOf(this.pattern, location)) > -1) {
|
|
1430
|
+
location = index + patternLen;
|
|
1431
|
+
indices.push([index, location - 1]);
|
|
1432
|
+
}
|
|
1433
|
+
const isMatch = !!indices.length;
|
|
1434
|
+
return {
|
|
1435
|
+
isMatch,
|
|
1436
|
+
score: isMatch ? 0 : 1,
|
|
1437
|
+
indices
|
|
1438
|
+
};
|
|
1439
|
+
}
|
|
1440
|
+
};
|
|
1441
|
+
var searchers = [
|
|
1442
|
+
ExactMatch,
|
|
1443
|
+
IncludeMatch,
|
|
1444
|
+
PrefixExactMatch,
|
|
1445
|
+
InversePrefixExactMatch,
|
|
1446
|
+
InverseSuffixExactMatch,
|
|
1447
|
+
SuffixExactMatch,
|
|
1448
|
+
InverseExactMatch,
|
|
1449
|
+
FuzzyMatch
|
|
1450
|
+
];
|
|
1451
|
+
var searchersLen = searchers.length;
|
|
1452
|
+
var SPACE_RE = / +(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)/;
|
|
1453
|
+
var OR_TOKEN = "|";
|
|
1454
|
+
function parseQuery(pattern, options = {}) {
|
|
1455
|
+
return pattern.split(OR_TOKEN).map((item) => {
|
|
1456
|
+
let query = item.trim().split(SPACE_RE).filter((item2) => item2 && !!item2.trim());
|
|
1457
|
+
let results = [];
|
|
1458
|
+
for (let i = 0, len = query.length; i < len; i += 1) {
|
|
1459
|
+
const queryItem = query[i];
|
|
1460
|
+
let found = false;
|
|
1461
|
+
let idx = -1;
|
|
1462
|
+
while (!found && ++idx < searchersLen) {
|
|
1463
|
+
const searcher = searchers[idx];
|
|
1464
|
+
let token = searcher.isMultiMatch(queryItem);
|
|
1465
|
+
if (token) {
|
|
1466
|
+
results.push(new searcher(token, options));
|
|
1467
|
+
found = true;
|
|
1468
|
+
}
|
|
1469
|
+
}
|
|
1470
|
+
if (found) {
|
|
1471
|
+
continue;
|
|
1472
|
+
}
|
|
1473
|
+
idx = -1;
|
|
1474
|
+
while (++idx < searchersLen) {
|
|
1475
|
+
const searcher = searchers[idx];
|
|
1476
|
+
let token = searcher.isSingleMatch(queryItem);
|
|
1477
|
+
if (token) {
|
|
1478
|
+
results.push(new searcher(token, options));
|
|
1479
|
+
break;
|
|
1480
|
+
}
|
|
1481
|
+
}
|
|
1482
|
+
}
|
|
1483
|
+
return results;
|
|
1484
|
+
});
|
|
1485
|
+
}
|
|
1486
|
+
var MultiMatchSet = /* @__PURE__ */ new Set([FuzzyMatch.type, IncludeMatch.type]);
|
|
1487
|
+
var ExtendedSearch = class {
|
|
1488
|
+
constructor(pattern, {
|
|
1489
|
+
isCaseSensitive = Config.isCaseSensitive,
|
|
1490
|
+
ignoreDiacritics = Config.ignoreDiacritics,
|
|
1491
|
+
includeMatches = Config.includeMatches,
|
|
1492
|
+
minMatchCharLength = Config.minMatchCharLength,
|
|
1493
|
+
ignoreLocation = Config.ignoreLocation,
|
|
1494
|
+
findAllMatches = Config.findAllMatches,
|
|
1495
|
+
location = Config.location,
|
|
1496
|
+
threshold = Config.threshold,
|
|
1497
|
+
distance = Config.distance
|
|
1498
|
+
} = {}) {
|
|
1499
|
+
this.query = null;
|
|
1500
|
+
this.options = {
|
|
1501
|
+
isCaseSensitive,
|
|
1502
|
+
ignoreDiacritics,
|
|
1503
|
+
includeMatches,
|
|
1504
|
+
minMatchCharLength,
|
|
1505
|
+
findAllMatches,
|
|
1506
|
+
ignoreLocation,
|
|
1507
|
+
location,
|
|
1508
|
+
threshold,
|
|
1509
|
+
distance
|
|
1510
|
+
};
|
|
1511
|
+
pattern = isCaseSensitive ? pattern : pattern.toLowerCase();
|
|
1512
|
+
pattern = ignoreDiacritics ? stripDiacritics(pattern) : pattern;
|
|
1513
|
+
this.pattern = pattern;
|
|
1514
|
+
this.query = parseQuery(this.pattern, this.options);
|
|
1515
|
+
}
|
|
1516
|
+
static condition(_6, options) {
|
|
1517
|
+
return options.useExtendedSearch;
|
|
1518
|
+
}
|
|
1519
|
+
searchIn(text) {
|
|
1520
|
+
const query = this.query;
|
|
1521
|
+
if (!query) {
|
|
1522
|
+
return {
|
|
1523
|
+
isMatch: false,
|
|
1524
|
+
score: 1
|
|
1525
|
+
};
|
|
1526
|
+
}
|
|
1527
|
+
const { includeMatches, isCaseSensitive, ignoreDiacritics } = this.options;
|
|
1528
|
+
text = isCaseSensitive ? text : text.toLowerCase();
|
|
1529
|
+
text = ignoreDiacritics ? stripDiacritics(text) : text;
|
|
1530
|
+
let numMatches = 0;
|
|
1531
|
+
let allIndices = [];
|
|
1532
|
+
let totalScore = 0;
|
|
1533
|
+
for (let i = 0, qLen = query.length; i < qLen; i += 1) {
|
|
1534
|
+
const searchers2 = query[i];
|
|
1535
|
+
allIndices.length = 0;
|
|
1536
|
+
numMatches = 0;
|
|
1537
|
+
for (let j = 0, pLen = searchers2.length; j < pLen; j += 1) {
|
|
1538
|
+
const searcher = searchers2[j];
|
|
1539
|
+
const { isMatch, indices, score } = searcher.search(text);
|
|
1540
|
+
if (isMatch) {
|
|
1541
|
+
numMatches += 1;
|
|
1542
|
+
totalScore += score;
|
|
1543
|
+
if (includeMatches) {
|
|
1544
|
+
const type = searcher.constructor.type;
|
|
1545
|
+
if (MultiMatchSet.has(type)) {
|
|
1546
|
+
allIndices = [...allIndices, ...indices];
|
|
1547
|
+
} else {
|
|
1548
|
+
allIndices.push(indices);
|
|
1549
|
+
}
|
|
1550
|
+
}
|
|
1551
|
+
} else {
|
|
1552
|
+
totalScore = 0;
|
|
1553
|
+
numMatches = 0;
|
|
1554
|
+
allIndices.length = 0;
|
|
1555
|
+
break;
|
|
1556
|
+
}
|
|
1557
|
+
}
|
|
1558
|
+
if (numMatches) {
|
|
1559
|
+
let result = {
|
|
1560
|
+
isMatch: true,
|
|
1561
|
+
score: totalScore / numMatches
|
|
1562
|
+
};
|
|
1563
|
+
if (includeMatches) {
|
|
1564
|
+
result.indices = allIndices;
|
|
1565
|
+
}
|
|
1566
|
+
return result;
|
|
1567
|
+
}
|
|
1568
|
+
}
|
|
1569
|
+
return {
|
|
1570
|
+
isMatch: false,
|
|
1571
|
+
score: 1
|
|
1572
|
+
};
|
|
1573
|
+
}
|
|
1574
|
+
};
|
|
1575
|
+
var registeredSearchers = [];
|
|
1576
|
+
function register(...args) {
|
|
1577
|
+
registeredSearchers.push(...args);
|
|
1578
|
+
}
|
|
1579
|
+
function createSearcher(pattern, options) {
|
|
1580
|
+
for (let i = 0, len = registeredSearchers.length; i < len; i += 1) {
|
|
1581
|
+
let searcherClass = registeredSearchers[i];
|
|
1582
|
+
if (searcherClass.condition(pattern, options)) {
|
|
1583
|
+
return new searcherClass(pattern, options);
|
|
1584
|
+
}
|
|
1585
|
+
}
|
|
1586
|
+
return new BitapSearch(pattern, options);
|
|
1587
|
+
}
|
|
1588
|
+
var LogicalOperator = {
|
|
1589
|
+
AND: "$and",
|
|
1590
|
+
OR: "$or"
|
|
1591
|
+
};
|
|
1592
|
+
var KeyType = {
|
|
1593
|
+
PATH: "$path",
|
|
1594
|
+
PATTERN: "$val"
|
|
1595
|
+
};
|
|
1596
|
+
var isExpression = (query) => !!(query[LogicalOperator.AND] || query[LogicalOperator.OR]);
|
|
1597
|
+
var isPath = (query) => !!query[KeyType.PATH];
|
|
1598
|
+
var isLeaf = (query) => !isArray(query) && isObject(query) && !isExpression(query);
|
|
1599
|
+
var convertToExplicit = (query) => ({
|
|
1600
|
+
[LogicalOperator.AND]: Object.keys(query).map((key) => ({
|
|
1601
|
+
[key]: query[key]
|
|
1602
|
+
}))
|
|
1603
|
+
});
|
|
1604
|
+
function parse(query, options, { auto = true } = {}) {
|
|
1605
|
+
const next = (query2) => {
|
|
1606
|
+
let keys = Object.keys(query2);
|
|
1607
|
+
const isQueryPath = isPath(query2);
|
|
1608
|
+
if (!isQueryPath && keys.length > 1 && !isExpression(query2)) {
|
|
1609
|
+
return next(convertToExplicit(query2));
|
|
1610
|
+
}
|
|
1611
|
+
if (isLeaf(query2)) {
|
|
1612
|
+
const key = isQueryPath ? query2[KeyType.PATH] : keys[0];
|
|
1613
|
+
const pattern = isQueryPath ? query2[KeyType.PATTERN] : query2[key];
|
|
1614
|
+
if (!isString(pattern)) {
|
|
1615
|
+
throw new Error(LOGICAL_SEARCH_INVALID_QUERY_FOR_KEY(key));
|
|
1616
|
+
}
|
|
1617
|
+
const obj = {
|
|
1618
|
+
keyId: createKeyId(key),
|
|
1619
|
+
pattern
|
|
1620
|
+
};
|
|
1621
|
+
if (auto) {
|
|
1622
|
+
obj.searcher = createSearcher(pattern, options);
|
|
1623
|
+
}
|
|
1624
|
+
return obj;
|
|
1625
|
+
}
|
|
1626
|
+
let node = {
|
|
1627
|
+
children: [],
|
|
1628
|
+
operator: keys[0]
|
|
1629
|
+
};
|
|
1630
|
+
keys.forEach((key) => {
|
|
1631
|
+
const value = query2[key];
|
|
1632
|
+
if (isArray(value)) {
|
|
1633
|
+
value.forEach((item) => {
|
|
1634
|
+
node.children.push(next(item));
|
|
1635
|
+
});
|
|
1636
|
+
}
|
|
1637
|
+
});
|
|
1638
|
+
return node;
|
|
1639
|
+
};
|
|
1640
|
+
if (!isExpression(query)) {
|
|
1641
|
+
query = convertToExplicit(query);
|
|
1642
|
+
}
|
|
1643
|
+
return next(query);
|
|
1644
|
+
}
|
|
1645
|
+
function computeScore(results, { ignoreFieldNorm = Config.ignoreFieldNorm }) {
|
|
1646
|
+
results.forEach((result) => {
|
|
1647
|
+
let totalScore = 1;
|
|
1648
|
+
result.matches.forEach(({ key, norm: norm2, score }) => {
|
|
1649
|
+
const weight = key ? key.weight : null;
|
|
1650
|
+
totalScore *= Math.pow(
|
|
1651
|
+
score === 0 && weight ? Number.EPSILON : score,
|
|
1652
|
+
(weight || 1) * (ignoreFieldNorm ? 1 : norm2)
|
|
1653
|
+
);
|
|
1654
|
+
});
|
|
1655
|
+
result.score = totalScore;
|
|
1656
|
+
});
|
|
1657
|
+
}
|
|
1658
|
+
function transformMatches(result, data) {
|
|
1659
|
+
const matches = result.matches;
|
|
1660
|
+
data.matches = [];
|
|
1661
|
+
if (!isDefined(matches)) {
|
|
1662
|
+
return;
|
|
1663
|
+
}
|
|
1664
|
+
matches.forEach((match) => {
|
|
1665
|
+
if (!isDefined(match.indices) || !match.indices.length) {
|
|
1666
|
+
return;
|
|
1667
|
+
}
|
|
1668
|
+
const { indices, value } = match;
|
|
1669
|
+
let obj = {
|
|
1670
|
+
indices,
|
|
1671
|
+
value
|
|
1672
|
+
};
|
|
1673
|
+
if (match.key) {
|
|
1674
|
+
obj.key = match.key.src;
|
|
1675
|
+
}
|
|
1676
|
+
if (match.idx > -1) {
|
|
1677
|
+
obj.refIndex = match.idx;
|
|
1678
|
+
}
|
|
1679
|
+
data.matches.push(obj);
|
|
1680
|
+
});
|
|
1681
|
+
}
|
|
1682
|
+
function transformScore(result, data) {
|
|
1683
|
+
data.score = result.score;
|
|
1684
|
+
}
|
|
1685
|
+
function format(results, docs, {
|
|
1686
|
+
includeMatches = Config.includeMatches,
|
|
1687
|
+
includeScore = Config.includeScore
|
|
1688
|
+
} = {}) {
|
|
1689
|
+
const transformers = [];
|
|
1690
|
+
if (includeMatches) transformers.push(transformMatches);
|
|
1691
|
+
if (includeScore) transformers.push(transformScore);
|
|
1692
|
+
return results.map((result) => {
|
|
1693
|
+
const { idx } = result;
|
|
1694
|
+
const data = {
|
|
1695
|
+
item: docs[idx],
|
|
1696
|
+
refIndex: idx
|
|
1697
|
+
};
|
|
1698
|
+
if (transformers.length) {
|
|
1699
|
+
transformers.forEach((transformer) => {
|
|
1700
|
+
transformer(result, data);
|
|
1701
|
+
});
|
|
1702
|
+
}
|
|
1703
|
+
return data;
|
|
1704
|
+
});
|
|
1705
|
+
}
|
|
1706
|
+
var Fuse = class {
|
|
1707
|
+
constructor(docs, options = {}, index) {
|
|
1708
|
+
this.options = { ...Config, ...options };
|
|
1709
|
+
if (this.options.useExtendedSearch && false) {
|
|
1710
|
+
throw new Error(EXTENDED_SEARCH_UNAVAILABLE);
|
|
1711
|
+
}
|
|
1712
|
+
this._keyStore = new KeyStore(this.options.keys);
|
|
1713
|
+
this.setCollection(docs, index);
|
|
1714
|
+
}
|
|
1715
|
+
setCollection(docs, index) {
|
|
1716
|
+
this._docs = docs;
|
|
1717
|
+
if (index && !(index instanceof FuseIndex)) {
|
|
1718
|
+
throw new Error(INCORRECT_INDEX_TYPE);
|
|
1719
|
+
}
|
|
1720
|
+
this._myIndex = index || createIndex(this.options.keys, this._docs, {
|
|
1721
|
+
getFn: this.options.getFn,
|
|
1722
|
+
fieldNormWeight: this.options.fieldNormWeight
|
|
1723
|
+
});
|
|
1724
|
+
}
|
|
1725
|
+
add(doc) {
|
|
1726
|
+
if (!isDefined(doc)) {
|
|
1727
|
+
return;
|
|
1728
|
+
}
|
|
1729
|
+
this._docs.push(doc);
|
|
1730
|
+
this._myIndex.add(doc);
|
|
1731
|
+
}
|
|
1732
|
+
remove(predicate = () => false) {
|
|
1733
|
+
const results = [];
|
|
1734
|
+
for (let i = 0, len = this._docs.length; i < len; i += 1) {
|
|
1735
|
+
const doc = this._docs[i];
|
|
1736
|
+
if (predicate(doc, i)) {
|
|
1737
|
+
this.removeAt(i);
|
|
1738
|
+
i -= 1;
|
|
1739
|
+
len -= 1;
|
|
1740
|
+
results.push(doc);
|
|
1741
|
+
}
|
|
1742
|
+
}
|
|
1743
|
+
return results;
|
|
1744
|
+
}
|
|
1745
|
+
removeAt(idx) {
|
|
1746
|
+
this._docs.splice(idx, 1);
|
|
1747
|
+
this._myIndex.removeAt(idx);
|
|
1748
|
+
}
|
|
1749
|
+
getIndex() {
|
|
1750
|
+
return this._myIndex;
|
|
1751
|
+
}
|
|
1752
|
+
search(query, { limit = -1 } = {}) {
|
|
1753
|
+
const {
|
|
1754
|
+
includeMatches,
|
|
1755
|
+
includeScore,
|
|
1756
|
+
shouldSort,
|
|
1757
|
+
sortFn,
|
|
1758
|
+
ignoreFieldNorm
|
|
1759
|
+
} = this.options;
|
|
1760
|
+
let results = isString(query) ? isString(this._docs[0]) ? this._searchStringList(query) : this._searchObjectList(query) : this._searchLogical(query);
|
|
1761
|
+
computeScore(results, { ignoreFieldNorm });
|
|
1762
|
+
if (shouldSort) {
|
|
1763
|
+
results.sort(sortFn);
|
|
1764
|
+
}
|
|
1765
|
+
if (isNumber(limit) && limit > -1) {
|
|
1766
|
+
results = results.slice(0, limit);
|
|
1767
|
+
}
|
|
1768
|
+
return format(results, this._docs, {
|
|
1769
|
+
includeMatches,
|
|
1770
|
+
includeScore
|
|
1771
|
+
});
|
|
1772
|
+
}
|
|
1773
|
+
_searchStringList(query) {
|
|
1774
|
+
const searcher = createSearcher(query, this.options);
|
|
1775
|
+
const { records } = this._myIndex;
|
|
1776
|
+
const results = [];
|
|
1777
|
+
records.forEach(({ v: text, i: idx, n: norm2 }) => {
|
|
1778
|
+
if (!isDefined(text)) {
|
|
1779
|
+
return;
|
|
1780
|
+
}
|
|
1781
|
+
const { isMatch, score, indices } = searcher.searchIn(text);
|
|
1782
|
+
if (isMatch) {
|
|
1783
|
+
results.push({
|
|
1784
|
+
item: text,
|
|
1785
|
+
idx,
|
|
1786
|
+
matches: [{ score, value: text, norm: norm2, indices }]
|
|
1787
|
+
});
|
|
1788
|
+
}
|
|
1789
|
+
});
|
|
1790
|
+
return results;
|
|
1791
|
+
}
|
|
1792
|
+
_searchLogical(query) {
|
|
1793
|
+
const expression = parse(query, this.options);
|
|
1794
|
+
const evaluate = (node, item, idx) => {
|
|
1795
|
+
if (!node.children) {
|
|
1796
|
+
const { keyId, searcher } = node;
|
|
1797
|
+
const matches = this._findMatches({
|
|
1798
|
+
key: this._keyStore.get(keyId),
|
|
1799
|
+
value: this._myIndex.getValueForItemAtKeyId(item, keyId),
|
|
1800
|
+
searcher
|
|
1801
|
+
});
|
|
1802
|
+
if (matches && matches.length) {
|
|
1803
|
+
return [
|
|
1804
|
+
{
|
|
1805
|
+
idx,
|
|
1806
|
+
item,
|
|
1807
|
+
matches
|
|
1808
|
+
}
|
|
1809
|
+
];
|
|
1810
|
+
}
|
|
1811
|
+
return [];
|
|
1812
|
+
}
|
|
1813
|
+
const res = [];
|
|
1814
|
+
for (let i = 0, len = node.children.length; i < len; i += 1) {
|
|
1815
|
+
const child = node.children[i];
|
|
1816
|
+
const result = evaluate(child, item, idx);
|
|
1817
|
+
if (result.length) {
|
|
1818
|
+
res.push(...result);
|
|
1819
|
+
} else if (node.operator === LogicalOperator.AND) {
|
|
1820
|
+
return [];
|
|
1821
|
+
}
|
|
1822
|
+
}
|
|
1823
|
+
return res;
|
|
1824
|
+
};
|
|
1825
|
+
const records = this._myIndex.records;
|
|
1826
|
+
const resultMap = {};
|
|
1827
|
+
const results = [];
|
|
1828
|
+
records.forEach(({ $: item, i: idx }) => {
|
|
1829
|
+
if (isDefined(item)) {
|
|
1830
|
+
let expResults = evaluate(expression, item, idx);
|
|
1831
|
+
if (expResults.length) {
|
|
1832
|
+
if (!resultMap[idx]) {
|
|
1833
|
+
resultMap[idx] = { idx, item, matches: [] };
|
|
1834
|
+
results.push(resultMap[idx]);
|
|
1835
|
+
}
|
|
1836
|
+
expResults.forEach(({ matches }) => {
|
|
1837
|
+
resultMap[idx].matches.push(...matches);
|
|
1838
|
+
});
|
|
1839
|
+
}
|
|
1840
|
+
}
|
|
1841
|
+
});
|
|
1842
|
+
return results;
|
|
1843
|
+
}
|
|
1844
|
+
_searchObjectList(query) {
|
|
1845
|
+
const searcher = createSearcher(query, this.options);
|
|
1846
|
+
const { keys, records } = this._myIndex;
|
|
1847
|
+
const results = [];
|
|
1848
|
+
records.forEach(({ $: item, i: idx }) => {
|
|
1849
|
+
if (!isDefined(item)) {
|
|
1850
|
+
return;
|
|
1851
|
+
}
|
|
1852
|
+
let matches = [];
|
|
1853
|
+
keys.forEach((key, keyIndex) => {
|
|
1854
|
+
matches.push(
|
|
1855
|
+
...this._findMatches({
|
|
1856
|
+
key,
|
|
1857
|
+
value: item[keyIndex],
|
|
1858
|
+
searcher
|
|
1859
|
+
})
|
|
1860
|
+
);
|
|
1861
|
+
});
|
|
1862
|
+
if (matches.length) {
|
|
1863
|
+
results.push({
|
|
1864
|
+
idx,
|
|
1865
|
+
item,
|
|
1866
|
+
matches
|
|
1867
|
+
});
|
|
1868
|
+
}
|
|
1869
|
+
});
|
|
1870
|
+
return results;
|
|
1871
|
+
}
|
|
1872
|
+
_findMatches({ key, value, searcher }) {
|
|
1873
|
+
if (!isDefined(value)) {
|
|
1874
|
+
return [];
|
|
1875
|
+
}
|
|
1876
|
+
let matches = [];
|
|
1877
|
+
if (isArray(value)) {
|
|
1878
|
+
value.forEach(({ v: text, i: idx, n: norm2 }) => {
|
|
1879
|
+
if (!isDefined(text)) {
|
|
1880
|
+
return;
|
|
1881
|
+
}
|
|
1882
|
+
const { isMatch, score, indices } = searcher.searchIn(text);
|
|
1883
|
+
if (isMatch) {
|
|
1884
|
+
matches.push({
|
|
1885
|
+
score,
|
|
1886
|
+
key,
|
|
1887
|
+
value: text,
|
|
1888
|
+
idx,
|
|
1889
|
+
norm: norm2,
|
|
1890
|
+
indices
|
|
1891
|
+
});
|
|
1892
|
+
}
|
|
1893
|
+
});
|
|
1894
|
+
} else {
|
|
1895
|
+
const { v: text, n: norm2 } = value;
|
|
1896
|
+
const { isMatch, score, indices } = searcher.searchIn(text);
|
|
1897
|
+
if (isMatch) {
|
|
1898
|
+
matches.push({ score, key, value: text, norm: norm2, indices });
|
|
1899
|
+
}
|
|
1900
|
+
}
|
|
1901
|
+
return matches;
|
|
1902
|
+
}
|
|
1903
|
+
};
|
|
1904
|
+
Fuse.version = "7.1.0";
|
|
1905
|
+
Fuse.createIndex = createIndex;
|
|
1906
|
+
Fuse.parseIndex = parseIndex;
|
|
1907
|
+
Fuse.config = Config;
|
|
1908
|
+
{
|
|
1909
|
+
Fuse.parseQuery = parse;
|
|
1910
|
+
}
|
|
1911
|
+
{
|
|
1912
|
+
register(ExtendedSearch);
|
|
1913
|
+
}
|
|
1914
|
+
|
|
1915
|
+
// src/data/search/utils/sanitizeInput.ts
|
|
1916
|
+
var sanitizeInput = (str) => str.replace(/[\u200E\u200F\u202A-\u202E\u2066-\u2069]/g, "").replace(/[\-–—_./()]+/g, "").normalize("NFC").trim();
|
|
1917
|
+
|
|
1918
|
+
// src/data/search/getSearchClient.ts
|
|
1919
|
+
var getSearchClient = ({ occupants, amenities }) => {
|
|
1920
|
+
const fuseAmenities = new Fuse(amenities, { threshold: 0.2 });
|
|
1921
|
+
const fuseOccupants = new Fuse(occupants, {
|
|
1922
|
+
threshold: 0.3,
|
|
1923
|
+
// 0.2 is too strict (can't find Mo-Mo Paradise with "momo" search string)
|
|
1924
|
+
includeScore: true,
|
|
1925
|
+
keys: [
|
|
1926
|
+
{ name: "properties.name", "weight": 4, getFn: (obj) => Object.values(obj.properties.name) },
|
|
1927
|
+
{ name: "properties.category", "weight": 0.25 },
|
|
1928
|
+
{
|
|
1929
|
+
name: "properties.local_categories",
|
|
1930
|
+
"weight": 0.25,
|
|
1931
|
+
getFn: (occ) => occ.properties.local_categories.map((cat3) => Object.values(cat3.properties.name)).flat()
|
|
1932
|
+
},
|
|
1933
|
+
{ name: "properties.keywords", "weight": 0.25 },
|
|
1934
|
+
{ name: "properties.description", "weight": 0.25, getFn: (occ) => Object.values(occ.properties.description || {}) },
|
|
1935
|
+
{ name: "properties.unit.properties.name", "weight": 0.25, getFn: (obj) => Object.values(obj.properties.unit?.properties.name || {}) },
|
|
1936
|
+
{ name: "properties.kiosk.properties.name", "weight": 0.25, getFn: (obj) => Object.values(obj.properties.kiosk?.properties.name || {}) }
|
|
1937
|
+
]
|
|
1938
|
+
});
|
|
1939
|
+
const fuseFuzzyAmenities = new Fuse(amenities, {
|
|
1940
|
+
threshold: 0.2,
|
|
1941
|
+
keys: [
|
|
1942
|
+
{ name: "properties.category", weight: 4 }
|
|
1943
|
+
]
|
|
1944
|
+
});
|
|
1945
|
+
const search2 = (value) => {
|
|
1946
|
+
const sanitizedValue = sanitizeInput(value);
|
|
1947
|
+
const matchedAmenities = fuseAmenities.search(sanitizedValue);
|
|
1948
|
+
if (matchedAmenities.length > 0) return matchedAmenities;
|
|
1949
|
+
const matchedOccupants = fuseOccupants.search(sanitizedValue);
|
|
1950
|
+
if (matchedOccupants.length > 0) return matchedOccupants;
|
|
1951
|
+
const matchedFuzzyAmenities = fuseFuzzyAmenities.search(sanitizedValue);
|
|
1952
|
+
if (matchedFuzzyAmenities.length > 0) return matchedFuzzyAmenities;
|
|
1953
|
+
return [];
|
|
1954
|
+
};
|
|
1955
|
+
return {
|
|
1956
|
+
search: search2
|
|
574
1957
|
};
|
|
575
1958
|
};
|
|
576
1959
|
|
|
577
1960
|
// src/data/getDataClient.ts
|
|
578
1961
|
var getDataClient = (options) => {
|
|
1962
|
+
let searchClient;
|
|
579
1963
|
const observers = /* @__PURE__ */ new Map();
|
|
580
1964
|
const queryClient = options.queryClient ?? new QueryClient();
|
|
581
1965
|
const { mode = "delivery", projectId, apiKey, baseUrl, previewToken } = options;
|
|
@@ -604,7 +1988,7 @@ var getDataClient = (options) => {
|
|
|
604
1988
|
}
|
|
605
1989
|
};
|
|
606
1990
|
const internalFindById = async (id) => {
|
|
607
|
-
if (id === null) return null;
|
|
1991
|
+
if (id === null || id === void 0) return null;
|
|
608
1992
|
const featureType = id.slice(0, id.lastIndexOf("-"));
|
|
609
1993
|
const feature2 = await queryClient.ensureQueryData({
|
|
610
1994
|
queryKey: ["_deliveryapi", featureType, id],
|
|
@@ -687,6 +2071,17 @@ var getDataClient = (options) => {
|
|
|
687
2071
|
const feature2 = await queryClient.ensureQueryData(findQueryOptions);
|
|
688
2072
|
return feature2;
|
|
689
2073
|
}
|
|
2074
|
+
const searchFn = async (txt) => {
|
|
2075
|
+
if (!searchClient) {
|
|
2076
|
+
const [occupants, amenities] = await Promise.all([
|
|
2077
|
+
filterByType("occupant", { populate: true }),
|
|
2078
|
+
filterByType("amenity")
|
|
2079
|
+
]);
|
|
2080
|
+
const haystack = { occupants, amenities };
|
|
2081
|
+
searchClient = getSearchClient(haystack);
|
|
2082
|
+
}
|
|
2083
|
+
return searchClient.search(txt);
|
|
2084
|
+
};
|
|
690
2085
|
return {
|
|
691
2086
|
projectId,
|
|
692
2087
|
queryClient,
|
|
@@ -696,7 +2091,8 @@ var getDataClient = (options) => {
|
|
|
696
2091
|
createFilterByTypeQueryOptions,
|
|
697
2092
|
createFindByIdQueryOptions,
|
|
698
2093
|
filterByType,
|
|
699
|
-
findById
|
|
2094
|
+
findById,
|
|
2095
|
+
search: searchFn
|
|
700
2096
|
};
|
|
701
2097
|
};
|
|
702
2098
|
|
|
@@ -754,7 +2150,7 @@ function point(coordinates, properties, options = {}) {
|
|
|
754
2150
|
if (coordinates.length < 2) {
|
|
755
2151
|
throw new Error("coordinates must be at least 2 numbers long");
|
|
756
2152
|
}
|
|
757
|
-
if (!
|
|
2153
|
+
if (!isNumber2(coordinates[0]) || !isNumber2(coordinates[1])) {
|
|
758
2154
|
throw new Error("coordinates must contain numbers");
|
|
759
2155
|
}
|
|
760
2156
|
const geom = {
|
|
@@ -813,7 +2209,7 @@ function multiPoint(coordinates, properties, options = {}) {
|
|
|
813
2209
|
};
|
|
814
2210
|
return feature(geom, properties, options);
|
|
815
2211
|
}
|
|
816
|
-
function
|
|
2212
|
+
function isNumber2(num) {
|
|
817
2213
|
return !isNaN(num) && num !== null && !Array.isArray(num);
|
|
818
2214
|
}
|
|
819
2215
|
|
|
@@ -2683,7 +4079,7 @@ var CameraManager = class {
|
|
|
2683
4079
|
// src/IndoorMap/renderer/RendererManager.ts
|
|
2684
4080
|
import { min, compact as compact3, isFunction } from "lodash-es";
|
|
2685
4081
|
import { center as turfCenter2 } from "@turf/center";
|
|
2686
|
-
import * as
|
|
4082
|
+
import * as THREE4 from "three";
|
|
2687
4083
|
|
|
2688
4084
|
// src/IndoorMap/renderer/3d/Element3DRenderer.ts
|
|
2689
4085
|
import * as maptalks4 from "maptalks-gl";
|
|
@@ -2706,7 +4102,7 @@ import {
|
|
|
2706
4102
|
PlaneGeometry
|
|
2707
4103
|
} from "three";
|
|
2708
4104
|
import { largestRect } from "d3plus-shape";
|
|
2709
|
-
import { max, merge, isNumber as
|
|
4105
|
+
import { max, merge, isNumber as isNumber3, isArray as isArray2, range } from "lodash-es";
|
|
2710
4106
|
var OPTIONS3 = {
|
|
2711
4107
|
// Allowing click through and prevent interaction
|
|
2712
4108
|
interactive: false,
|
|
@@ -2852,7 +4248,7 @@ var GroundLabel = class extends BaseObject4 {
|
|
|
2852
4248
|
strokeStyle,
|
|
2853
4249
|
lineWidth
|
|
2854
4250
|
});
|
|
2855
|
-
const rectAngles =
|
|
4251
|
+
const rectAngles = isArray2(angle) ? angle : [angle];
|
|
2856
4252
|
material.needsUpdate = true;
|
|
2857
4253
|
const rect = largestRect(bound, {
|
|
2858
4254
|
cache: true,
|
|
@@ -2925,32 +4321,32 @@ var GroundLabel = class extends BaseObject4 {
|
|
|
2925
4321
|
return { x: this.#offsetX, y: this.#offsetY };
|
|
2926
4322
|
}
|
|
2927
4323
|
set offsetX(value) {
|
|
2928
|
-
if (
|
|
4324
|
+
if (isNumber3(value)) {
|
|
2929
4325
|
this.#offsetX = value;
|
|
2930
4326
|
this.#updatePosition();
|
|
2931
4327
|
}
|
|
2932
4328
|
}
|
|
2933
4329
|
set offsetY(value) {
|
|
2934
|
-
if (
|
|
4330
|
+
if (isNumber3(value)) {
|
|
2935
4331
|
this.#offsetY = value;
|
|
2936
4332
|
this.#updatePosition();
|
|
2937
4333
|
}
|
|
2938
4334
|
}
|
|
2939
4335
|
set angle(newAngle) {
|
|
2940
|
-
if (
|
|
4336
|
+
if (isNumber3(newAngle)) {
|
|
2941
4337
|
this.#angle = newAngle;
|
|
2942
4338
|
this.getObject3d().rotation.z = Math.PI / 180 * this.#angle;
|
|
2943
4339
|
}
|
|
2944
4340
|
}
|
|
2945
4341
|
setOffset(offsetX, offsetY) {
|
|
2946
|
-
if (
|
|
4342
|
+
if (isNumber3(offsetX) && isNumber3(offsetY)) {
|
|
2947
4343
|
this.#offsetX = offsetX;
|
|
2948
4344
|
this.#offsetY = offsetY;
|
|
2949
4345
|
this.#updatePosition();
|
|
2950
4346
|
}
|
|
2951
4347
|
}
|
|
2952
4348
|
addOffset(deltaX, deltaY) {
|
|
2953
|
-
if (
|
|
4349
|
+
if (isNumber3(deltaX) && isNumber3(deltaY)) {
|
|
2954
4350
|
this.#offsetX += deltaX;
|
|
2955
4351
|
this.#offsetY += deltaY;
|
|
2956
4352
|
this.#updatePosition();
|
|
@@ -3032,7 +4428,7 @@ var DEFAULT_POLYGON_OPTION = {
|
|
|
3032
4428
|
offset: 0,
|
|
3033
4429
|
altitude: 0
|
|
3034
4430
|
};
|
|
3035
|
-
var get3DRendererOption = (featureType, category, options) => {
|
|
4431
|
+
var get3DRendererOption = (featureType, category, options = {}) => {
|
|
3036
4432
|
try {
|
|
3037
4433
|
const option = options[featureType] ?? element3DRendererOptions[featureType];
|
|
3038
4434
|
return (category && option.byCategory?.[category]) ?? option?.default ?? DEFAULT_POLYGON_OPTION;
|
|
@@ -3493,6 +4889,12 @@ var Marker2DRenderer = class extends EventTarget {
|
|
|
3493
4889
|
marker.addTo(this.map);
|
|
3494
4890
|
return marker;
|
|
3495
4891
|
};
|
|
4892
|
+
createTextMarker = (position, label, options) => {
|
|
4893
|
+
return null;
|
|
4894
|
+
};
|
|
4895
|
+
createImageMarker = (position, src, options) => {
|
|
4896
|
+
return null;
|
|
4897
|
+
};
|
|
3496
4898
|
removeMarker = (marker) => {
|
|
3497
4899
|
marker.remove();
|
|
3498
4900
|
};
|
|
@@ -3504,6 +4906,7 @@ var Marker2DRenderer = class extends EventTarget {
|
|
|
3504
4906
|
|
|
3505
4907
|
// src/IndoorMap/renderer/3d/Marker3DRenderer.ts
|
|
3506
4908
|
import * as maptalks7 from "maptalks-gl";
|
|
4909
|
+
import * as THREE3 from "three";
|
|
3507
4910
|
|
|
3508
4911
|
// src/IndoorMap/renderer/3d/objects/TextSpriteMarker.ts
|
|
3509
4912
|
import { Coordinate as Coordinate2, Util as Util4 } from "maptalks";
|
|
@@ -3703,21 +5106,35 @@ var TextSpriteMarker = class extends BaseObject6 {
|
|
|
3703
5106
|
};
|
|
3704
5107
|
|
|
3705
5108
|
// src/IndoorMap/renderer/3d/Marker3DRenderer.ts
|
|
3706
|
-
var HEIGHT_METER2 = 4;
|
|
3707
|
-
var MULTIORDINAL_HEIGHT_METER3 = 9;
|
|
3708
5109
|
var Marker3DRenderer = class extends EventTarget {
|
|
3709
5110
|
isReady = false;
|
|
3710
5111
|
threeLayer;
|
|
3711
5112
|
map;
|
|
3712
|
-
materialByKey;
|
|
3713
5113
|
constructor(map, options, layer) {
|
|
3714
5114
|
super();
|
|
3715
5115
|
this.map = map;
|
|
3716
5116
|
this.threeLayer = layer;
|
|
3717
5117
|
}
|
|
3718
|
-
|
|
5118
|
+
createPointMaterialFromSvg(svgPath, size = 40) {
|
|
5119
|
+
return new THREE3.PointsMaterial({
|
|
5120
|
+
size,
|
|
5121
|
+
sizeAttenuation: false,
|
|
5122
|
+
// Always same size in screen pixels (Screen pixel)
|
|
5123
|
+
// color: fillStyle,
|
|
5124
|
+
alphaTest: 0.5,
|
|
5125
|
+
// vertexColors: THREE.VertexColors,
|
|
5126
|
+
// color: 0xffffff,
|
|
5127
|
+
transparent: true,
|
|
5128
|
+
blending: THREE3.NormalBlending,
|
|
5129
|
+
depthTest: true,
|
|
5130
|
+
// POI is hidden behind building
|
|
5131
|
+
depthWrite: true,
|
|
5132
|
+
map: new THREE3.TextureLoader().load(svgPath)
|
|
5133
|
+
});
|
|
5134
|
+
}
|
|
5135
|
+
createTextMarker = (position, label, options) => {
|
|
3719
5136
|
const combinedOptions = {
|
|
3720
|
-
altitude:
|
|
5137
|
+
altitude: 0,
|
|
3721
5138
|
text: label,
|
|
3722
5139
|
...options ?? {}
|
|
3723
5140
|
};
|
|
@@ -3726,17 +5143,37 @@ var Marker3DRenderer = class extends EventTarget {
|
|
|
3726
5143
|
this.threeLayer.addMesh([marker]);
|
|
3727
5144
|
return marker;
|
|
3728
5145
|
};
|
|
3729
|
-
createImageMarker = () => {
|
|
3730
|
-
|
|
3731
|
-
|
|
3732
|
-
|
|
5146
|
+
createImageMarker = (position, src, options) => {
|
|
5147
|
+
const [lng, lat] = position;
|
|
5148
|
+
let meshes = [];
|
|
5149
|
+
const height = options.height ?? 0;
|
|
5150
|
+
const { leg, ...markerOptions } = options;
|
|
5151
|
+
const { color: legColor = "#000000", ...legOptions } = leg ?? {};
|
|
5152
|
+
const material = this.createPointMaterialFromSvg(src, 40);
|
|
5153
|
+
const marker = this.threeLayer.toPoint(new maptalks7.Coordinate(lng, lat), { height, ...markerOptions }, material);
|
|
5154
|
+
marker.getObject3d().renderOrder = 10;
|
|
5155
|
+
meshes.push(marker);
|
|
5156
|
+
if (options.leg) {
|
|
5157
|
+
const legMaterial = new THREE3.MeshLambertMaterial({ color: legColor, transparent: true });
|
|
5158
|
+
const leg2 = this.threeLayer.toBar(new maptalks7.Coordinate(lng, lat), { ...legOptions, height }, legMaterial);
|
|
5159
|
+
const legObj = leg2.getObject3d();
|
|
5160
|
+
legObj.traverse((o) => {
|
|
5161
|
+
if (o.isMesh && o.material) {
|
|
5162
|
+
o.material.depthWrite = false;
|
|
5163
|
+
o.material.depthTest = true;
|
|
5164
|
+
o.renderOrder = 0;
|
|
5165
|
+
}
|
|
5166
|
+
});
|
|
5167
|
+
meshes = [leg2, ...meshes];
|
|
5168
|
+
}
|
|
5169
|
+
this.threeLayer.addMesh(meshes);
|
|
5170
|
+
return meshes;
|
|
3733
5171
|
};
|
|
3734
5172
|
removeMarker = (marker) => {
|
|
3735
5173
|
marker.remove();
|
|
3736
5174
|
};
|
|
3737
5175
|
showMarkers(elements, ordinalDiff = 0) {
|
|
3738
5176
|
elements.forEach((element) => {
|
|
3739
|
-
element.setAltitude(ordinalDiff * MULTIORDINAL_HEIGHT_METER3);
|
|
3740
5177
|
element.show();
|
|
3741
5178
|
});
|
|
3742
5179
|
}
|
|
@@ -4275,7 +5712,11 @@ function inBBox(pt, bbox2) {
|
|
|
4275
5712
|
|
|
4276
5713
|
// src/IndoorMap/renderer/utils/findUnitOnPoint.ts
|
|
4277
5714
|
var findUnitOnPoint = (units, point2) => {
|
|
4278
|
-
|
|
5715
|
+
try {
|
|
5716
|
+
return units.find((unit) => booleanPointInPolygon(point2, polygon(unit.geometry.coordinates)));
|
|
5717
|
+
} catch (err) {
|
|
5718
|
+
return null;
|
|
5719
|
+
}
|
|
4279
5720
|
};
|
|
4280
5721
|
|
|
4281
5722
|
// src/IndoorMap/renderer/RendererManager.ts
|
|
@@ -4345,13 +5786,13 @@ var RendererManager = class extends EventTarget {
|
|
|
4345
5786
|
}
|
|
4346
5787
|
return bad;
|
|
4347
5788
|
}
|
|
4348
|
-
const ambientLight = new
|
|
5789
|
+
const ambientLight = new THREE4.AmbientLight(16777215, 0.3);
|
|
4349
5790
|
scene.add(ambientLight);
|
|
4350
5791
|
const dirColor = 16777215;
|
|
4351
|
-
const dllight = new
|
|
5792
|
+
const dllight = new THREE4.DirectionalLight(dirColor, 0.8);
|
|
4352
5793
|
dllight.position.set(0, -10, 20).normalize();
|
|
4353
5794
|
scene.add(dllight);
|
|
4354
|
-
const hemi = new
|
|
5795
|
+
const hemi = new THREE4.HemisphereLight(16777215, 4473924, 0.4);
|
|
4355
5796
|
scene.add(hemi);
|
|
4356
5797
|
_this.elementRenderer = new Element3DRenderer(map, options.elements);
|
|
4357
5798
|
_this.markerRenderer = new Marker3DRenderer(map, {}, threeLayer);
|
|
@@ -4434,7 +5875,7 @@ var RendererManager = class extends EventTarget {
|
|
|
4434
5875
|
return openings.find((o) => o.id === openingId);
|
|
4435
5876
|
}));
|
|
4436
5877
|
const innerElements = this.elementRenderer.createGeometry(unit);
|
|
4437
|
-
const wallElements =
|
|
5878
|
+
const wallElements = [];
|
|
4438
5879
|
if (innerElements || wallElements) {
|
|
4439
5880
|
const _innerElements = Array.isArray(innerElements) ? innerElements : [innerElements];
|
|
4440
5881
|
const _wallElements = Array.isArray(wallElements) ? wallElements : [wallElements];
|
|
@@ -4489,10 +5930,12 @@ var RendererManager = class extends EventTarget {
|
|
|
4489
5930
|
for (const label of groundLabels) {
|
|
4490
5931
|
const center2 = turfCenter2(polygon(label.geometry.coordinates)).geometry.coordinates;
|
|
4491
5932
|
const unit = findUnitOnPoint(units, center2);
|
|
4492
|
-
|
|
4493
|
-
|
|
4494
|
-
|
|
4495
|
-
|
|
5933
|
+
if (unit) {
|
|
5934
|
+
const element = this.elementRenderer.createGroundLabel(label, unit);
|
|
5935
|
+
if (element) {
|
|
5936
|
+
const _elements = Array.isArray(element) ? element : [element];
|
|
5937
|
+
this.addElementsToManager(label.id, _elements, label.properties.ordinal);
|
|
5938
|
+
}
|
|
4496
5939
|
}
|
|
4497
5940
|
}
|
|
4498
5941
|
if (this.options.type === "3D") {
|
|
@@ -4574,10 +6017,11 @@ var RendererManager = class extends EventTarget {
|
|
|
4574
6017
|
this.markerRenderer.hideMarkers(markers, ordinal);
|
|
4575
6018
|
}
|
|
4576
6019
|
};
|
|
4577
|
-
createMarker(coordinate, ordinal,
|
|
4578
|
-
const
|
|
6020
|
+
createMarker(type, coordinate, ordinal, textOrPath, options) {
|
|
6021
|
+
const meshes = type === "text" ? this.markerRenderer.createTextMarker(coordinate, textOrPath, options) : this.markerRenderer.createImageMarker(coordinate, textOrPath, options);
|
|
4579
6022
|
const markerId = `${this.markersMap.size + 1}`;
|
|
4580
|
-
|
|
6023
|
+
const markerMeshes = Array.isArray(meshes) ? meshes : [meshes];
|
|
6024
|
+
this._addMarkersToManager(markerId, markerMeshes, ordinal);
|
|
4581
6025
|
}
|
|
4582
6026
|
clearMarkers() {
|
|
4583
6027
|
for (const [markerId, marker] of this.markersMap) {
|
|
@@ -4717,6 +6161,7 @@ var IndoorMap = class extends EventTarget {
|
|
|
4717
6161
|
this.#dataClient = value;
|
|
4718
6162
|
if (!this.options.camera?.defaultView?.center) {
|
|
4719
6163
|
this.#dataClient.filterByType("venue").then((venues) => {
|
|
6164
|
+
this.#venues = venues;
|
|
4720
6165
|
const venueCenters = turfCenter3(featureCollection(venues));
|
|
4721
6166
|
const [x, y] = venueCenters.geometry.coordinates;
|
|
4722
6167
|
const center2 = new Coordinate4(x, y);
|