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.
Files changed (150) hide show
  1. package/README.md +24 -18
  2. package/dist/CmpStr.esm.js +485 -220
  3. package/dist/CmpStr.esm.min.js +2 -3
  4. package/dist/CmpStr.umd.js +484 -220
  5. package/dist/CmpStr.umd.min.js +2 -3
  6. package/dist/cjs/CmpStr.cjs +57 -36
  7. package/dist/cjs/CmpStrAsync.cjs +30 -24
  8. package/dist/cjs/index.cjs +1 -2
  9. package/dist/cjs/metric/Cosine.cjs +1 -2
  10. package/dist/cjs/metric/DamerauLevenshtein.cjs +1 -2
  11. package/dist/cjs/metric/DiceSorensen.cjs +1 -2
  12. package/dist/cjs/metric/Hamming.cjs +5 -4
  13. package/dist/cjs/metric/Jaccard.cjs +1 -2
  14. package/dist/cjs/metric/JaroWinkler.cjs +1 -2
  15. package/dist/cjs/metric/LCS.cjs +1 -2
  16. package/dist/cjs/metric/Levenshtein.cjs +1 -2
  17. package/dist/cjs/metric/Metric.cjs +57 -38
  18. package/dist/cjs/metric/NeedlemanWunsch.cjs +1 -2
  19. package/dist/cjs/metric/QGram.cjs +1 -2
  20. package/dist/cjs/metric/SmithWaterman.cjs +1 -2
  21. package/dist/cjs/phonetic/Caverphone.cjs +1 -2
  22. package/dist/cjs/phonetic/Cologne.cjs +1 -2
  23. package/dist/cjs/phonetic/Metaphone.cjs +1 -2
  24. package/dist/cjs/phonetic/Phonetic.cjs +55 -35
  25. package/dist/cjs/phonetic/Soundex.cjs +1 -2
  26. package/dist/cjs/root.cjs +3 -2
  27. package/dist/cjs/utils/DeepMerge.cjs +10 -5
  28. package/dist/cjs/utils/DiffChecker.cjs +1 -2
  29. package/dist/cjs/utils/Errors.cjs +103 -0
  30. package/dist/cjs/utils/Filter.cjs +52 -27
  31. package/dist/cjs/utils/HashTable.cjs +1 -2
  32. package/dist/cjs/utils/Normalizer.cjs +54 -34
  33. package/dist/cjs/utils/Pool.cjs +42 -18
  34. package/dist/cjs/utils/Profiler.cjs +1 -2
  35. package/dist/cjs/utils/Registry.cjs +46 -22
  36. package/dist/cjs/utils/StructuredData.cjs +13 -5
  37. package/dist/cjs/utils/TextAnalyzer.cjs +1 -2
  38. package/dist/esm/CmpStr.mjs +55 -32
  39. package/dist/esm/CmpStrAsync.mjs +26 -20
  40. package/dist/esm/index.mjs +1 -2
  41. package/dist/esm/metric/Cosine.mjs +1 -2
  42. package/dist/esm/metric/DamerauLevenshtein.mjs +1 -2
  43. package/dist/esm/metric/DiceSorensen.mjs +1 -2
  44. package/dist/esm/metric/Hamming.mjs +5 -4
  45. package/dist/esm/metric/Jaccard.mjs +1 -2
  46. package/dist/esm/metric/JaroWinkler.mjs +1 -2
  47. package/dist/esm/metric/LCS.mjs +1 -2
  48. package/dist/esm/metric/Levenshtein.mjs +1 -2
  49. package/dist/esm/metric/Metric.mjs +59 -38
  50. package/dist/esm/metric/NeedlemanWunsch.mjs +1 -2
  51. package/dist/esm/metric/QGram.mjs +1 -2
  52. package/dist/esm/metric/SmithWaterman.mjs +1 -2
  53. package/dist/esm/phonetic/Caverphone.mjs +1 -2
  54. package/dist/esm/phonetic/Cologne.mjs +1 -2
  55. package/dist/esm/phonetic/Metaphone.mjs +1 -2
  56. package/dist/esm/phonetic/Phonetic.mjs +55 -35
  57. package/dist/esm/phonetic/Soundex.mjs +1 -2
  58. package/dist/esm/root.mjs +3 -2
  59. package/dist/esm/utils/DeepMerge.mjs +10 -5
  60. package/dist/esm/utils/DiffChecker.mjs +1 -2
  61. package/dist/esm/utils/Errors.mjs +103 -0
  62. package/dist/esm/utils/Filter.mjs +52 -27
  63. package/dist/esm/utils/HashTable.mjs +1 -2
  64. package/dist/esm/utils/Normalizer.mjs +54 -34
  65. package/dist/esm/utils/Pool.mjs +38 -18
  66. package/dist/esm/utils/Profiler.mjs +1 -2
  67. package/dist/esm/utils/Registry.mjs +46 -22
  68. package/dist/esm/utils/StructuredData.mjs +13 -5
  69. package/dist/esm/utils/TextAnalyzer.mjs +1 -2
  70. package/dist/types/CmpStr.d.ts +5 -1
  71. package/dist/types/CmpStrAsync.d.ts +1 -0
  72. package/dist/types/index.d.ts +3 -2
  73. package/dist/types/metric/Metric.d.ts +6 -5
  74. package/dist/types/phonetic/Phonetic.d.ts +3 -1
  75. package/dist/types/root.d.ts +2 -1
  76. package/dist/types/utils/DeepMerge.d.ts +1 -1
  77. package/dist/types/utils/Errors.d.ts +137 -0
  78. package/dist/types/utils/Filter.d.ts +4 -0
  79. package/dist/types/utils/Normalizer.d.ts +3 -0
  80. package/dist/types/utils/Pool.d.ts +2 -0
  81. package/dist/types/utils/Registry.d.ts +3 -3
  82. package/dist/types/utils/StructuredData.d.ts +3 -1
  83. package/dist/types/utils/Types.d.ts +26 -0
  84. package/package.json +7 -7
  85. package/dist/CmpStr.esm.js.map +0 -1
  86. package/dist/CmpStr.esm.min.js.map +0 -1
  87. package/dist/CmpStr.umd.js.map +0 -1
  88. package/dist/CmpStr.umd.min.js.map +0 -1
  89. package/dist/cjs/CmpStr.cjs.map +0 -1
  90. package/dist/cjs/CmpStrAsync.cjs.map +0 -1
  91. package/dist/cjs/index.cjs.map +0 -1
  92. package/dist/cjs/metric/Cosine.cjs.map +0 -1
  93. package/dist/cjs/metric/DamerauLevenshtein.cjs.map +0 -1
  94. package/dist/cjs/metric/DiceSorensen.cjs.map +0 -1
  95. package/dist/cjs/metric/Hamming.cjs.map +0 -1
  96. package/dist/cjs/metric/Jaccard.cjs.map +0 -1
  97. package/dist/cjs/metric/JaroWinkler.cjs.map +0 -1
  98. package/dist/cjs/metric/LCS.cjs.map +0 -1
  99. package/dist/cjs/metric/Levenshtein.cjs.map +0 -1
  100. package/dist/cjs/metric/Metric.cjs.map +0 -1
  101. package/dist/cjs/metric/NeedlemanWunsch.cjs.map +0 -1
  102. package/dist/cjs/metric/QGram.cjs.map +0 -1
  103. package/dist/cjs/metric/SmithWaterman.cjs.map +0 -1
  104. package/dist/cjs/phonetic/Caverphone.cjs.map +0 -1
  105. package/dist/cjs/phonetic/Cologne.cjs.map +0 -1
  106. package/dist/cjs/phonetic/Metaphone.cjs.map +0 -1
  107. package/dist/cjs/phonetic/Phonetic.cjs.map +0 -1
  108. package/dist/cjs/phonetic/Soundex.cjs.map +0 -1
  109. package/dist/cjs/root.cjs.map +0 -1
  110. package/dist/cjs/utils/DeepMerge.cjs.map +0 -1
  111. package/dist/cjs/utils/DiffChecker.cjs.map +0 -1
  112. package/dist/cjs/utils/Filter.cjs.map +0 -1
  113. package/dist/cjs/utils/HashTable.cjs.map +0 -1
  114. package/dist/cjs/utils/Normalizer.cjs.map +0 -1
  115. package/dist/cjs/utils/Pool.cjs.map +0 -1
  116. package/dist/cjs/utils/Profiler.cjs.map +0 -1
  117. package/dist/cjs/utils/Registry.cjs.map +0 -1
  118. package/dist/cjs/utils/StructuredData.cjs.map +0 -1
  119. package/dist/cjs/utils/TextAnalyzer.cjs.map +0 -1
  120. package/dist/esm/CmpStr.mjs.map +0 -1
  121. package/dist/esm/CmpStrAsync.mjs.map +0 -1
  122. package/dist/esm/index.mjs.map +0 -1
  123. package/dist/esm/metric/Cosine.mjs.map +0 -1
  124. package/dist/esm/metric/DamerauLevenshtein.mjs.map +0 -1
  125. package/dist/esm/metric/DiceSorensen.mjs.map +0 -1
  126. package/dist/esm/metric/Hamming.mjs.map +0 -1
  127. package/dist/esm/metric/Jaccard.mjs.map +0 -1
  128. package/dist/esm/metric/JaroWinkler.mjs.map +0 -1
  129. package/dist/esm/metric/LCS.mjs.map +0 -1
  130. package/dist/esm/metric/Levenshtein.mjs.map +0 -1
  131. package/dist/esm/metric/Metric.mjs.map +0 -1
  132. package/dist/esm/metric/NeedlemanWunsch.mjs.map +0 -1
  133. package/dist/esm/metric/QGram.mjs.map +0 -1
  134. package/dist/esm/metric/SmithWaterman.mjs.map +0 -1
  135. package/dist/esm/phonetic/Caverphone.mjs.map +0 -1
  136. package/dist/esm/phonetic/Cologne.mjs.map +0 -1
  137. package/dist/esm/phonetic/Metaphone.mjs.map +0 -1
  138. package/dist/esm/phonetic/Phonetic.mjs.map +0 -1
  139. package/dist/esm/phonetic/Soundex.mjs.map +0 -1
  140. package/dist/esm/root.mjs.map +0 -1
  141. package/dist/esm/utils/DeepMerge.mjs.map +0 -1
  142. package/dist/esm/utils/DiffChecker.mjs.map +0 -1
  143. package/dist/esm/utils/Filter.mjs.map +0 -1
  144. package/dist/esm/utils/HashTable.mjs.map +0 -1
  145. package/dist/esm/utils/Normalizer.mjs.map +0 -1
  146. package/dist/esm/utils/Pool.mjs.map +0 -1
  147. package/dist/esm/utils/Profiler.mjs.map +0 -1
  148. package/dist/esm/utils/Registry.mjs.map +0 -1
  149. package/dist/esm/utils/StructuredData.mjs.map +0 -1
  150. package/dist/esm/utils/TextAnalyzer.mjs.map +0 -1
@@ -1,5 +1,5 @@
1
1
  /**
2
- * CmpStr v3.2.1 build-3439ccb-260130
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 Error(`Cannot set property <${keys[0]}> of <${JSON.stringify(t)}>`);
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 Error(
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
- const cached = Filter.pipeline.get(hook);
429
- if (cached) return cached;
430
- const filter = Filter.filters.get(hook);
431
- if (!filter) return (s) => s;
432
- const pipeline = Array.from(filter.values())
433
- .filter((f) => f.active)
434
- .sort((a, b) => a.priority - b.priority)
435
- .map((f) => f.fn);
436
- const fn = (input) => pipeline.reduce((v, f) => f(v), input);
437
- Filter.pipeline.set(hook, fn);
438
- return fn;
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
- const { priority = 10, active = true, overrideable = true } = opt;
445
- const filter = Filter.filters.get(hook) ?? new Map();
446
- const index = filter.get(id);
447
- if (index && !index.overrideable) return false;
448
- filter.set(id, { id, fn, priority, active, overrideable });
449
- Filter.filters.set(hook, filter);
450
- Filter.pipeline.delete(hook);
451
- return true;
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
- const fn = Filter.getPipeline(hook);
477
- return Array.isArray(input) ? input.map(fn) : fn(input);
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
- const fn = Filter.getPipeline(hook);
481
- return Array.isArray(input)
482
- ? Promise.all(input.map(fn))
483
- : Promise.resolve(fn(input));
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
- if (Normalizer.pipeline.has(flags)) return Normalizer.pipeline.get(flags);
572
- const { REGEX } = Normalizer;
573
- const steps = [
574
- ['d', (s) => s.normalize('NFD')],
575
- ['i', (s) => s.toLowerCase()],
576
- ['k', (s) => s.replace(REGEX.nonLetters, '')],
577
- ['n', (s) => s.replace(REGEX.nonNumbers, '')],
578
- ['r', (s) => s.replace(REGEX.doubleChars, '$1')],
579
- ['s', (s) => s.replace(REGEX.specialChars, '')],
580
- ['t', (s) => s.trim()],
581
- ['u', (s) => s.normalize('NFC')],
582
- ['w', (s) => s.replace(REGEX.whitespace, ' ')],
583
- ['x', (s) => s.normalize('NFKC')]
584
- ];
585
- const pipeline = steps
586
- .filter(([f]) => flags.includes(f))
587
- .map(([, fn]) => fn);
588
- const fn = (s) => pipeline.reduce((v, f) => f(v), s);
589
- Normalizer.pipeline.set(flags, fn);
590
- return fn;
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
- if (!flags || typeof flags !== 'string' || !input) return input;
594
- flags = this.canonicalFlags(flags);
595
- if (Array.isArray(input))
596
- return input.map((s) => Normalizer.normalize(s, flags));
597
- const key = Normalizer.cache.key(flags, [input]);
598
- if (key && Normalizer.cache.has(key)) return Normalizer.cache.get(key);
599
- const res = Normalizer.getPipeline(flags)(input);
600
- if (key) Normalizer.cache.set(key, res);
601
- return res;
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 (Array.isArray(input)
605
- ? Promise.all(input.map((s) => Normalizer.normalize(s, flags)))
606
- : Promise.resolve(Normalizer.normalize(input, flags)));
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
- if (reg in registry || reg in factory)
697
- throw new Error(
698
- `Registry <${reg}> already exists / overwriting is forbidden`
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
- if (!(cls.prototype instanceof ctor))
704
- throw new TypeError(`Class must extend <${reg}>`);
705
- if (!update && name in classes)
706
- throw new Error(
707
- `Entry <${name}> already exists / use <update=true> to overwrite`
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
- if (!(name in classes))
722
- throw new Error(`Class <${name}> not registered for <${reg}>`);
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 ReferenceError(`Registry <${reg}> does not exist`);
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
- try {
738
- return new cls(...args);
739
- } catch (err) {
740
- throw new Error(`Cannot instantiate class <${cls.name ?? cls}>`, {
741
- cause: err
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
- const len = this.buffers.length;
755
- for (let i = 0; i < len; i++) {
756
- const idx = (this.pointer + i) & (len - 1);
757
- const item = this.buffers[idx];
758
- if (item.size >= minSize && (allowOversize || item.size === minSize)) {
759
- this.pointer = (idx + 1) & (len - 1);
760
- return item;
761
- }
762
- }
763
- return null;
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
- if (this.buffers.length < this.maxSize)
767
- return void [this.buffers.push(item)];
768
- this.buffers[this.pointer] = item;
769
- this.pointer = (this.pointer + 1) % this.maxSize;
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
- if (size <= this.CONFIG[type].maxItemSize)
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 TypeError(
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 this.finalizeLookup(fn(), extractedStrings, opt);
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 this.finalizeLookup(await fn(), extractedStrings, opt);
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
- if (this.a.length === 0 || this.b.length === 0)
1208
- throw new Error(`Inputs <a> and <b> must not be empty`);
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 Error(`Method compute() must be overridden in a subclass`);
1428
+ throw new CmpStrInternalError(
1429
+ `Method compute() must be overridden in a subclass`
1430
+ );
1222
1431
  }
1223
1432
  runSingle(i, j) {
1224
- let a = String(this.a[i]),
1225
- A = a;
1226
- let b = String(this.b[j]),
1227
- B = b;
1228
- let m = A.length,
1229
- n = B.length;
1230
- let result = this.preCompute(A, B, m, n);
1231
- if (!result) {
1232
- result = profiler$2.run(() => {
1233
- if (this.symmetric) [A, B, m, n] = Metric.swap(A, B, m, n);
1234
- const key =
1235
- Metric.cache.key(this.metric, [A, B], this.symmetric) + this.optKey;
1236
- return (
1237
- Metric.cache.get(key || '') ??
1238
- (() => {
1239
- const res = this.compute(A, B, m, n, Math.max(m, n));
1240
- if (key) Metric.cache.set(key, res);
1241
- return res;
1242
- })()
1243
- );
1244
- });
1245
- }
1246
- return {
1247
- metric: this.metric,
1248
- a: this.origA[i] ?? a,
1249
- b: this.origB[j] ?? b,
1250
- ...result
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 Error(
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 Error(`Unsupported mode <${mode}>`);
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 Error(`Unsupported async mode <${mode}>`);
1558
+ throw new CmpStrInternalError(`Unsupported async mode <${mode}>`);
1342
1559
  }
1343
1560
  }
1344
1561
  getMetricName = () => this.metric;
1345
1562
  getResults() {
1346
- if (this.results === undefined)
1347
- throw new Error(`run() must be called before getResult()`);
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 Error(
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 Error(`No mapping specified for phonetic algorithm`);
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 Error(`Requested mapping <${mapId}> is not declared`);
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
- const index = [];
1855
- for (const word of words) {
1856
- const key = Phonetic.cache.key(this.algo, [word]) + this.optKey;
1857
- const code =
1858
- Phonetic.cache.get(key || '') ??
1859
- (() => {
1860
- const res = this.encode(word);
1861
- if (key) Phonetic.cache.set(key, res);
1862
- return res;
1863
- })();
1864
- if (code && code.length) index.push(this.equalLen(code));
1865
- }
1866
- return index;
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
- const index = [];
1870
- for (const word of words) {
1871
- const key = Phonetic.cache.key(this.algo, [word]) + this.optKey;
1872
- const code = await Promise.resolve(
1873
- Phonetic.cache.get(key || '') ??
1874
- (() => {
1875
- const res = this.encode(word);
1876
- if (key) Phonetic.cache.set(key, res);
1877
- return res;
1878
- })()
1879
- );
1880
- if (code && code.length) index.push(this.equalLen(code));
1881
- }
1882
- return index;
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
- if (!update && id in mappings)
1909
- throw new Error(
1910
- `Entry <${id}> already exists / use <update=true> to overwrite`
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 Error(
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 Error(
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 Error(`Cmpstr condition <${cond}> unknown`);
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
- const resolved = this.resolveOptions(opt);
2391
- this.assert('metric', resolved.metric);
2392
- const A = skip ? a : this.prepare(a, resolved);
2393
- const B = skip ? b : this.prepare(b, resolved);
2394
- if (
2395
- resolved.safeEmpty &&
2396
- ((Array.isArray(A) && A.length === 0) ||
2397
- (Array.isArray(B) && B.length === 0) ||
2398
- A === '' ||
2399
- B === '')
2400
- ) {
2401
- return [];
2402
- }
2403
- const metric = factory['metric'](resolved.metric, A, B, resolved.opt);
2404
- if (resolved.output !== 'prep') metric.setOriginal(a, b);
2405
- metric.run(mode);
2406
- const result = this.postProcess(metric.getResults(), resolved);
2407
- return this.output(result, raw ?? resolved.raw);
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 (raw ?? this.options.raw)
2411
- ? result
2412
- : Array.isArray(result)
2413
- ? result.map((r) => ({ source: r.a, target: r.b, match: r.res }))
2414
- : { source: result.a, target: result.b, match: result.res };
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
- this.options = JSON.parse(opt);
2432
- return this;
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
- const resolved = this.resolveOptions(opt);
2579
- this.assert('metric', resolved.metric);
2580
- const A = skip ? a : await this.prepareAsync(a, resolved);
2581
- const B = skip ? b : await this.prepareAsync(b, resolved);
2582
- if (
2583
- resolved.safeEmpty &&
2584
- ((Array.isArray(A) && A.length === 0) ||
2585
- (Array.isArray(B) && B.length === 0) ||
2586
- A === '' ||
2587
- B === '')
2588
- ) {
2589
- return [];
2590
- }
2591
- const metric = factory['metric'](resolved.metric, A, B, resolved.opt);
2592
- if (resolved.output !== 'prep') metric.setOriginal(a, b);
2593
- await metric.runAsync(mode);
2594
- const result = this.postProcess(metric.getResults(), resolved);
2595
- return this.output(result, raw ?? resolved.raw);
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