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.
Files changed (171) hide show
  1. package/README.md +26 -18
  2. package/dist/CmpStr.esm.js +490 -220
  3. package/dist/CmpStr.esm.min.js +2 -3
  4. package/dist/CmpStr.umd.js +489 -220
  5. package/dist/CmpStr.umd.min.js +2 -3
  6. package/dist/cjs/CmpStr.cjs +58 -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 +56 -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 +56 -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 +56 -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 +12 -6
  71. package/dist/types/CmpStrAsync.d.ts +6 -4
  72. package/dist/types/index.d.ts +3 -2
  73. package/dist/types/metric/Cosine.d.ts +2 -1
  74. package/dist/types/metric/DamerauLevenshtein.d.ts +2 -1
  75. package/dist/types/metric/DiceSorensen.d.ts +2 -1
  76. package/dist/types/metric/Hamming.d.ts +2 -1
  77. package/dist/types/metric/Jaccard.d.ts +2 -1
  78. package/dist/types/metric/JaroWinkler.d.ts +2 -1
  79. package/dist/types/metric/LCS.d.ts +2 -1
  80. package/dist/types/metric/Levenshtein.d.ts +2 -1
  81. package/dist/types/metric/Metric.d.ts +7 -5
  82. package/dist/types/metric/NeedlemanWunsch.d.ts +2 -1
  83. package/dist/types/metric/QGram.d.ts +2 -1
  84. package/dist/types/metric/SmithWaterman.d.ts +2 -1
  85. package/dist/types/metric/index.d.ts +1 -0
  86. package/dist/types/phonetic/Caverphone.d.ts +2 -1
  87. package/dist/types/phonetic/Cologne.d.ts +2 -1
  88. package/dist/types/phonetic/Metaphone.d.ts +2 -1
  89. package/dist/types/phonetic/Phonetic.d.ts +4 -1
  90. package/dist/types/phonetic/Soundex.d.ts +2 -1
  91. package/dist/types/phonetic/index.d.ts +1 -0
  92. package/dist/types/root.d.ts +2 -1
  93. package/dist/types/utils/DeepMerge.d.ts +3 -2
  94. package/dist/types/utils/DiffChecker.d.ts +2 -1
  95. package/dist/types/utils/Errors.d.ts +137 -0
  96. package/dist/types/utils/Filter.d.ts +33 -22
  97. package/dist/types/utils/HashTable.d.ts +2 -1
  98. package/dist/types/utils/Normalizer.d.ts +5 -1
  99. package/dist/types/utils/Pool.d.ts +4 -1
  100. package/dist/types/utils/Profiler.d.ts +3 -2
  101. package/dist/types/utils/Registry.d.ts +5 -4
  102. package/dist/types/utils/StructuredData.d.ts +5 -2
  103. package/dist/types/utils/TextAnalyzer.d.ts +2 -1
  104. package/dist/types/utils/Types.d.ts +34 -2
  105. package/package.json +10 -7
  106. package/dist/CmpStr.esm.js.map +0 -1
  107. package/dist/CmpStr.esm.min.js.map +0 -1
  108. package/dist/CmpStr.umd.js.map +0 -1
  109. package/dist/CmpStr.umd.min.js.map +0 -1
  110. package/dist/cjs/CmpStr.cjs.map +0 -1
  111. package/dist/cjs/CmpStrAsync.cjs.map +0 -1
  112. package/dist/cjs/index.cjs.map +0 -1
  113. package/dist/cjs/metric/Cosine.cjs.map +0 -1
  114. package/dist/cjs/metric/DamerauLevenshtein.cjs.map +0 -1
  115. package/dist/cjs/metric/DiceSorensen.cjs.map +0 -1
  116. package/dist/cjs/metric/Hamming.cjs.map +0 -1
  117. package/dist/cjs/metric/Jaccard.cjs.map +0 -1
  118. package/dist/cjs/metric/JaroWinkler.cjs.map +0 -1
  119. package/dist/cjs/metric/LCS.cjs.map +0 -1
  120. package/dist/cjs/metric/Levenshtein.cjs.map +0 -1
  121. package/dist/cjs/metric/Metric.cjs.map +0 -1
  122. package/dist/cjs/metric/NeedlemanWunsch.cjs.map +0 -1
  123. package/dist/cjs/metric/QGram.cjs.map +0 -1
  124. package/dist/cjs/metric/SmithWaterman.cjs.map +0 -1
  125. package/dist/cjs/phonetic/Caverphone.cjs.map +0 -1
  126. package/dist/cjs/phonetic/Cologne.cjs.map +0 -1
  127. package/dist/cjs/phonetic/Metaphone.cjs.map +0 -1
  128. package/dist/cjs/phonetic/Phonetic.cjs.map +0 -1
  129. package/dist/cjs/phonetic/Soundex.cjs.map +0 -1
  130. package/dist/cjs/root.cjs.map +0 -1
  131. package/dist/cjs/utils/DeepMerge.cjs.map +0 -1
  132. package/dist/cjs/utils/DiffChecker.cjs.map +0 -1
  133. package/dist/cjs/utils/Filter.cjs.map +0 -1
  134. package/dist/cjs/utils/HashTable.cjs.map +0 -1
  135. package/dist/cjs/utils/Normalizer.cjs.map +0 -1
  136. package/dist/cjs/utils/Pool.cjs.map +0 -1
  137. package/dist/cjs/utils/Profiler.cjs.map +0 -1
  138. package/dist/cjs/utils/Registry.cjs.map +0 -1
  139. package/dist/cjs/utils/StructuredData.cjs.map +0 -1
  140. package/dist/cjs/utils/TextAnalyzer.cjs.map +0 -1
  141. package/dist/esm/CmpStr.mjs.map +0 -1
  142. package/dist/esm/CmpStrAsync.mjs.map +0 -1
  143. package/dist/esm/index.mjs.map +0 -1
  144. package/dist/esm/metric/Cosine.mjs.map +0 -1
  145. package/dist/esm/metric/DamerauLevenshtein.mjs.map +0 -1
  146. package/dist/esm/metric/DiceSorensen.mjs.map +0 -1
  147. package/dist/esm/metric/Hamming.mjs.map +0 -1
  148. package/dist/esm/metric/Jaccard.mjs.map +0 -1
  149. package/dist/esm/metric/JaroWinkler.mjs.map +0 -1
  150. package/dist/esm/metric/LCS.mjs.map +0 -1
  151. package/dist/esm/metric/Levenshtein.mjs.map +0 -1
  152. package/dist/esm/metric/Metric.mjs.map +0 -1
  153. package/dist/esm/metric/NeedlemanWunsch.mjs.map +0 -1
  154. package/dist/esm/metric/QGram.mjs.map +0 -1
  155. package/dist/esm/metric/SmithWaterman.mjs.map +0 -1
  156. package/dist/esm/phonetic/Caverphone.mjs.map +0 -1
  157. package/dist/esm/phonetic/Cologne.mjs.map +0 -1
  158. package/dist/esm/phonetic/Metaphone.mjs.map +0 -1
  159. package/dist/esm/phonetic/Phonetic.mjs.map +0 -1
  160. package/dist/esm/phonetic/Soundex.mjs.map +0 -1
  161. package/dist/esm/root.mjs.map +0 -1
  162. package/dist/esm/utils/DeepMerge.mjs.map +0 -1
  163. package/dist/esm/utils/DiffChecker.mjs.map +0 -1
  164. package/dist/esm/utils/Filter.mjs.map +0 -1
  165. package/dist/esm/utils/HashTable.mjs.map +0 -1
  166. package/dist/esm/utils/Normalizer.mjs.map +0 -1
  167. package/dist/esm/utils/Pool.mjs.map +0 -1
  168. package/dist/esm/utils/Profiler.mjs.map +0 -1
  169. package/dist/esm/utils/Registry.mjs.map +0 -1
  170. package/dist/esm/utils/StructuredData.mjs.map +0 -1
  171. package/dist/esm/utils/TextAnalyzer.mjs.map +0 -1
@@ -1,5 +1,5 @@
1
1
  /**
2
- * CmpStr v3.2.0 build-6929b12-260122
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,19 +593,35 @@
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) {
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
- if (Normalizer.pipeline.has(flags)) return Normalizer.pipeline.get(flags);
568
- const { REGEX } = Normalizer;
569
- const steps = [
570
- ['d', (s) => s.normalize('NFD')],
571
- ['i', (s) => s.toLowerCase()],
572
- ['k', (s) => s.replace(REGEX.nonLetters, '')],
573
- ['n', (s) => s.replace(REGEX.nonNumbers, '')],
574
- ['r', (s) => s.replace(REGEX.doubleChars, '$1')],
575
- ['s', (s) => s.replace(REGEX.specialChars, '')],
576
- ['t', (s) => s.trim()],
577
- ['u', (s) => s.normalize('NFC')],
578
- ['w', (s) => s.replace(REGEX.whitespace, ' ')],
579
- ['x', (s) => s.normalize('NFKC')]
580
- ];
581
- const pipeline = steps
582
- .filter(([f]) => flags.includes(f))
583
- .map(([, fn]) => fn);
584
- const fn = (s) => pipeline.reduce((v, f) => f(v), s);
585
- Normalizer.pipeline.set(flags, fn);
586
- 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
+ );
587
730
  }
588
731
  static normalize(input, flags) {
589
- if (!flags || typeof flags !== 'string' || !input) return input;
590
- flags = this.canonicalFlags(flags);
591
- if (Array.isArray(input))
592
- return input.map((s) => Normalizer.normalize(s, flags));
593
- const key = Normalizer.cache.key(flags, [input]);
594
- if (key && Normalizer.cache.has(key)) return Normalizer.cache.get(key);
595
- const res = Normalizer.getPipeline(flags)(input);
596
- if (key) Normalizer.cache.set(key, res);
597
- 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
+ );
598
748
  }
599
749
  static async normalizeAsync(input, flags) {
600
- return await (Array.isArray(input)
601
- ? Promise.all(input.map((s) => Normalizer.normalize(s, flags)))
602
- : 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
+ );
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
- if (reg in registry || reg in factory)
693
- throw new Error(
694
- `Registry <${reg}> already exists / overwriting is forbidden`
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
- if (!(cls.prototype instanceof ctor))
700
- throw new TypeError(`Class must extend <${reg}>`);
701
- if (!update && name in classes)
702
- throw new Error(
703
- `Entry <${name}> already exists / use <update=true> to overwrite`
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
- if (!(name in classes))
718
- 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
+ );
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 ReferenceError(`Registry <${reg}> does not exist`);
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
- try {
734
- return new cls(...args);
735
- } catch (err) {
736
- throw new Error(`Cannot instantiate class <${cls.name ?? cls}>`, {
737
- cause: err
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
- const len = this.buffers.length;
751
- for (let i = 0; i < len; i++) {
752
- const idx = (this.pointer + i) & (len - 1);
753
- const item = this.buffers[idx];
754
- if (item.size >= minSize && (allowOversize || item.size === minSize)) {
755
- this.pointer = (idx + 1) & (len - 1);
756
- return item;
757
- }
758
- }
759
- 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
+ );
760
949
  }
761
950
  release(item) {
762
- if (this.buffers.length < this.maxSize)
763
- return void [this.buffers.push(item)];
764
- this.buffers[this.pointer] = item;
765
- 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
+ );
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
- 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)
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 TypeError(
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 this.finalizeLookup(fn(), extractedStrings, opt);
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 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
+ );
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
- if (this.a.length === 0 || this.b.length === 0)
1204
- 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
+ );
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 Error(`Method compute() must be overridden in a subclass`);
1428
+ throw new CmpStrInternalError(
1429
+ `Method compute() must be overridden in a subclass`
1430
+ );
1218
1431
  }
1219
1432
  runSingle(i, j) {
1220
- let a = String(this.a[i]),
1221
- A = a;
1222
- let b = String(this.b[j]),
1223
- B = b;
1224
- let m = A.length,
1225
- n = B.length;
1226
- let result = this.preCompute(A, B, m, n);
1227
- if (!result) {
1228
- result = profiler$2.run(() => {
1229
- if (this.symmetric) [A, B, m, n] = Metric.swap(A, B, m, n);
1230
- const key =
1231
- Metric.cache.key(this.metric, [A, B], this.symmetric) + this.optKey;
1232
- return (
1233
- Metric.cache.get(key || '') ??
1234
- (() => {
1235
- const res = this.compute(A, B, m, n, Math.max(m, n));
1236
- if (key) Metric.cache.set(key, res);
1237
- return res;
1238
- })()
1239
- );
1240
- });
1241
- }
1242
- return {
1243
- metric: this.metric,
1244
- a: this.origA[i] ?? a,
1245
- b: this.origB[j] ?? b,
1246
- ...result
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 Error(
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 Error(`Unsupported mode <${mode}>`);
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 Error(`Unsupported async mode <${mode}>`);
1558
+ throw new CmpStrInternalError(`Unsupported async mode <${mode}>`);
1338
1559
  }
1339
1560
  }
1340
1561
  getMetricName = () => this.metric;
1341
1562
  getResults() {
1342
- if (this.results === undefined)
1343
- throw new Error(`run() must be called before getResult()`);
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 Error(
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 Error(`No mapping specified for phonetic algorithm`);
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 Error(`Requested mapping <${mapId}> is not declared`);
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
- const index = [];
1851
- for (const word of words) {
1852
- const key = Phonetic.cache.key(this.algo, [word]) + this.optKey;
1853
- const code =
1854
- Phonetic.cache.get(key || '') ??
1855
- (() => {
1856
- const res = this.encode(word);
1857
- if (key) Phonetic.cache.set(key, res);
1858
- return res;
1859
- })();
1860
- if (code && code.length) index.push(this.equalLen(code));
1861
- }
1862
- 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
+ );
1863
2099
  }
1864
2100
  async loopAsync(words) {
1865
- const index = [];
1866
- for (const word of words) {
1867
- const key = Phonetic.cache.key(this.algo, [word]) + this.optKey;
1868
- const code = await Promise.resolve(
1869
- Phonetic.cache.get(key || '') ??
1870
- (() => {
1871
- const res = this.encode(word);
1872
- if (key) Phonetic.cache.set(key, res);
1873
- return res;
1874
- })()
1875
- );
1876
- if (code && code.length) index.push(this.equalLen(code));
1877
- }
1878
- 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
+ );
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
- if (!update && id in mappings)
1905
- throw new Error(
1906
- `Entry <${id}> already exists / use <update=true> to overwrite`
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 Error(
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 Error(
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 Error(`Cmpstr condition <${cond}> unknown`);
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
- const resolved = this.resolveOptions(opt);
2386
- this.assert('metric', resolved.metric);
2387
- const A = skip ? a : this.prepare(a, resolved);
2388
- const B = skip ? b : this.prepare(b, resolved);
2389
- if (
2390
- resolved.safeEmpty &&
2391
- ((Array.isArray(A) && A.length === 0) ||
2392
- (Array.isArray(B) && B.length === 0) ||
2393
- A === '' ||
2394
- B === '')
2395
- ) {
2396
- return [];
2397
- }
2398
- const metric = factory['metric'](resolved.metric, A, B, resolved.opt);
2399
- if (resolved.output !== 'prep') metric.setOriginal(a, b);
2400
- metric.run(mode);
2401
- const result = this.postProcess(metric.getResults(), resolved);
2402
- 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
+ );
2403
2655
  }
2404
2656
  output(result, raw) {
2405
- return (raw ?? this.options.raw)
2406
- ? result
2407
- : Array.isArray(result)
2408
- ? result.map((r) => ({ source: r.a, target: r.b, match: r.res }))
2409
- : { 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
+ );
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
- this.options = JSON.parse(opt);
2427
- 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
+ );
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
- const resolved = this.resolveOptions(opt);
2574
- this.assert('metric', resolved.metric);
2575
- const A = skip ? a : await this.prepareAsync(a, resolved);
2576
- const B = skip ? b : await this.prepareAsync(b, resolved);
2577
- if (
2578
- resolved.safeEmpty &&
2579
- ((Array.isArray(A) && A.length === 0) ||
2580
- (Array.isArray(B) && B.length === 0) ||
2581
- A === '' ||
2582
- B === '')
2583
- ) {
2584
- return [];
2585
- }
2586
- const metric = factory['metric'](resolved.metric, A, B, resolved.opt);
2587
- if (resolved.output !== 'prep') metric.setOriginal(a, b);
2588
- await metric.runAsync(mode);
2589
- const result = this.postProcess(metric.getResults(), resolved);
2590
- 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
+ );
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