cmpstr 3.2.0 → 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 +26 -18
- package/dist/CmpStr.esm.js +490 -220
- package/dist/CmpStr.esm.min.js +2 -3
- package/dist/CmpStr.umd.js +489 -220
- package/dist/CmpStr.umd.min.js +2 -3
- package/dist/cjs/CmpStr.cjs +58 -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 +56 -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 +56 -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 +56 -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 +12 -6
- package/dist/types/CmpStrAsync.d.ts +6 -4
- package/dist/types/index.d.ts +3 -2
- package/dist/types/metric/Cosine.d.ts +2 -1
- package/dist/types/metric/DamerauLevenshtein.d.ts +2 -1
- package/dist/types/metric/DiceSorensen.d.ts +2 -1
- package/dist/types/metric/Hamming.d.ts +2 -1
- package/dist/types/metric/Jaccard.d.ts +2 -1
- package/dist/types/metric/JaroWinkler.d.ts +2 -1
- package/dist/types/metric/LCS.d.ts +2 -1
- package/dist/types/metric/Levenshtein.d.ts +2 -1
- package/dist/types/metric/Metric.d.ts +7 -5
- package/dist/types/metric/NeedlemanWunsch.d.ts +2 -1
- package/dist/types/metric/QGram.d.ts +2 -1
- package/dist/types/metric/SmithWaterman.d.ts +2 -1
- package/dist/types/metric/index.d.ts +1 -0
- package/dist/types/phonetic/Caverphone.d.ts +2 -1
- package/dist/types/phonetic/Cologne.d.ts +2 -1
- package/dist/types/phonetic/Metaphone.d.ts +2 -1
- package/dist/types/phonetic/Phonetic.d.ts +4 -1
- package/dist/types/phonetic/Soundex.d.ts +2 -1
- package/dist/types/phonetic/index.d.ts +1 -0
- package/dist/types/root.d.ts +2 -1
- package/dist/types/utils/DeepMerge.d.ts +3 -2
- package/dist/types/utils/DiffChecker.d.ts +2 -1
- package/dist/types/utils/Errors.d.ts +137 -0
- package/dist/types/utils/Filter.d.ts +33 -22
- package/dist/types/utils/HashTable.d.ts +2 -1
- package/dist/types/utils/Normalizer.d.ts +5 -1
- package/dist/types/utils/Pool.d.ts +4 -1
- package/dist/types/utils/Profiler.d.ts +3 -2
- package/dist/types/utils/Registry.d.ts +5 -4
- package/dist/types/utils/StructuredData.d.ts +5 -2
- package/dist/types/utils/TextAnalyzer.d.ts +2 -1
- package/dist/types/utils/Types.d.ts +34 -2
- package/package.json +10 -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,19 +593,35 @@
|
|
|
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) {
|
|
618
|
+
Filter.pipeline.clear();
|
|
486
619
|
if (hook) Filter.filters.delete(hook);
|
|
487
620
|
else Filter.filters.clear();
|
|
488
621
|
}
|
|
622
|
+
static clearPipeline() {
|
|
623
|
+
Filter.pipeline.clear();
|
|
624
|
+
}
|
|
489
625
|
}
|
|
490
626
|
|
|
491
627
|
class Hasher {
|
|
@@ -564,42 +700,63 @@
|
|
|
564
700
|
return Array.from(new Set(flags)).sort().join('');
|
|
565
701
|
}
|
|
566
702
|
static getPipeline(flags) {
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
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
|
+
);
|
|
587
730
|
}
|
|
588
731
|
static normalize(input, flags) {
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
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
|
+
);
|
|
598
748
|
}
|
|
599
749
|
static async normalizeAsync(input, flags) {
|
|
600
|
-
return await
|
|
601
|
-
|
|
602
|
-
|
|
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
|
+
);
|
|
603
760
|
}
|
|
604
761
|
static clear() {
|
|
605
762
|
Normalizer.pipeline.clear();
|
|
@@ -689,19 +846,34 @@
|
|
|
689
846
|
const registry = Object.create(null);
|
|
690
847
|
const factory = Object.create(null);
|
|
691
848
|
function Registry(reg, ctor) {
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
849
|
+
ErrorUtil.assert(
|
|
850
|
+
!(reg in registry || reg in factory),
|
|
851
|
+
`Registry <${reg}> already exists / overwriting is forbidden`,
|
|
852
|
+
{ registry: reg }
|
|
853
|
+
);
|
|
696
854
|
const classes = Object.create(null);
|
|
697
855
|
const service = Object.freeze({
|
|
698
856
|
add(name, cls, update = false) {
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
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
|
+
);
|
|
705
877
|
classes[name] = cls;
|
|
706
878
|
},
|
|
707
879
|
remove(name) {
|
|
@@ -714,8 +886,16 @@
|
|
|
714
886
|
return Object.keys(classes);
|
|
715
887
|
},
|
|
716
888
|
get(name) {
|
|
717
|
-
|
|
718
|
-
|
|
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
|
+
);
|
|
719
899
|
return classes[name];
|
|
720
900
|
}
|
|
721
901
|
});
|
|
@@ -725,18 +905,18 @@
|
|
|
725
905
|
}
|
|
726
906
|
function resolveCls(reg, cls) {
|
|
727
907
|
if (!(reg in registry))
|
|
728
|
-
throw new
|
|
908
|
+
throw new CmpStrNotFoundError(`Registry <${reg}> does not exist`, {
|
|
909
|
+
registry: reg
|
|
910
|
+
});
|
|
729
911
|
return typeof cls === 'string' ? registry[reg]?.get(cls) : cls;
|
|
730
912
|
}
|
|
731
913
|
function createFromRegistry(reg, cls, ...args) {
|
|
732
914
|
cls = resolveCls(reg, cls);
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
});
|
|
739
|
-
}
|
|
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
|
+
);
|
|
740
920
|
}
|
|
741
921
|
|
|
742
922
|
class RingPool {
|
|
@@ -747,22 +927,37 @@
|
|
|
747
927
|
this.maxSize = maxSize;
|
|
748
928
|
}
|
|
749
929
|
acquire(minSize, allowOversize) {
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
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
|
+
);
|
|
760
949
|
}
|
|
761
950
|
release(item) {
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
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
|
+
);
|
|
766
961
|
}
|
|
767
962
|
clear() {
|
|
768
963
|
this.buffers = [];
|
|
@@ -815,6 +1010,8 @@
|
|
|
815
1010
|
}
|
|
816
1011
|
static acquire(type, size) {
|
|
817
1012
|
const CONFIG = this.CONFIG[type];
|
|
1013
|
+
if (!CONFIG)
|
|
1014
|
+
throw new CmpStrUsageError(`Unsupported pool type <${type}>`, { type });
|
|
818
1015
|
if (size > CONFIG.maxItemSize) return this.allocate(type, size);
|
|
819
1016
|
const item = this.POOLS[type].acquire(size, CONFIG.allowOversize);
|
|
820
1017
|
if (item)
|
|
@@ -825,7 +1022,10 @@
|
|
|
825
1022
|
return sizes.map((size) => this.acquire(type, size));
|
|
826
1023
|
}
|
|
827
1024
|
static release(type, buffer, size) {
|
|
828
|
-
|
|
1025
|
+
const CONFIG = this.CONFIG[type];
|
|
1026
|
+
if (!CONFIG)
|
|
1027
|
+
throw new CmpStrUsageError(`Unsupported pool type <${type}>`, { type });
|
|
1028
|
+
if (size <= CONFIG.maxItemSize)
|
|
829
1029
|
this.POOLS[type].release({ buffer, size });
|
|
830
1030
|
}
|
|
831
1031
|
}
|
|
@@ -881,7 +1081,7 @@
|
|
|
881
1081
|
raw: r.raw
|
|
882
1082
|
}));
|
|
883
1083
|
else
|
|
884
|
-
throw new
|
|
1084
|
+
throw new CmpStrValidationError(
|
|
885
1085
|
'Unsupported result format for StructuredData normalization.'
|
|
886
1086
|
);
|
|
887
1087
|
return normalized.map((r, idx) => ({ ...r, __idx: idx }));
|
|
@@ -943,10 +1143,18 @@
|
|
|
943
1143
|
);
|
|
944
1144
|
}
|
|
945
1145
|
performLookup(fn, extractedStrings, opt) {
|
|
946
|
-
return
|
|
1146
|
+
return ErrorUtil.wrap(
|
|
1147
|
+
() => this.finalizeLookup(fn(), extractedStrings, opt),
|
|
1148
|
+
'StructuredData lookup failed',
|
|
1149
|
+
{ key: this.key }
|
|
1150
|
+
);
|
|
947
1151
|
}
|
|
948
1152
|
async performLookupAsync(fn, extractedStrings, opt) {
|
|
949
|
-
return
|
|
1153
|
+
return await ErrorUtil.wrapAsync(
|
|
1154
|
+
async () => this.finalizeLookup(await fn(), extractedStrings, opt),
|
|
1155
|
+
'StructuredData async lookup failed',
|
|
1156
|
+
{ key: this.key }
|
|
1157
|
+
);
|
|
950
1158
|
}
|
|
951
1159
|
lookup(fn, query, opt) {
|
|
952
1160
|
const b = this.extract();
|
|
@@ -1200,8 +1408,11 @@
|
|
|
1200
1408
|
this.metric = metric;
|
|
1201
1409
|
this.a = Array.isArray(a) ? a : [a];
|
|
1202
1410
|
this.b = Array.isArray(b) ? b : [b];
|
|
1203
|
-
|
|
1204
|
-
|
|
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
|
+
);
|
|
1205
1416
|
this.options = opt;
|
|
1206
1417
|
this.optKey = Hasher.fastFNV1a(
|
|
1207
1418
|
JSON.stringify(opt, Object.keys(opt).sort())
|
|
@@ -1214,37 +1425,46 @@
|
|
|
1214
1425
|
return undefined;
|
|
1215
1426
|
}
|
|
1216
1427
|
compute(a, b, m, n, maxLen) {
|
|
1217
|
-
throw new
|
|
1428
|
+
throw new CmpStrInternalError(
|
|
1429
|
+
`Method compute() must be overridden in a subclass`
|
|
1430
|
+
);
|
|
1218
1431
|
}
|
|
1219
1432
|
runSingle(i, j) {
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
if (
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
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
|
+
);
|
|
1248
1468
|
}
|
|
1249
1469
|
async runSingleAsync(i, j) {
|
|
1250
1470
|
return Promise.resolve(this.runSingle(i, j));
|
|
@@ -1287,8 +1507,9 @@
|
|
|
1287
1507
|
? true
|
|
1288
1508
|
: !safe &&
|
|
1289
1509
|
(() => {
|
|
1290
|
-
throw new
|
|
1291
|
-
`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 }
|
|
1292
1513
|
);
|
|
1293
1514
|
})();
|
|
1294
1515
|
}
|
|
@@ -1313,7 +1534,7 @@
|
|
|
1313
1534
|
if (this.isPairwise()) this.runPairwise();
|
|
1314
1535
|
break;
|
|
1315
1536
|
default:
|
|
1316
|
-
throw new
|
|
1537
|
+
throw new CmpStrInternalError(`Unsupported mode <${mode}>`);
|
|
1317
1538
|
}
|
|
1318
1539
|
}
|
|
1319
1540
|
async runAsync(mode, clear = true) {
|
|
@@ -1334,13 +1555,15 @@
|
|
|
1334
1555
|
if (this.isPairwise()) await this.runPairwiseAsync();
|
|
1335
1556
|
break;
|
|
1336
1557
|
default:
|
|
1337
|
-
throw new
|
|
1558
|
+
throw new CmpStrInternalError(`Unsupported async mode <${mode}>`);
|
|
1338
1559
|
}
|
|
1339
1560
|
}
|
|
1340
1561
|
getMetricName = () => this.metric;
|
|
1341
1562
|
getResults() {
|
|
1342
|
-
|
|
1343
|
-
|
|
1563
|
+
ErrorUtil.assert(
|
|
1564
|
+
this.results !== undefined,
|
|
1565
|
+
`run() must be called before getResults()`
|
|
1566
|
+
);
|
|
1344
1567
|
return this.results;
|
|
1345
1568
|
}
|
|
1346
1569
|
}
|
|
@@ -1472,9 +1695,10 @@
|
|
|
1472
1695
|
if (n < maxLen) b = b.padEnd(maxLen, this.options.pad);
|
|
1473
1696
|
m = n = maxLen;
|
|
1474
1697
|
} else
|
|
1475
|
-
throw new
|
|
1698
|
+
throw new CmpStrUsageError(
|
|
1476
1699
|
`Strings must be of equal length for Hamming Distance, a=${m} and b=${n} given, ` +
|
|
1477
|
-
`use option.pad for automatic adjustment
|
|
1700
|
+
`use option.pad for automatic adjustment`,
|
|
1701
|
+
{ a: m, b: n }
|
|
1478
1702
|
);
|
|
1479
1703
|
}
|
|
1480
1704
|
let dist = 0;
|
|
@@ -1753,10 +1977,16 @@
|
|
|
1753
1977
|
const defaults = this.constructor.default ?? {};
|
|
1754
1978
|
const mapId = opt.map ?? defaults.map;
|
|
1755
1979
|
if (!mapId)
|
|
1756
|
-
throw new
|
|
1980
|
+
throw new CmpStrNotFoundError(
|
|
1981
|
+
`No mapping specified for phonetic algorithm`,
|
|
1982
|
+
{ algo }
|
|
1983
|
+
);
|
|
1757
1984
|
const map = PhoneticMappingRegistry.get(algo, mapId);
|
|
1758
1985
|
if (map === undefined)
|
|
1759
|
-
throw new
|
|
1986
|
+
throw new CmpStrNotFoundError(
|
|
1987
|
+
`Requested mapping <${mapId}> is not declared`,
|
|
1988
|
+
{ algo, mapId }
|
|
1989
|
+
);
|
|
1760
1990
|
this.options = merge(merge(defaults, map.options ?? {}), opt);
|
|
1761
1991
|
this.optKey = Hasher.fastFNV1a(
|
|
1762
1992
|
JSON.stringify(this.options, Object.keys(this.options).sort())
|
|
@@ -1847,35 +2077,47 @@
|
|
|
1847
2077
|
return code;
|
|
1848
2078
|
}
|
|
1849
2079
|
loop(words) {
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
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
|
+
);
|
|
1863
2099
|
}
|
|
1864
2100
|
async loopAsync(words) {
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
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
|
+
);
|
|
1879
2121
|
}
|
|
1880
2122
|
getAlgoName = () => this.algo;
|
|
1881
2123
|
getIndex(input) {
|
|
@@ -1901,10 +2143,11 @@
|
|
|
1901
2143
|
return Object.freeze({
|
|
1902
2144
|
add(algo, id, map, update = false) {
|
|
1903
2145
|
const mappings = maps(algo);
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
2146
|
+
ErrorUtil.assert(
|
|
2147
|
+
!(!id || id in mappings) || update,
|
|
2148
|
+
`Entry <${id}> already exists / use <update=true> to overwrite`,
|
|
2149
|
+
{ algo, id }
|
|
2150
|
+
);
|
|
1908
2151
|
mappings[id] = map;
|
|
1909
2152
|
},
|
|
1910
2153
|
remove(algo, id) {
|
|
@@ -2311,6 +2554,7 @@
|
|
|
2311
2554
|
static profiler = profiler.services;
|
|
2312
2555
|
static clearCache = {
|
|
2313
2556
|
normalizer: Normalizer.clear,
|
|
2557
|
+
filter: Filter.clearPipeline,
|
|
2314
2558
|
metric: Metric.clear,
|
|
2315
2559
|
phonetic: Phonetic.clear
|
|
2316
2560
|
};
|
|
@@ -2330,20 +2574,22 @@
|
|
|
2330
2574
|
switch (cond) {
|
|
2331
2575
|
case 'metric':
|
|
2332
2576
|
if (!CmpStr.metric.has(test))
|
|
2333
|
-
throw new
|
|
2577
|
+
throw new CmpStrNotFoundError(
|
|
2334
2578
|
`CmpStr <metric> must be set, call .setMetric(), ` +
|
|
2335
|
-
`use CmpStr.metric.list() for available metrics
|
|
2579
|
+
`use CmpStr.metric.list() for available metrics`,
|
|
2580
|
+
{ metric: test }
|
|
2336
2581
|
);
|
|
2337
2582
|
break;
|
|
2338
2583
|
case 'phonetic':
|
|
2339
2584
|
if (!CmpStr.phonetic.has(test))
|
|
2340
|
-
throw new
|
|
2585
|
+
throw new CmpStrNotFoundError(
|
|
2341
2586
|
`CmpStr <phonetic> must be set, call .setPhonetic(), ` +
|
|
2342
|
-
`use CmpStr.phonetic.list() for available phonetic algorithms
|
|
2587
|
+
`use CmpStr.phonetic.list() for available phonetic algorithms`,
|
|
2588
|
+
{ phonetic: test }
|
|
2343
2589
|
);
|
|
2344
2590
|
break;
|
|
2345
2591
|
default:
|
|
2346
|
-
throw new
|
|
2592
|
+
throw new CmpStrInternalError(`Cmpstr condition <${cond}> unknown`);
|
|
2347
2593
|
}
|
|
2348
2594
|
}
|
|
2349
2595
|
assertMany(...cond) {
|
|
@@ -2382,31 +2628,42 @@
|
|
|
2382
2628
|
return StructuredData.create(data, key);
|
|
2383
2629
|
}
|
|
2384
2630
|
compute(a, b, opt, mode, raw, skip) {
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
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
|
+
);
|
|
2403
2655
|
}
|
|
2404
2656
|
output(result, raw) {
|
|
2405
|
-
return (
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
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
|
+
);
|
|
2410
2667
|
}
|
|
2411
2668
|
clone = () =>
|
|
2412
2669
|
Object.assign(Object.create(Object.getPrototypeOf(this)), this);
|
|
@@ -2423,8 +2680,14 @@
|
|
|
2423
2680
|
return this;
|
|
2424
2681
|
}
|
|
2425
2682
|
setSerializedOptions(opt) {
|
|
2426
|
-
|
|
2427
|
-
|
|
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
|
+
);
|
|
2428
2691
|
}
|
|
2429
2692
|
setOption(path, value) {
|
|
2430
2693
|
set(this.options, path, value);
|
|
@@ -2570,24 +2833,30 @@
|
|
|
2570
2833
|
: phonetic.getIndexAsync(input).then((r) => r.join(delimiter));
|
|
2571
2834
|
}
|
|
2572
2835
|
async computeAsync(a, b, opt, mode, raw, skip) {
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
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
|
+
);
|
|
2591
2860
|
}
|
|
2592
2861
|
async testAsync(a, b, opt) {
|
|
2593
2862
|
return this.computeAsync(a, b, opt, 'single');
|
|
@@ -2688,6 +2957,7 @@
|
|
|
2688
2957
|
|
|
2689
2958
|
exports.CmpStr = CmpStr;
|
|
2690
2959
|
exports.CmpStrAsync = CmpStrAsync;
|
|
2960
|
+
exports.CmpStrError = Errors;
|
|
2691
2961
|
exports.DeepMerge = DeepMerge;
|
|
2692
2962
|
exports.DiffChecker = DiffChecker;
|
|
2693
2963
|
exports.Filter = Filter;
|
|
@@ -2704,4 +2974,3 @@
|
|
|
2704
2974
|
exports.StructuredData = StructuredData;
|
|
2705
2975
|
exports.TextAnalyzer = TextAnalyzer;
|
|
2706
2976
|
});
|
|
2707
|
-
//# sourceMappingURL=CmpStr.umd.js.map
|