cmpstr 3.2.1 → 3.2.2
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/README.md +24 -18
- package/dist/CmpStr.esm.js +485 -220
- package/dist/CmpStr.esm.min.js +2 -3
- package/dist/CmpStr.umd.js +484 -220
- package/dist/CmpStr.umd.min.js +2 -3
- package/dist/cjs/CmpStr.cjs +57 -36
- package/dist/cjs/CmpStrAsync.cjs +30 -24
- package/dist/cjs/index.cjs +1 -2
- package/dist/cjs/metric/Cosine.cjs +1 -2
- package/dist/cjs/metric/DamerauLevenshtein.cjs +1 -2
- package/dist/cjs/metric/DiceSorensen.cjs +1 -2
- package/dist/cjs/metric/Hamming.cjs +5 -4
- package/dist/cjs/metric/Jaccard.cjs +1 -2
- package/dist/cjs/metric/JaroWinkler.cjs +1 -2
- package/dist/cjs/metric/LCS.cjs +1 -2
- package/dist/cjs/metric/Levenshtein.cjs +1 -2
- package/dist/cjs/metric/Metric.cjs +57 -38
- package/dist/cjs/metric/NeedlemanWunsch.cjs +1 -2
- package/dist/cjs/metric/QGram.cjs +1 -2
- package/dist/cjs/metric/SmithWaterman.cjs +1 -2
- package/dist/cjs/phonetic/Caverphone.cjs +1 -2
- package/dist/cjs/phonetic/Cologne.cjs +1 -2
- package/dist/cjs/phonetic/Metaphone.cjs +1 -2
- package/dist/cjs/phonetic/Phonetic.cjs +55 -35
- package/dist/cjs/phonetic/Soundex.cjs +1 -2
- package/dist/cjs/root.cjs +3 -2
- package/dist/cjs/utils/DeepMerge.cjs +10 -5
- package/dist/cjs/utils/DiffChecker.cjs +1 -2
- package/dist/cjs/utils/Errors.cjs +103 -0
- package/dist/cjs/utils/Filter.cjs +52 -27
- package/dist/cjs/utils/HashTable.cjs +1 -2
- package/dist/cjs/utils/Normalizer.cjs +54 -34
- package/dist/cjs/utils/Pool.cjs +42 -18
- package/dist/cjs/utils/Profiler.cjs +1 -2
- package/dist/cjs/utils/Registry.cjs +46 -22
- package/dist/cjs/utils/StructuredData.cjs +13 -5
- package/dist/cjs/utils/TextAnalyzer.cjs +1 -2
- package/dist/esm/CmpStr.mjs +55 -32
- package/dist/esm/CmpStrAsync.mjs +26 -20
- package/dist/esm/index.mjs +1 -2
- package/dist/esm/metric/Cosine.mjs +1 -2
- package/dist/esm/metric/DamerauLevenshtein.mjs +1 -2
- package/dist/esm/metric/DiceSorensen.mjs +1 -2
- package/dist/esm/metric/Hamming.mjs +5 -4
- package/dist/esm/metric/Jaccard.mjs +1 -2
- package/dist/esm/metric/JaroWinkler.mjs +1 -2
- package/dist/esm/metric/LCS.mjs +1 -2
- package/dist/esm/metric/Levenshtein.mjs +1 -2
- package/dist/esm/metric/Metric.mjs +59 -38
- package/dist/esm/metric/NeedlemanWunsch.mjs +1 -2
- package/dist/esm/metric/QGram.mjs +1 -2
- package/dist/esm/metric/SmithWaterman.mjs +1 -2
- package/dist/esm/phonetic/Caverphone.mjs +1 -2
- package/dist/esm/phonetic/Cologne.mjs +1 -2
- package/dist/esm/phonetic/Metaphone.mjs +1 -2
- package/dist/esm/phonetic/Phonetic.mjs +55 -35
- package/dist/esm/phonetic/Soundex.mjs +1 -2
- package/dist/esm/root.mjs +3 -2
- package/dist/esm/utils/DeepMerge.mjs +10 -5
- package/dist/esm/utils/DiffChecker.mjs +1 -2
- package/dist/esm/utils/Errors.mjs +103 -0
- package/dist/esm/utils/Filter.mjs +52 -27
- package/dist/esm/utils/HashTable.mjs +1 -2
- package/dist/esm/utils/Normalizer.mjs +54 -34
- package/dist/esm/utils/Pool.mjs +38 -18
- package/dist/esm/utils/Profiler.mjs +1 -2
- package/dist/esm/utils/Registry.mjs +46 -22
- package/dist/esm/utils/StructuredData.mjs +13 -5
- package/dist/esm/utils/TextAnalyzer.mjs +1 -2
- package/dist/types/CmpStr.d.ts +5 -1
- package/dist/types/CmpStrAsync.d.ts +1 -0
- package/dist/types/index.d.ts +3 -2
- package/dist/types/metric/Metric.d.ts +6 -5
- package/dist/types/phonetic/Phonetic.d.ts +3 -1
- package/dist/types/root.d.ts +2 -1
- package/dist/types/utils/DeepMerge.d.ts +1 -1
- package/dist/types/utils/Errors.d.ts +137 -0
- package/dist/types/utils/Filter.d.ts +4 -0
- package/dist/types/utils/Normalizer.d.ts +3 -0
- package/dist/types/utils/Pool.d.ts +2 -0
- package/dist/types/utils/Registry.d.ts +3 -3
- package/dist/types/utils/StructuredData.d.ts +3 -1
- package/dist/types/utils/Types.d.ts +26 -0
- package/package.json +7 -7
- package/dist/CmpStr.esm.js.map +0 -1
- package/dist/CmpStr.esm.min.js.map +0 -1
- package/dist/CmpStr.umd.js.map +0 -1
- package/dist/CmpStr.umd.min.js.map +0 -1
- package/dist/cjs/CmpStr.cjs.map +0 -1
- package/dist/cjs/CmpStrAsync.cjs.map +0 -1
- package/dist/cjs/index.cjs.map +0 -1
- package/dist/cjs/metric/Cosine.cjs.map +0 -1
- package/dist/cjs/metric/DamerauLevenshtein.cjs.map +0 -1
- package/dist/cjs/metric/DiceSorensen.cjs.map +0 -1
- package/dist/cjs/metric/Hamming.cjs.map +0 -1
- package/dist/cjs/metric/Jaccard.cjs.map +0 -1
- package/dist/cjs/metric/JaroWinkler.cjs.map +0 -1
- package/dist/cjs/metric/LCS.cjs.map +0 -1
- package/dist/cjs/metric/Levenshtein.cjs.map +0 -1
- package/dist/cjs/metric/Metric.cjs.map +0 -1
- package/dist/cjs/metric/NeedlemanWunsch.cjs.map +0 -1
- package/dist/cjs/metric/QGram.cjs.map +0 -1
- package/dist/cjs/metric/SmithWaterman.cjs.map +0 -1
- package/dist/cjs/phonetic/Caverphone.cjs.map +0 -1
- package/dist/cjs/phonetic/Cologne.cjs.map +0 -1
- package/dist/cjs/phonetic/Metaphone.cjs.map +0 -1
- package/dist/cjs/phonetic/Phonetic.cjs.map +0 -1
- package/dist/cjs/phonetic/Soundex.cjs.map +0 -1
- package/dist/cjs/root.cjs.map +0 -1
- package/dist/cjs/utils/DeepMerge.cjs.map +0 -1
- package/dist/cjs/utils/DiffChecker.cjs.map +0 -1
- package/dist/cjs/utils/Filter.cjs.map +0 -1
- package/dist/cjs/utils/HashTable.cjs.map +0 -1
- package/dist/cjs/utils/Normalizer.cjs.map +0 -1
- package/dist/cjs/utils/Pool.cjs.map +0 -1
- package/dist/cjs/utils/Profiler.cjs.map +0 -1
- package/dist/cjs/utils/Registry.cjs.map +0 -1
- package/dist/cjs/utils/StructuredData.cjs.map +0 -1
- package/dist/cjs/utils/TextAnalyzer.cjs.map +0 -1
- package/dist/esm/CmpStr.mjs.map +0 -1
- package/dist/esm/CmpStrAsync.mjs.map +0 -1
- package/dist/esm/index.mjs.map +0 -1
- package/dist/esm/metric/Cosine.mjs.map +0 -1
- package/dist/esm/metric/DamerauLevenshtein.mjs.map +0 -1
- package/dist/esm/metric/DiceSorensen.mjs.map +0 -1
- package/dist/esm/metric/Hamming.mjs.map +0 -1
- package/dist/esm/metric/Jaccard.mjs.map +0 -1
- package/dist/esm/metric/JaroWinkler.mjs.map +0 -1
- package/dist/esm/metric/LCS.mjs.map +0 -1
- package/dist/esm/metric/Levenshtein.mjs.map +0 -1
- package/dist/esm/metric/Metric.mjs.map +0 -1
- package/dist/esm/metric/NeedlemanWunsch.mjs.map +0 -1
- package/dist/esm/metric/QGram.mjs.map +0 -1
- package/dist/esm/metric/SmithWaterman.mjs.map +0 -1
- package/dist/esm/phonetic/Caverphone.mjs.map +0 -1
- package/dist/esm/phonetic/Cologne.mjs.map +0 -1
- package/dist/esm/phonetic/Metaphone.mjs.map +0 -1
- package/dist/esm/phonetic/Phonetic.mjs.map +0 -1
- package/dist/esm/phonetic/Soundex.mjs.map +0 -1
- package/dist/esm/root.mjs.map +0 -1
- package/dist/esm/utils/DeepMerge.mjs.map +0 -1
- package/dist/esm/utils/DiffChecker.mjs.map +0 -1
- package/dist/esm/utils/Filter.mjs.map +0 -1
- package/dist/esm/utils/HashTable.mjs.map +0 -1
- package/dist/esm/utils/Normalizer.mjs.map +0 -1
- package/dist/esm/utils/Pool.mjs.map +0 -1
- package/dist/esm/utils/Profiler.mjs.map +0 -1
- package/dist/esm/utils/Registry.mjs.map +0 -1
- package/dist/esm/utils/StructuredData.mjs.map +0 -1
- package/dist/esm/utils/TextAnalyzer.mjs.map +0 -1
package/dist/CmpStr.umd.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* CmpStr v3.2.
|
|
2
|
+
* CmpStr v3.2.2 build-bb61120-260311
|
|
3
3
|
* This is a lightweight, fast and well performing library for calculating string similarity.
|
|
4
4
|
* (c) 2023-2026 Paul Köhler @komed3 / MIT License
|
|
5
5
|
* Visit https://github.com/komed3/cmpstr and https://npmjs.org/package/cmpstr
|
|
@@ -15,6 +15,110 @@
|
|
|
15
15
|
})(this, function (exports) {
|
|
16
16
|
'use strict';
|
|
17
17
|
|
|
18
|
+
class CmpStrError extends Error {
|
|
19
|
+
code;
|
|
20
|
+
meta;
|
|
21
|
+
cause;
|
|
22
|
+
when = new Date().toISOString();
|
|
23
|
+
constructor(code, message, meta, cause) {
|
|
24
|
+
super(message);
|
|
25
|
+
this.name = this.constructor.name;
|
|
26
|
+
this.code = code;
|
|
27
|
+
this.meta = meta;
|
|
28
|
+
this.cause = cause;
|
|
29
|
+
if (typeof Error.captureStackTrace === 'function') {
|
|
30
|
+
Error.captureStackTrace(this, this.constructor);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
toJSON() {
|
|
34
|
+
return {
|
|
35
|
+
name: this.name,
|
|
36
|
+
code: this.code,
|
|
37
|
+
message: this.message,
|
|
38
|
+
meta: this.meta,
|
|
39
|
+
when: this.when,
|
|
40
|
+
cause:
|
|
41
|
+
this.cause instanceof Error
|
|
42
|
+
? {
|
|
43
|
+
name: this.cause.name,
|
|
44
|
+
message: this.cause.message,
|
|
45
|
+
stack: this.cause.stack
|
|
46
|
+
}
|
|
47
|
+
: this.cause
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
toString(stack = false) {
|
|
51
|
+
const parts = [`${this.name} [${this.code}]`, this.message];
|
|
52
|
+
if (this.meta && Object.keys(this.meta).length) {
|
|
53
|
+
try {
|
|
54
|
+
parts.push(JSON.stringify(this.meta));
|
|
55
|
+
} catch {}
|
|
56
|
+
}
|
|
57
|
+
return (
|
|
58
|
+
parts.join(' - ') +
|
|
59
|
+
(stack && this.stack ? `\nStack Trace:\n${this.stack}` : '')
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
class CmpStrValidationError extends CmpStrError {
|
|
64
|
+
constructor(message, meta, cause) {
|
|
65
|
+
super('E_VALIDATION', message, meta, cause);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
class CmpStrNotFoundError extends CmpStrError {
|
|
69
|
+
constructor(message, meta, cause) {
|
|
70
|
+
super('E_NOT_FOUND', message, meta, cause);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
class CmpStrUsageError extends CmpStrError {
|
|
74
|
+
constructor(message, meta, cause) {
|
|
75
|
+
super('E_USAGE', message, meta, cause);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
class CmpStrInternalError extends CmpStrError {
|
|
79
|
+
constructor(message, meta, cause) {
|
|
80
|
+
super('E_INTERNAL', message, meta, cause);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
class ErrorUtil {
|
|
84
|
+
static assert(condition, message, meta) {
|
|
85
|
+
if (!condition) throw new CmpStrUsageError(message, meta);
|
|
86
|
+
}
|
|
87
|
+
static create(err, message, meta) {
|
|
88
|
+
if (err instanceof CmpStrError) throw err;
|
|
89
|
+
throw new CmpStrInternalError(message, meta, err);
|
|
90
|
+
}
|
|
91
|
+
static format(err) {
|
|
92
|
+
if (err instanceof CmpStrError) return err.toString();
|
|
93
|
+
if (err instanceof Error) return `${err.name}: ${err.message}`;
|
|
94
|
+
return String(err);
|
|
95
|
+
}
|
|
96
|
+
static wrap(fn, message, meta) {
|
|
97
|
+
try {
|
|
98
|
+
return fn();
|
|
99
|
+
} catch (err) {
|
|
100
|
+
throw new CmpStrInternalError(message, meta, err);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
static async wrapAsync(fn, message, meta) {
|
|
104
|
+
try {
|
|
105
|
+
return await fn();
|
|
106
|
+
} catch (err) {
|
|
107
|
+
throw new CmpStrInternalError(message, meta, err);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
var Errors = /*#__PURE__*/ Object.freeze({
|
|
113
|
+
__proto__: null,
|
|
114
|
+
CmpStrError: CmpStrError,
|
|
115
|
+
CmpStrInternalError: CmpStrInternalError,
|
|
116
|
+
CmpStrNotFoundError: CmpStrNotFoundError,
|
|
117
|
+
CmpStrUsageError: CmpStrUsageError,
|
|
118
|
+
CmpStrValidationError: CmpStrValidationError,
|
|
119
|
+
ErrorUtil: ErrorUtil
|
|
120
|
+
});
|
|
121
|
+
|
|
18
122
|
const BRACKET_PATTERN = /\[(\d+)]/g;
|
|
19
123
|
const PATH_CACHE = new Map();
|
|
20
124
|
function parse(p) {
|
|
@@ -50,15 +154,19 @@
|
|
|
50
154
|
if (path === '') return value;
|
|
51
155
|
const keys = parse(path);
|
|
52
156
|
if (t !== undefined && (typeof t !== 'object' || t === null))
|
|
53
|
-
throw
|
|
157
|
+
throw new CmpStrUsageError(
|
|
158
|
+
`Cannot set property <${keys[0]}> of <${JSON.stringify(t)}>`,
|
|
159
|
+
{ path: keys[0], target: t }
|
|
160
|
+
);
|
|
54
161
|
const root = t ?? (typeof keys[0] === 'number' ? [] : Object.create(null));
|
|
55
162
|
let cur = root;
|
|
56
163
|
for (let i = 0; i < keys.length - 1; i++) {
|
|
57
164
|
const k = keys[i];
|
|
58
165
|
let n = cur[k];
|
|
59
166
|
if (n != null && typeof n !== 'object')
|
|
60
|
-
throw
|
|
61
|
-
`Cannot set property <${keys[i + 1]}> of <${JSON.stringify(n)}
|
|
167
|
+
throw new CmpStrUsageError(
|
|
168
|
+
`Cannot set property <${keys[i + 1]}> of <${JSON.stringify(n)}>`,
|
|
169
|
+
{ path: keys.slice(0, i + 2), value: n }
|
|
62
170
|
);
|
|
63
171
|
if (n == null)
|
|
64
172
|
n = cur[k] = typeof keys[i + 1] === 'number' ? [] : Object.create(null);
|
|
@@ -425,30 +533,42 @@
|
|
|
425
533
|
static filters = new Map();
|
|
426
534
|
static pipeline = new Map();
|
|
427
535
|
static getPipeline(hook) {
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
536
|
+
return ErrorUtil.wrap(
|
|
537
|
+
() => {
|
|
538
|
+
const cached = Filter.pipeline.get(hook);
|
|
539
|
+
if (cached) return cached;
|
|
540
|
+
const filter = Filter.filters.get(hook);
|
|
541
|
+
if (!filter) return (s) => s;
|
|
542
|
+
const pipeline = Array.from(filter.values())
|
|
543
|
+
.filter((f) => f.active)
|
|
544
|
+
.sort((a, b) => a.priority - b.priority)
|
|
545
|
+
.map((f) => f.fn);
|
|
546
|
+
const fn = (input) => pipeline.reduce((v, f) => f(v), input);
|
|
547
|
+
Filter.pipeline.set(hook, fn);
|
|
548
|
+
return fn;
|
|
549
|
+
},
|
|
550
|
+
`Error compiling filter pipeline for hook <${hook}>`,
|
|
551
|
+
{ hook }
|
|
552
|
+
);
|
|
439
553
|
}
|
|
440
554
|
static has(hook, id) {
|
|
441
555
|
return !!Filter.filters.get(hook)?.has(id);
|
|
442
556
|
}
|
|
443
557
|
static add(hook, id, fn, opt = {}) {
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
558
|
+
return ErrorUtil.wrap(
|
|
559
|
+
() => {
|
|
560
|
+
const { priority = 10, active = true, overrideable = true } = opt;
|
|
561
|
+
const filter = Filter.filters.get(hook) ?? new Map();
|
|
562
|
+
const index = filter.get(id);
|
|
563
|
+
if (index && !index.overrideable) return false;
|
|
564
|
+
filter.set(id, { id, fn, priority, active, overrideable });
|
|
565
|
+
Filter.filters.set(hook, filter);
|
|
566
|
+
Filter.pipeline.delete(hook);
|
|
567
|
+
return true;
|
|
568
|
+
},
|
|
569
|
+
`Error adding filter <${id}> to hook <${hook}>`,
|
|
570
|
+
{ hook, id, opt }
|
|
571
|
+
);
|
|
452
572
|
}
|
|
453
573
|
static remove(hook, id) {
|
|
454
574
|
Filter.pipeline.delete(hook);
|
|
@@ -473,14 +593,26 @@
|
|
|
473
593
|
return out;
|
|
474
594
|
}
|
|
475
595
|
static apply(hook, input) {
|
|
476
|
-
|
|
477
|
-
|
|
596
|
+
return ErrorUtil.wrap(
|
|
597
|
+
() => {
|
|
598
|
+
const fn = Filter.getPipeline(hook);
|
|
599
|
+
return Array.isArray(input) ? input.map(fn) : fn(input);
|
|
600
|
+
},
|
|
601
|
+
`Error applying filters for hook <${hook}>`,
|
|
602
|
+
{ hook, input }
|
|
603
|
+
);
|
|
478
604
|
}
|
|
479
605
|
static async applyAsync(hook, input) {
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
606
|
+
return ErrorUtil.wrapAsync(
|
|
607
|
+
async () => {
|
|
608
|
+
const fn = Filter.getPipeline(hook);
|
|
609
|
+
return Array.isArray(input)
|
|
610
|
+
? Promise.all(input.map(fn))
|
|
611
|
+
: Promise.resolve(fn(input));
|
|
612
|
+
},
|
|
613
|
+
`Error applying filters for hook <${hook}>`,
|
|
614
|
+
{ hook, input }
|
|
615
|
+
);
|
|
484
616
|
}
|
|
485
617
|
static clear(hook) {
|
|
486
618
|
Filter.pipeline.clear();
|
|
@@ -568,42 +700,63 @@
|
|
|
568
700
|
return Array.from(new Set(flags)).sort().join('');
|
|
569
701
|
}
|
|
570
702
|
static getPipeline(flags) {
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
703
|
+
return ErrorUtil.wrap(
|
|
704
|
+
() => {
|
|
705
|
+
if (Normalizer.pipeline.has(flags))
|
|
706
|
+
return Normalizer.pipeline.get(flags);
|
|
707
|
+
const { REGEX } = Normalizer;
|
|
708
|
+
const steps = [
|
|
709
|
+
['d', (s) => s.normalize('NFD')],
|
|
710
|
+
['i', (s) => s.toLowerCase()],
|
|
711
|
+
['k', (s) => s.replace(REGEX.nonLetters, '')],
|
|
712
|
+
['n', (s) => s.replace(REGEX.nonNumbers, '')],
|
|
713
|
+
['r', (s) => s.replace(REGEX.doubleChars, '$1')],
|
|
714
|
+
['s', (s) => s.replace(REGEX.specialChars, '')],
|
|
715
|
+
['t', (s) => s.trim()],
|
|
716
|
+
['u', (s) => s.normalize('NFC')],
|
|
717
|
+
['w', (s) => s.replace(REGEX.whitespace, ' ')],
|
|
718
|
+
['x', (s) => s.normalize('NFKC')]
|
|
719
|
+
];
|
|
720
|
+
const pipeline = steps
|
|
721
|
+
.filter(([f]) => flags.includes(f))
|
|
722
|
+
.map(([, fn]) => fn);
|
|
723
|
+
const fn = (s) => pipeline.reduce((v, f) => f(v), s);
|
|
724
|
+
Normalizer.pipeline.set(flags, fn);
|
|
725
|
+
return fn;
|
|
726
|
+
},
|
|
727
|
+
`Failed to create normalization pipeline for flags: ${flags}`,
|
|
728
|
+
{ flags }
|
|
729
|
+
);
|
|
591
730
|
}
|
|
592
731
|
static normalize(input, flags) {
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
732
|
+
return ErrorUtil.wrap(
|
|
733
|
+
() => {
|
|
734
|
+
if (!flags || typeof flags !== 'string' || !input) return input;
|
|
735
|
+
flags = this.canonicalFlags(flags);
|
|
736
|
+
if (Array.isArray(input))
|
|
737
|
+
return input.map((s) => Normalizer.normalize(s, flags));
|
|
738
|
+
const key = Normalizer.cache.key(flags, [input]);
|
|
739
|
+
if (key && Normalizer.cache.has(key))
|
|
740
|
+
return Normalizer.cache.get(key);
|
|
741
|
+
const res = Normalizer.getPipeline(flags)(input);
|
|
742
|
+
if (key) Normalizer.cache.set(key, res);
|
|
743
|
+
return res;
|
|
744
|
+
},
|
|
745
|
+
`Failed to normalize input with flags: ${flags}`,
|
|
746
|
+
{ input, flags }
|
|
747
|
+
);
|
|
602
748
|
}
|
|
603
749
|
static async normalizeAsync(input, flags) {
|
|
604
|
-
return await
|
|
605
|
-
|
|
606
|
-
|
|
750
|
+
return await ErrorUtil.wrapAsync(
|
|
751
|
+
async () => {
|
|
752
|
+
if (!flags || typeof flags !== 'string' || !input) return input;
|
|
753
|
+
return await (Array.isArray(input)
|
|
754
|
+
? Promise.all(input.map((s) => Normalizer.normalize(s, flags)))
|
|
755
|
+
: Promise.resolve(Normalizer.normalize(input, flags)));
|
|
756
|
+
},
|
|
757
|
+
`Failed to asynchronously normalize input with flags: ${flags}`,
|
|
758
|
+
{ input, flags }
|
|
759
|
+
);
|
|
607
760
|
}
|
|
608
761
|
static clear() {
|
|
609
762
|
Normalizer.pipeline.clear();
|
|
@@ -693,19 +846,34 @@
|
|
|
693
846
|
const registry = Object.create(null);
|
|
694
847
|
const factory = Object.create(null);
|
|
695
848
|
function Registry(reg, ctor) {
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
849
|
+
ErrorUtil.assert(
|
|
850
|
+
!(reg in registry || reg in factory),
|
|
851
|
+
`Registry <${reg}> already exists / overwriting is forbidden`,
|
|
852
|
+
{ registry: reg }
|
|
853
|
+
);
|
|
700
854
|
const classes = Object.create(null);
|
|
701
855
|
const service = Object.freeze({
|
|
702
856
|
add(name, cls, update = false) {
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
857
|
+
ErrorUtil.assert(
|
|
858
|
+
typeof name === 'string' && name.length > 0,
|
|
859
|
+
`Class name must be a non-empty string`,
|
|
860
|
+
{ registry: reg, name }
|
|
861
|
+
);
|
|
862
|
+
ErrorUtil.assert(
|
|
863
|
+
typeof cls === 'function',
|
|
864
|
+
`Class must be a constructor function`,
|
|
865
|
+
{ registry: reg, class: cls }
|
|
866
|
+
);
|
|
867
|
+
ErrorUtil.assert(
|
|
868
|
+
cls.prototype instanceof ctor,
|
|
869
|
+
`Class must extend <${reg}>`,
|
|
870
|
+
{ registry: reg, class: cls }
|
|
871
|
+
);
|
|
872
|
+
ErrorUtil.assert(
|
|
873
|
+
update || !(name in classes),
|
|
874
|
+
`Class <${name}> already exists / use <update=true> to overwrite`,
|
|
875
|
+
{ registry: reg, name }
|
|
876
|
+
);
|
|
709
877
|
classes[name] = cls;
|
|
710
878
|
},
|
|
711
879
|
remove(name) {
|
|
@@ -718,8 +886,16 @@
|
|
|
718
886
|
return Object.keys(classes);
|
|
719
887
|
},
|
|
720
888
|
get(name) {
|
|
721
|
-
|
|
722
|
-
|
|
889
|
+
ErrorUtil.assert(
|
|
890
|
+
typeof name === 'string' && name.length > 0,
|
|
891
|
+
`Class name must be a non-empty string`,
|
|
892
|
+
{ registry: reg, name }
|
|
893
|
+
);
|
|
894
|
+
ErrorUtil.assert(
|
|
895
|
+
name in classes,
|
|
896
|
+
`Class <${name}> not registered for <${reg}>`,
|
|
897
|
+
{ registry: reg, name }
|
|
898
|
+
);
|
|
723
899
|
return classes[name];
|
|
724
900
|
}
|
|
725
901
|
});
|
|
@@ -729,18 +905,18 @@
|
|
|
729
905
|
}
|
|
730
906
|
function resolveCls(reg, cls) {
|
|
731
907
|
if (!(reg in registry))
|
|
732
|
-
throw new
|
|
908
|
+
throw new CmpStrNotFoundError(`Registry <${reg}> does not exist`, {
|
|
909
|
+
registry: reg
|
|
910
|
+
});
|
|
733
911
|
return typeof cls === 'string' ? registry[reg]?.get(cls) : cls;
|
|
734
912
|
}
|
|
735
913
|
function createFromRegistry(reg, cls, ...args) {
|
|
736
914
|
cls = resolveCls(reg, cls);
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
});
|
|
743
|
-
}
|
|
915
|
+
return ErrorUtil.wrap(
|
|
916
|
+
() => new cls(...args),
|
|
917
|
+
`Failed to create instance of class <${cls.name ?? cls}> from registry <${reg}>`,
|
|
918
|
+
{ registry: reg, class: cls, args }
|
|
919
|
+
);
|
|
744
920
|
}
|
|
745
921
|
|
|
746
922
|
class RingPool {
|
|
@@ -751,22 +927,37 @@
|
|
|
751
927
|
this.maxSize = maxSize;
|
|
752
928
|
}
|
|
753
929
|
acquire(minSize, allowOversize) {
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
930
|
+
return ErrorUtil.wrap(
|
|
931
|
+
() => {
|
|
932
|
+
const len = this.buffers.length;
|
|
933
|
+
for (let i = 0; i < len; i++) {
|
|
934
|
+
const idx = (this.pointer + i) & (len - 1);
|
|
935
|
+
const item = this.buffers[idx];
|
|
936
|
+
if (
|
|
937
|
+
item.size >= minSize &&
|
|
938
|
+
(allowOversize || item.size === minSize)
|
|
939
|
+
) {
|
|
940
|
+
this.pointer = (idx + 1) & (len - 1);
|
|
941
|
+
return item;
|
|
942
|
+
}
|
|
943
|
+
}
|
|
944
|
+
return null;
|
|
945
|
+
},
|
|
946
|
+
`Failed to acquire buffer of size >= ${minSize} from pool`,
|
|
947
|
+
{ minSize, allowOversize }
|
|
948
|
+
);
|
|
764
949
|
}
|
|
765
950
|
release(item) {
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
951
|
+
ErrorUtil.wrap(
|
|
952
|
+
() => {
|
|
953
|
+
if (this.buffers.length < this.maxSize)
|
|
954
|
+
return void [this.buffers.push(item)];
|
|
955
|
+
this.buffers[this.pointer] = item;
|
|
956
|
+
this.pointer = (this.pointer + 1) % this.maxSize;
|
|
957
|
+
},
|
|
958
|
+
`Failed to release buffer back to pool`,
|
|
959
|
+
{ item }
|
|
960
|
+
);
|
|
770
961
|
}
|
|
771
962
|
clear() {
|
|
772
963
|
this.buffers = [];
|
|
@@ -819,6 +1010,8 @@
|
|
|
819
1010
|
}
|
|
820
1011
|
static acquire(type, size) {
|
|
821
1012
|
const CONFIG = this.CONFIG[type];
|
|
1013
|
+
if (!CONFIG)
|
|
1014
|
+
throw new CmpStrUsageError(`Unsupported pool type <${type}>`, { type });
|
|
822
1015
|
if (size > CONFIG.maxItemSize) return this.allocate(type, size);
|
|
823
1016
|
const item = this.POOLS[type].acquire(size, CONFIG.allowOversize);
|
|
824
1017
|
if (item)
|
|
@@ -829,7 +1022,10 @@
|
|
|
829
1022
|
return sizes.map((size) => this.acquire(type, size));
|
|
830
1023
|
}
|
|
831
1024
|
static release(type, buffer, size) {
|
|
832
|
-
|
|
1025
|
+
const CONFIG = this.CONFIG[type];
|
|
1026
|
+
if (!CONFIG)
|
|
1027
|
+
throw new CmpStrUsageError(`Unsupported pool type <${type}>`, { type });
|
|
1028
|
+
if (size <= CONFIG.maxItemSize)
|
|
833
1029
|
this.POOLS[type].release({ buffer, size });
|
|
834
1030
|
}
|
|
835
1031
|
}
|
|
@@ -885,7 +1081,7 @@
|
|
|
885
1081
|
raw: r.raw
|
|
886
1082
|
}));
|
|
887
1083
|
else
|
|
888
|
-
throw new
|
|
1084
|
+
throw new CmpStrValidationError(
|
|
889
1085
|
'Unsupported result format for StructuredData normalization.'
|
|
890
1086
|
);
|
|
891
1087
|
return normalized.map((r, idx) => ({ ...r, __idx: idx }));
|
|
@@ -947,10 +1143,18 @@
|
|
|
947
1143
|
);
|
|
948
1144
|
}
|
|
949
1145
|
performLookup(fn, extractedStrings, opt) {
|
|
950
|
-
return
|
|
1146
|
+
return ErrorUtil.wrap(
|
|
1147
|
+
() => this.finalizeLookup(fn(), extractedStrings, opt),
|
|
1148
|
+
'StructuredData lookup failed',
|
|
1149
|
+
{ key: this.key }
|
|
1150
|
+
);
|
|
951
1151
|
}
|
|
952
1152
|
async performLookupAsync(fn, extractedStrings, opt) {
|
|
953
|
-
return
|
|
1153
|
+
return await ErrorUtil.wrapAsync(
|
|
1154
|
+
async () => this.finalizeLookup(await fn(), extractedStrings, opt),
|
|
1155
|
+
'StructuredData async lookup failed',
|
|
1156
|
+
{ key: this.key }
|
|
1157
|
+
);
|
|
954
1158
|
}
|
|
955
1159
|
lookup(fn, query, opt) {
|
|
956
1160
|
const b = this.extract();
|
|
@@ -1204,8 +1408,11 @@
|
|
|
1204
1408
|
this.metric = metric;
|
|
1205
1409
|
this.a = Array.isArray(a) ? a : [a];
|
|
1206
1410
|
this.b = Array.isArray(b) ? b : [b];
|
|
1207
|
-
|
|
1208
|
-
|
|
1411
|
+
ErrorUtil.assert(
|
|
1412
|
+
this.a.length > 0 && this.b.length > 0,
|
|
1413
|
+
`Inputs <a> and <b> must not be empty`,
|
|
1414
|
+
{ a: this.a, b: this.b }
|
|
1415
|
+
);
|
|
1209
1416
|
this.options = opt;
|
|
1210
1417
|
this.optKey = Hasher.fastFNV1a(
|
|
1211
1418
|
JSON.stringify(opt, Object.keys(opt).sort())
|
|
@@ -1218,37 +1425,46 @@
|
|
|
1218
1425
|
return undefined;
|
|
1219
1426
|
}
|
|
1220
1427
|
compute(a, b, m, n, maxLen) {
|
|
1221
|
-
throw new
|
|
1428
|
+
throw new CmpStrInternalError(
|
|
1429
|
+
`Method compute() must be overridden in a subclass`
|
|
1430
|
+
);
|
|
1222
1431
|
}
|
|
1223
1432
|
runSingle(i, j) {
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
if (
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1433
|
+
return ErrorUtil.wrap(
|
|
1434
|
+
() => {
|
|
1435
|
+
let a = String(this.a[i]),
|
|
1436
|
+
A = a;
|
|
1437
|
+
let b = String(this.b[j]),
|
|
1438
|
+
B = b;
|
|
1439
|
+
let m = A.length,
|
|
1440
|
+
n = B.length;
|
|
1441
|
+
let result = this.preCompute(A, B, m, n);
|
|
1442
|
+
if (!result) {
|
|
1443
|
+
result = profiler$2.run(() => {
|
|
1444
|
+
if (this.symmetric) [A, B, m, n] = Metric.swap(A, B, m, n);
|
|
1445
|
+
const key =
|
|
1446
|
+
Metric.cache.key(this.metric, [A, B], this.symmetric) +
|
|
1447
|
+
this.optKey;
|
|
1448
|
+
return (
|
|
1449
|
+
Metric.cache.get(key || '') ??
|
|
1450
|
+
(() => {
|
|
1451
|
+
const res = this.compute(A, B, m, n, Math.max(m, n));
|
|
1452
|
+
if (key) Metric.cache.set(key, res);
|
|
1453
|
+
return res;
|
|
1454
|
+
})()
|
|
1455
|
+
);
|
|
1456
|
+
});
|
|
1457
|
+
}
|
|
1458
|
+
return {
|
|
1459
|
+
metric: this.metric,
|
|
1460
|
+
a: this.origA[i] ?? a,
|
|
1461
|
+
b: this.origB[j] ?? b,
|
|
1462
|
+
...result
|
|
1463
|
+
};
|
|
1464
|
+
},
|
|
1465
|
+
`Failed to compute metric for inputs at indices a[${i}] and b[${j}]`,
|
|
1466
|
+
{ i, j }
|
|
1467
|
+
);
|
|
1252
1468
|
}
|
|
1253
1469
|
async runSingleAsync(i, j) {
|
|
1254
1470
|
return Promise.resolve(this.runSingle(i, j));
|
|
@@ -1291,8 +1507,9 @@
|
|
|
1291
1507
|
? true
|
|
1292
1508
|
: !safe &&
|
|
1293
1509
|
(() => {
|
|
1294
|
-
throw new
|
|
1295
|
-
`Mode <pairwise> requires arrays of equal length
|
|
1510
|
+
throw new CmpStrUsageError(
|
|
1511
|
+
`Mode <pairwise> requires arrays of equal length`,
|
|
1512
|
+
{ a: this.a, b: this.b }
|
|
1296
1513
|
);
|
|
1297
1514
|
})();
|
|
1298
1515
|
}
|
|
@@ -1317,7 +1534,7 @@
|
|
|
1317
1534
|
if (this.isPairwise()) this.runPairwise();
|
|
1318
1535
|
break;
|
|
1319
1536
|
default:
|
|
1320
|
-
throw new
|
|
1537
|
+
throw new CmpStrInternalError(`Unsupported mode <${mode}>`);
|
|
1321
1538
|
}
|
|
1322
1539
|
}
|
|
1323
1540
|
async runAsync(mode, clear = true) {
|
|
@@ -1338,13 +1555,15 @@
|
|
|
1338
1555
|
if (this.isPairwise()) await this.runPairwiseAsync();
|
|
1339
1556
|
break;
|
|
1340
1557
|
default:
|
|
1341
|
-
throw new
|
|
1558
|
+
throw new CmpStrInternalError(`Unsupported async mode <${mode}>`);
|
|
1342
1559
|
}
|
|
1343
1560
|
}
|
|
1344
1561
|
getMetricName = () => this.metric;
|
|
1345
1562
|
getResults() {
|
|
1346
|
-
|
|
1347
|
-
|
|
1563
|
+
ErrorUtil.assert(
|
|
1564
|
+
this.results !== undefined,
|
|
1565
|
+
`run() must be called before getResults()`
|
|
1566
|
+
);
|
|
1348
1567
|
return this.results;
|
|
1349
1568
|
}
|
|
1350
1569
|
}
|
|
@@ -1476,9 +1695,10 @@
|
|
|
1476
1695
|
if (n < maxLen) b = b.padEnd(maxLen, this.options.pad);
|
|
1477
1696
|
m = n = maxLen;
|
|
1478
1697
|
} else
|
|
1479
|
-
throw new
|
|
1698
|
+
throw new CmpStrUsageError(
|
|
1480
1699
|
`Strings must be of equal length for Hamming Distance, a=${m} and b=${n} given, ` +
|
|
1481
|
-
`use option.pad for automatic adjustment
|
|
1700
|
+
`use option.pad for automatic adjustment`,
|
|
1701
|
+
{ a: m, b: n }
|
|
1482
1702
|
);
|
|
1483
1703
|
}
|
|
1484
1704
|
let dist = 0;
|
|
@@ -1757,10 +1977,16 @@
|
|
|
1757
1977
|
const defaults = this.constructor.default ?? {};
|
|
1758
1978
|
const mapId = opt.map ?? defaults.map;
|
|
1759
1979
|
if (!mapId)
|
|
1760
|
-
throw new
|
|
1980
|
+
throw new CmpStrNotFoundError(
|
|
1981
|
+
`No mapping specified for phonetic algorithm`,
|
|
1982
|
+
{ algo }
|
|
1983
|
+
);
|
|
1761
1984
|
const map = PhoneticMappingRegistry.get(algo, mapId);
|
|
1762
1985
|
if (map === undefined)
|
|
1763
|
-
throw new
|
|
1986
|
+
throw new CmpStrNotFoundError(
|
|
1987
|
+
`Requested mapping <${mapId}> is not declared`,
|
|
1988
|
+
{ algo, mapId }
|
|
1989
|
+
);
|
|
1764
1990
|
this.options = merge(merge(defaults, map.options ?? {}), opt);
|
|
1765
1991
|
this.optKey = Hasher.fastFNV1a(
|
|
1766
1992
|
JSON.stringify(this.options, Object.keys(this.options).sort())
|
|
@@ -1851,35 +2077,47 @@
|
|
|
1851
2077
|
return code;
|
|
1852
2078
|
}
|
|
1853
2079
|
loop(words) {
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
2080
|
+
return ErrorUtil.wrap(
|
|
2081
|
+
() => {
|
|
2082
|
+
const index = [];
|
|
2083
|
+
for (const word of words) {
|
|
2084
|
+
const key = Phonetic.cache.key(this.algo, [word]) + this.optKey;
|
|
2085
|
+
const code =
|
|
2086
|
+
Phonetic.cache.get(key || '') ??
|
|
2087
|
+
(() => {
|
|
2088
|
+
const res = this.encode(word);
|
|
2089
|
+
if (key) Phonetic.cache.set(key, res);
|
|
2090
|
+
return res;
|
|
2091
|
+
})();
|
|
2092
|
+
if (code && code.length) index.push(this.equalLen(code));
|
|
2093
|
+
}
|
|
2094
|
+
return index;
|
|
2095
|
+
},
|
|
2096
|
+
`Failed to generate phonetic index`,
|
|
2097
|
+
{ algo: this.algo, words }
|
|
2098
|
+
);
|
|
1867
2099
|
}
|
|
1868
2100
|
async loopAsync(words) {
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
2101
|
+
return ErrorUtil.wrapAsync(
|
|
2102
|
+
async () => {
|
|
2103
|
+
const index = [];
|
|
2104
|
+
for (const word of words) {
|
|
2105
|
+
const key = Phonetic.cache.key(this.algo, [word]) + this.optKey;
|
|
2106
|
+
const code = await Promise.resolve(
|
|
2107
|
+
Phonetic.cache.get(key || '') ??
|
|
2108
|
+
(() => {
|
|
2109
|
+
const res = this.encode(word);
|
|
2110
|
+
if (key) Phonetic.cache.set(key, res);
|
|
2111
|
+
return res;
|
|
2112
|
+
})()
|
|
2113
|
+
);
|
|
2114
|
+
if (code && code.length) index.push(this.equalLen(code));
|
|
2115
|
+
}
|
|
2116
|
+
return index;
|
|
2117
|
+
},
|
|
2118
|
+
`Failed to generate phonetic index asynchronously`,
|
|
2119
|
+
{ algo: this.algo, words }
|
|
2120
|
+
);
|
|
1883
2121
|
}
|
|
1884
2122
|
getAlgoName = () => this.algo;
|
|
1885
2123
|
getIndex(input) {
|
|
@@ -1905,10 +2143,11 @@
|
|
|
1905
2143
|
return Object.freeze({
|
|
1906
2144
|
add(algo, id, map, update = false) {
|
|
1907
2145
|
const mappings = maps(algo);
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
2146
|
+
ErrorUtil.assert(
|
|
2147
|
+
!(!id || id in mappings) || update,
|
|
2148
|
+
`Entry <${id}> already exists / use <update=true> to overwrite`,
|
|
2149
|
+
{ algo, id }
|
|
2150
|
+
);
|
|
1912
2151
|
mappings[id] = map;
|
|
1913
2152
|
},
|
|
1914
2153
|
remove(algo, id) {
|
|
@@ -2335,20 +2574,22 @@
|
|
|
2335
2574
|
switch (cond) {
|
|
2336
2575
|
case 'metric':
|
|
2337
2576
|
if (!CmpStr.metric.has(test))
|
|
2338
|
-
throw new
|
|
2577
|
+
throw new CmpStrNotFoundError(
|
|
2339
2578
|
`CmpStr <metric> must be set, call .setMetric(), ` +
|
|
2340
|
-
`use CmpStr.metric.list() for available metrics
|
|
2579
|
+
`use CmpStr.metric.list() for available metrics`,
|
|
2580
|
+
{ metric: test }
|
|
2341
2581
|
);
|
|
2342
2582
|
break;
|
|
2343
2583
|
case 'phonetic':
|
|
2344
2584
|
if (!CmpStr.phonetic.has(test))
|
|
2345
|
-
throw new
|
|
2585
|
+
throw new CmpStrNotFoundError(
|
|
2346
2586
|
`CmpStr <phonetic> must be set, call .setPhonetic(), ` +
|
|
2347
|
-
`use CmpStr.phonetic.list() for available phonetic algorithms
|
|
2587
|
+
`use CmpStr.phonetic.list() for available phonetic algorithms`,
|
|
2588
|
+
{ phonetic: test }
|
|
2348
2589
|
);
|
|
2349
2590
|
break;
|
|
2350
2591
|
default:
|
|
2351
|
-
throw new
|
|
2592
|
+
throw new CmpStrInternalError(`Cmpstr condition <${cond}> unknown`);
|
|
2352
2593
|
}
|
|
2353
2594
|
}
|
|
2354
2595
|
assertMany(...cond) {
|
|
@@ -2387,31 +2628,42 @@
|
|
|
2387
2628
|
return StructuredData.create(data, key);
|
|
2388
2629
|
}
|
|
2389
2630
|
compute(a, b, opt, mode, raw, skip) {
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2631
|
+
return ErrorUtil.wrap(
|
|
2632
|
+
() => {
|
|
2633
|
+
const resolved = this.resolveOptions(opt);
|
|
2634
|
+
this.assert('metric', resolved.metric);
|
|
2635
|
+
const A = skip ? a : this.prepare(a, resolved);
|
|
2636
|
+
const B = skip ? b : this.prepare(b, resolved);
|
|
2637
|
+
if (
|
|
2638
|
+
resolved.safeEmpty &&
|
|
2639
|
+
((Array.isArray(A) && A.length === 0) ||
|
|
2640
|
+
(Array.isArray(B) && B.length === 0) ||
|
|
2641
|
+
A === '' ||
|
|
2642
|
+
B === '')
|
|
2643
|
+
) {
|
|
2644
|
+
return [];
|
|
2645
|
+
}
|
|
2646
|
+
const metric = factory['metric'](resolved.metric, A, B, resolved.opt);
|
|
2647
|
+
if (resolved.output !== 'prep') metric.setOriginal(a, b);
|
|
2648
|
+
metric.run(mode);
|
|
2649
|
+
const result = this.postProcess(metric.getResults(), resolved);
|
|
2650
|
+
return this.output(result, raw ?? resolved.raw);
|
|
2651
|
+
},
|
|
2652
|
+
`Failed to compute metric <${opt?.metric ?? this.options.metric}> for the given inputs`,
|
|
2653
|
+
{ a, b, options: opt }
|
|
2654
|
+
);
|
|
2408
2655
|
}
|
|
2409
2656
|
output(result, raw) {
|
|
2410
|
-
return (
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
|
|
2657
|
+
return ErrorUtil.wrap(
|
|
2658
|
+
() =>
|
|
2659
|
+
(raw ?? this.options.raw)
|
|
2660
|
+
? result
|
|
2661
|
+
: Array.isArray(result)
|
|
2662
|
+
? result.map((r) => ({ source: r.a, target: r.b, match: r.res }))
|
|
2663
|
+
: { source: result.a, target: result.b, match: result.res },
|
|
2664
|
+
`Failed to resolve output format for the metric result`,
|
|
2665
|
+
{ result, raw }
|
|
2666
|
+
);
|
|
2415
2667
|
}
|
|
2416
2668
|
clone = () =>
|
|
2417
2669
|
Object.assign(Object.create(Object.getPrototypeOf(this)), this);
|
|
@@ -2428,8 +2680,14 @@
|
|
|
2428
2680
|
return this;
|
|
2429
2681
|
}
|
|
2430
2682
|
setSerializedOptions(opt) {
|
|
2431
|
-
|
|
2432
|
-
|
|
2683
|
+
return ErrorUtil.wrap(
|
|
2684
|
+
() => {
|
|
2685
|
+
this.options = JSON.parse(opt);
|
|
2686
|
+
return this;
|
|
2687
|
+
},
|
|
2688
|
+
`Failed to parse serialized options, invalid JSON string`,
|
|
2689
|
+
{ opt }
|
|
2690
|
+
);
|
|
2433
2691
|
}
|
|
2434
2692
|
setOption(path, value) {
|
|
2435
2693
|
set(this.options, path, value);
|
|
@@ -2575,24 +2833,30 @@
|
|
|
2575
2833
|
: phonetic.getIndexAsync(input).then((r) => r.join(delimiter));
|
|
2576
2834
|
}
|
|
2577
2835
|
async computeAsync(a, b, opt, mode, raw, skip) {
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2836
|
+
return ErrorUtil.wrapAsync(
|
|
2837
|
+
async () => {
|
|
2838
|
+
const resolved = this.resolveOptions(opt);
|
|
2839
|
+
this.assert('metric', resolved.metric);
|
|
2840
|
+
const A = skip ? a : await this.prepareAsync(a, resolved);
|
|
2841
|
+
const B = skip ? b : await this.prepareAsync(b, resolved);
|
|
2842
|
+
if (
|
|
2843
|
+
resolved.safeEmpty &&
|
|
2844
|
+
((Array.isArray(A) && A.length === 0) ||
|
|
2845
|
+
(Array.isArray(B) && B.length === 0) ||
|
|
2846
|
+
A === '' ||
|
|
2847
|
+
B === '')
|
|
2848
|
+
) {
|
|
2849
|
+
return [];
|
|
2850
|
+
}
|
|
2851
|
+
const metric = factory['metric'](resolved.metric, A, B, resolved.opt);
|
|
2852
|
+
if (resolved.output !== 'prep') metric.setOriginal(a, b);
|
|
2853
|
+
await metric.runAsync(mode);
|
|
2854
|
+
const result = this.postProcess(metric.getResults(), resolved);
|
|
2855
|
+
return this.output(result, raw ?? resolved.raw);
|
|
2856
|
+
},
|
|
2857
|
+
`Failed to compute metric <${opt?.metric ?? this.options.metric}> for the given inputs`,
|
|
2858
|
+
{ a, b, opt }
|
|
2859
|
+
);
|
|
2596
2860
|
}
|
|
2597
2861
|
async testAsync(a, b, opt) {
|
|
2598
2862
|
return this.computeAsync(a, b, opt, 'single');
|
|
@@ -2693,6 +2957,7 @@
|
|
|
2693
2957
|
|
|
2694
2958
|
exports.CmpStr = CmpStr;
|
|
2695
2959
|
exports.CmpStrAsync = CmpStrAsync;
|
|
2960
|
+
exports.CmpStrError = Errors;
|
|
2696
2961
|
exports.DeepMerge = DeepMerge;
|
|
2697
2962
|
exports.DiffChecker = DiffChecker;
|
|
2698
2963
|
exports.Filter = Filter;
|
|
@@ -2709,4 +2974,3 @@
|
|
|
2709
2974
|
exports.StructuredData = StructuredData;
|
|
2710
2975
|
exports.TextAnalyzer = TextAnalyzer;
|
|
2711
2976
|
});
|
|
2712
|
-
//# sourceMappingURL=CmpStr.umd.js.map
|