cmpstr 2.0.2 → 3.0.0

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 (172) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +75 -499
  3. package/dist/CmpStr.esm.js +4863 -0
  4. package/dist/CmpStr.esm.js.map +1 -0
  5. package/dist/CmpStr.esm.min.js +8 -0
  6. package/dist/CmpStr.esm.min.js.map +1 -0
  7. package/dist/CmpStr.umd.js +4875 -0
  8. package/dist/CmpStr.umd.js.map +1 -0
  9. package/dist/CmpStr.umd.min.js +8 -0
  10. package/dist/CmpStr.umd.min.js.map +1 -0
  11. package/dist/cjs/CmpStr.js +663 -0
  12. package/dist/cjs/CmpStr.js.map +1 -0
  13. package/dist/cjs/CmpStrAsync.js +336 -0
  14. package/dist/cjs/CmpStrAsync.js.map +1 -0
  15. package/dist/cjs/index.js +15 -0
  16. package/dist/cjs/index.js.map +1 -0
  17. package/dist/cjs/metric/Cosine.js +101 -0
  18. package/dist/cjs/metric/Cosine.js.map +1 -0
  19. package/dist/cjs/metric/DamerauLevenshtein.js +110 -0
  20. package/dist/cjs/metric/DamerauLevenshtein.js.map +1 -0
  21. package/dist/cjs/metric/DiceSorensen.js +91 -0
  22. package/dist/cjs/metric/DiceSorensen.js.map +1 -0
  23. package/dist/cjs/metric/Hamming.js +82 -0
  24. package/dist/cjs/metric/Hamming.js.map +1 -0
  25. package/dist/cjs/metric/Jaccard.js +76 -0
  26. package/dist/cjs/metric/Jaccard.js.map +1 -0
  27. package/dist/cjs/metric/JaroWinkler.js +114 -0
  28. package/dist/cjs/metric/JaroWinkler.js.map +1 -0
  29. package/dist/cjs/metric/LCS.js +89 -0
  30. package/dist/cjs/metric/LCS.js.map +1 -0
  31. package/dist/cjs/metric/Levenshtein.js +94 -0
  32. package/dist/cjs/metric/Levenshtein.js.map +1 -0
  33. package/dist/cjs/metric/Metric.js +445 -0
  34. package/dist/cjs/metric/Metric.js.map +1 -0
  35. package/dist/cjs/metric/NeedlemanWunsch.js +95 -0
  36. package/dist/cjs/metric/NeedlemanWunsch.js.map +1 -0
  37. package/dist/cjs/metric/SmithWaterman.js +98 -0
  38. package/dist/cjs/metric/SmithWaterman.js.map +1 -0
  39. package/dist/cjs/metric/qGram.js +91 -0
  40. package/dist/cjs/metric/qGram.js.map +1 -0
  41. package/dist/cjs/phonetic/Cologne.js +112 -0
  42. package/dist/cjs/phonetic/Cologne.js.map +1 -0
  43. package/dist/cjs/phonetic/Metaphone.js +172 -0
  44. package/dist/cjs/phonetic/Metaphone.js.map +1 -0
  45. package/dist/cjs/phonetic/Phonetic.js +413 -0
  46. package/dist/cjs/phonetic/Phonetic.js.map +1 -0
  47. package/dist/cjs/phonetic/Soundex.js +135 -0
  48. package/dist/cjs/phonetic/Soundex.js.map +1 -0
  49. package/dist/cjs/utils/DeepMerge.js +144 -0
  50. package/dist/cjs/utils/DeepMerge.js.map +1 -0
  51. package/dist/cjs/utils/DiffChecker.js +500 -0
  52. package/dist/cjs/utils/DiffChecker.js.map +1 -0
  53. package/dist/cjs/utils/Filter.js +189 -0
  54. package/dist/cjs/utils/Filter.js.map +1 -0
  55. package/dist/cjs/utils/HashTable.js +175 -0
  56. package/dist/cjs/utils/HashTable.js.map +1 -0
  57. package/dist/cjs/utils/Normalizer.js +144 -0
  58. package/dist/cjs/utils/Normalizer.js.map +1 -0
  59. package/dist/cjs/utils/Pool.js +196 -0
  60. package/dist/cjs/utils/Pool.js.map +1 -0
  61. package/dist/cjs/utils/Profiler.js +229 -0
  62. package/dist/cjs/utils/Profiler.js.map +1 -0
  63. package/dist/cjs/utils/Registry.js +148 -0
  64. package/dist/cjs/utils/Registry.js.map +1 -0
  65. package/dist/cjs/utils/TextAnalyzer.js +358 -0
  66. package/dist/cjs/utils/TextAnalyzer.js.map +1 -0
  67. package/dist/esm/CmpStr.js +662 -0
  68. package/dist/esm/CmpStr.js.map +1 -0
  69. package/dist/esm/CmpStrAsync.js +331 -0
  70. package/dist/esm/CmpStrAsync.js.map +1 -0
  71. package/dist/esm/index.js +7 -0
  72. package/dist/esm/index.js.map +1 -0
  73. package/dist/esm/metric/Cosine.js +99 -0
  74. package/dist/esm/metric/Cosine.js.map +1 -0
  75. package/dist/esm/metric/DamerauLevenshtein.js +108 -0
  76. package/dist/esm/metric/DamerauLevenshtein.js.map +1 -0
  77. package/dist/esm/metric/DiceSorensen.js +89 -0
  78. package/dist/esm/metric/DiceSorensen.js.map +1 -0
  79. package/dist/esm/metric/Hamming.js +77 -0
  80. package/dist/esm/metric/Hamming.js.map +1 -0
  81. package/dist/esm/metric/Jaccard.js +74 -0
  82. package/dist/esm/metric/Jaccard.js.map +1 -0
  83. package/dist/esm/metric/JaroWinkler.js +112 -0
  84. package/dist/esm/metric/JaroWinkler.js.map +1 -0
  85. package/dist/esm/metric/LCS.js +87 -0
  86. package/dist/esm/metric/LCS.js.map +1 -0
  87. package/dist/esm/metric/Levenshtein.js +92 -0
  88. package/dist/esm/metric/Levenshtein.js.map +1 -0
  89. package/dist/esm/metric/Metric.js +442 -0
  90. package/dist/esm/metric/Metric.js.map +1 -0
  91. package/dist/esm/metric/NeedlemanWunsch.js +93 -0
  92. package/dist/esm/metric/NeedlemanWunsch.js.map +1 -0
  93. package/dist/esm/metric/SmithWaterman.js +96 -0
  94. package/dist/esm/metric/SmithWaterman.js.map +1 -0
  95. package/dist/esm/metric/qGram.js +89 -0
  96. package/dist/esm/metric/qGram.js.map +1 -0
  97. package/dist/esm/phonetic/Cologne.js +114 -0
  98. package/dist/esm/phonetic/Cologne.js.map +1 -0
  99. package/dist/esm/phonetic/Metaphone.js +174 -0
  100. package/dist/esm/phonetic/Metaphone.js.map +1 -0
  101. package/dist/esm/phonetic/Phonetic.js +409 -0
  102. package/dist/esm/phonetic/Phonetic.js.map +1 -0
  103. package/dist/esm/phonetic/Soundex.js +137 -0
  104. package/dist/esm/phonetic/Soundex.js.map +1 -0
  105. package/dist/esm/utils/DeepMerge.js +139 -0
  106. package/dist/esm/utils/DeepMerge.js.map +1 -0
  107. package/dist/esm/utils/DiffChecker.js +498 -0
  108. package/dist/esm/utils/DiffChecker.js.map +1 -0
  109. package/dist/esm/utils/Filter.js +187 -0
  110. package/dist/esm/utils/Filter.js.map +1 -0
  111. package/dist/esm/utils/HashTable.js +173 -0
  112. package/dist/esm/utils/HashTable.js.map +1 -0
  113. package/dist/esm/utils/Normalizer.js +142 -0
  114. package/dist/esm/utils/Normalizer.js.map +1 -0
  115. package/dist/esm/utils/Pool.js +194 -0
  116. package/dist/esm/utils/Pool.js.map +1 -0
  117. package/dist/esm/utils/Profiler.js +227 -0
  118. package/dist/esm/utils/Profiler.js.map +1 -0
  119. package/dist/esm/utils/Registry.js +142 -0
  120. package/dist/esm/utils/Registry.js.map +1 -0
  121. package/dist/esm/utils/TextAnalyzer.js +356 -0
  122. package/dist/esm/utils/TextAnalyzer.js.map +1 -0
  123. package/dist/types/CmpStr.d.ts +472 -0
  124. package/dist/types/CmpStrAsync.d.ts +233 -0
  125. package/dist/types/index.d.ts +51 -0
  126. package/dist/types/metric/Cosine.d.ts +57 -0
  127. package/dist/types/metric/DamerauLevenshtein.d.ts +50 -0
  128. package/dist/types/metric/DiceSorensen.d.ts +57 -0
  129. package/dist/types/metric/Hamming.d.ts +49 -0
  130. package/dist/types/metric/Jaccard.d.ts +48 -0
  131. package/dist/types/metric/JaroWinkler.d.ts +50 -0
  132. package/dist/types/metric/LCS.d.ts +50 -0
  133. package/dist/types/metric/Levenshtein.d.ts +50 -0
  134. package/dist/types/metric/Metric.d.ts +261 -0
  135. package/dist/types/metric/NeedlemanWunsch.d.ts +47 -0
  136. package/dist/types/metric/SmithWaterman.d.ts +48 -0
  137. package/dist/types/metric/index.d.ts +41 -0
  138. package/dist/types/metric/qGram.d.ts +56 -0
  139. package/dist/types/phonetic/Cologne.d.ts +46 -0
  140. package/dist/types/phonetic/Metaphone.d.ts +50 -0
  141. package/dist/types/phonetic/Phonetic.d.ts +189 -0
  142. package/dist/types/phonetic/Soundex.d.ts +49 -0
  143. package/dist/types/phonetic/index.d.ts +30 -0
  144. package/dist/types/utils/DeepMerge.d.ts +70 -0
  145. package/dist/types/utils/DiffChecker.d.ts +137 -0
  146. package/dist/types/utils/Filter.d.ts +97 -0
  147. package/dist/types/utils/HashTable.d.ts +86 -0
  148. package/dist/types/utils/Normalizer.d.ts +76 -0
  149. package/dist/types/utils/Pool.d.ts +63 -0
  150. package/dist/types/utils/Profiler.d.ts +129 -0
  151. package/dist/types/utils/Registry.d.ts +57 -0
  152. package/dist/types/utils/TextAnalyzer.d.ts +199 -0
  153. package/dist/types/utils/Types.d.ts +313 -0
  154. package/package.json +62 -49
  155. package/src/CmpStr.d.ts +0 -70
  156. package/src/CmpStr.js +0 -912
  157. package/src/CmpStrAsync.d.ts +0 -19
  158. package/src/CmpStrAsync.js +0 -204
  159. package/src/algorithms/cosine.js +0 -86
  160. package/src/algorithms/damerau.js +0 -78
  161. package/src/algorithms/dice.js +0 -65
  162. package/src/algorithms/hamming.js +0 -44
  163. package/src/algorithms/jaccard.js +0 -34
  164. package/src/algorithms/jaroWinkler.js +0 -106
  165. package/src/algorithms/lcs.js +0 -58
  166. package/src/algorithms/levenshtein.js +0 -70
  167. package/src/algorithms/needlemanWunsch.js +0 -72
  168. package/src/algorithms/qGram.js +0 -63
  169. package/src/algorithms/smithWaterman.js +0 -78
  170. package/src/algorithms/soundex.js +0 -152
  171. package/src/index.d.ts +0 -3
  172. package/src/index.js +0 -47
@@ -0,0 +1,662 @@
1
+ // CmpStr v3.0.0 dev-1a82e20-250612 by Paul Köhler @komed3 / MIT License
2
+ import { merge, set, rmv, get } from './utils/DeepMerge.js';
3
+ import { Profiler } from './utils/Profiler.js';
4
+ import { TextAnalyzer } from './utils/TextAnalyzer.js';
5
+ import { DiffChecker } from './utils/DiffChecker.js';
6
+ import { Normalizer } from './utils/Normalizer.js';
7
+ import { Filter } from './utils/Filter.js';
8
+ import { factory } from './utils/Registry.js';
9
+ import './metric/Cosine.js';
10
+ import './metric/DamerauLevenshtein.js';
11
+ import './metric/DiceSorensen.js';
12
+ import './metric/Hamming.js';
13
+ import './metric/Jaccard.js';
14
+ import './metric/JaroWinkler.js';
15
+ import './metric/LCS.js';
16
+ import './metric/Levenshtein.js';
17
+ import './metric/NeedlemanWunsch.js';
18
+ import './metric/qGram.js';
19
+ import './metric/SmithWaterman.js';
20
+ import { MetricRegistry, Metric } from './metric/Metric.js';
21
+ import './phonetic/Cologne.js';
22
+ import './phonetic/Metaphone.js';
23
+ import './phonetic/Soundex.js';
24
+ import {
25
+ PhoneticMappingRegistry,
26
+ PhoneticRegistry,
27
+ Phonetic
28
+ } from './phonetic/Phonetic.js';
29
+
30
+ /**
31
+ * CmpStr Main API
32
+ * src/CmpStr.ts
33
+ *
34
+ * The CmpStr class provides a comprehensive, highly abstracted, and type-safe interface
35
+ * for string comparison, similarity measurement, phonetic indexing, filtering, normalization,
36
+ * and text analysis. It unifies all core features of the CmpStr package and exposes a
37
+ * consistent, user-friendly API for both single and batch operations.
38
+ *
39
+ * Features:
40
+ * - Centralized management of metrics, phonetic algorithms, and filters
41
+ * - Flexible normalization and filtering pipeline for all inputs
42
+ * - Batch, pairwise, and single string comparison with detailed results
43
+ * - Phonetic indexing and phonetic-aware search and comparison
44
+ * - Text analysis and unified diff utilities
45
+ * - Full TypeScript type safety and extensibility
46
+ *
47
+ * @module CmpStr
48
+ * @author Paul Köhler (komed3)
49
+ * @license MIT
50
+ */
51
+ // Import the Profiler instance for global profiling
52
+ const profiler = Profiler.getInstance();
53
+ /**
54
+ * The main CmpStr class that provides a unified interface for string comparison,
55
+ * phonetic indexing, filtering, and text analysis.
56
+ *
57
+ * @template R - The type of the metric result, defaults to MetricRaw
58
+ */
59
+ class CmpStr {
60
+ /**
61
+ * --------------------------------------------------------------------------------
62
+ * Static methods and properties for global access to CmpStr features
63
+ * --------------------------------------------------------------------------------
64
+ *
65
+ * These static methods provide a convenient way to access the core features of
66
+ * the CmpStr package without needing to instantiate a CmpStr object.
67
+ */
68
+ /**
69
+ * Adds, removes, pauses, resumes, lists, or clears global filters.
70
+ *
71
+ * @see Filter
72
+ */
73
+ static filter = {
74
+ add: Filter.add,
75
+ remove: Filter.remove,
76
+ pause: Filter.pause,
77
+ resume: Filter.resume,
78
+ list: Filter.list,
79
+ clear: Filter.clear
80
+ };
81
+ /**
82
+ * Adds, removes, checks, or lists available metrics.
83
+ *
84
+ * @see MetricRegistry
85
+ */
86
+ static metric = {
87
+ add: MetricRegistry.add,
88
+ remove: MetricRegistry.remove,
89
+ has: MetricRegistry.has,
90
+ list: MetricRegistry.list
91
+ };
92
+ /**
93
+ * Adds, removes, checks, or lists available phonetic algorithms and mappings.
94
+ *
95
+ * @see PhoneticRegistry
96
+ */
97
+ static phonetic = {
98
+ add: PhoneticRegistry.add,
99
+ remove: PhoneticRegistry.remove,
100
+ has: PhoneticRegistry.has,
101
+ list: PhoneticRegistry.list,
102
+ map: {
103
+ add: PhoneticMappingRegistry.add,
104
+ remove: PhoneticMappingRegistry.remove,
105
+ has: PhoneticMappingRegistry.has,
106
+ list: PhoneticMappingRegistry.list
107
+ }
108
+ };
109
+ /**
110
+ * Provides access to the global profiler services.
111
+ *
112
+ * @see Profiler
113
+ */
114
+ static profiler = profiler.services;
115
+ /**
116
+ * Clears the caches for normalizer, metric, and phonetic modules.
117
+ */
118
+ static clearCache = {
119
+ normalizer: Normalizer.clear,
120
+ metric: Metric.clear,
121
+ phonetic: Phonetic.clear
122
+ };
123
+ /**
124
+ * Returns a TextAnalyzer instance for the given input string.
125
+ *
126
+ * @param {string} [input] - The input string
127
+ * @returns {TextAnalyzer} - The text analyzer
128
+ */
129
+ static analyze(input) {
130
+ return new TextAnalyzer(input);
131
+ }
132
+ /**
133
+ * Returns a DiffChecker instance for computing the unified diff between two texts.
134
+ *
135
+ * @param {string} a - The first (original) text
136
+ * @param {string} b - The second (modified) text
137
+ * @param {DiffOptions} [opt] - Optional diff configuration
138
+ * @returns {DiffChecker} - The diff checker instance
139
+ */
140
+ static diff(a, b, opt) {
141
+ return new DiffChecker(a, b, opt);
142
+ }
143
+ /**
144
+ * --------------------------------------------------------------------------------
145
+ * Instanciate the CmpStr class
146
+ * --------------------------------------------------------------------------------
147
+ *
148
+ * Methods to create a new CmpStr instance with the given options.
149
+ * Using the static `create` method is recommended to ensure proper instantiation.
150
+ */
151
+ /**
152
+ * Creates a new CmpStr instance with the given options.
153
+ *
154
+ * @param {string|CmpStrOptions} [opt] - Optional serialized or options object
155
+ * @returns {CmpStr<R>} - A new CmpStr instance
156
+ */
157
+ static create(opt) {
158
+ return new CmpStr(opt);
159
+ }
160
+ // The options object that holds the configuration for this CmpStr instance
161
+ options = Object.create(null);
162
+ /**
163
+ * Creates a new CmpStr instance with the given options.
164
+ * The constructor is protected to enforce the use of the static `create` method.
165
+ *
166
+ * @param {string|CmpStrOptions} [opt] - Optional serialized or options object
167
+ */
168
+ constructor(opt) {
169
+ if (opt)
170
+ typeof opt === 'string'
171
+ ? this.setSerializedOptions(opt)
172
+ : this.setOptions(opt);
173
+ }
174
+ /**
175
+ * ---------------------------------------------------------------------------------
176
+ * Protected utility methods for internal use
177
+ * ---------------------------------------------------------------------------------
178
+ *
179
+ * These methods provide utility functions for converting inputs, merging options,
180
+ * normalizing inputs, filtering, and preparing inputs for comparison.
181
+ */
182
+ /**
183
+ * Assert a condition and throws if the condition is not met.
184
+ *
185
+ * @param {string} cond - The condition to met
186
+ * @param {any} [test] - Value to test for
187
+ * @throws {Error} If the condition is not met
188
+ */
189
+ assert(cond, test) {
190
+ switch (cond) {
191
+ // Check if the metric exists
192
+ case 'metric':
193
+ if (!CmpStr.metric.has(test))
194
+ throw new Error(
195
+ `CmpStr <metric> must be set, call .setMetric(), ` +
196
+ `use CmpStr.metric.list() for available metrics`
197
+ );
198
+ break;
199
+ // Check if the phonetic algorithm exists
200
+ case 'phonetic':
201
+ if (!CmpStr.phonetic.has(test))
202
+ throw new Error(
203
+ `CmpStr <phonetic> must be set, call .setPhonetic(), ` +
204
+ `use CmpStr.phonetic.list() for available phonetic algorithms`
205
+ );
206
+ break;
207
+ // Throw an error for unknown conditions
208
+ default:
209
+ throw new Error(`Cmpstr condition <${cond}> unknown`);
210
+ }
211
+ }
212
+ /**
213
+ * Assert multiple conditions.
214
+ *
215
+ * @param {[ string, any? ][]} cond - Array of [ condition, value ] pairs
216
+ */
217
+ assertMany(...cond) {
218
+ for (const [c, test] of cond) this.assert(c, test);
219
+ }
220
+ /**
221
+ * Resolves the options for the CmpStr instance, merging the provided options with
222
+ * the existing options.
223
+ *
224
+ * @param {CmpStrOptions} [opt] - Optional options to merge
225
+ * @returns {CmpStrOptions} - The resolved options
226
+ */
227
+ resolveOptions(opt) {
228
+ return merge({ ...(this.options ?? Object.create(null)) }, opt);
229
+ }
230
+ /**
231
+ * Normalizes the input string or array using the configured or provided flags.
232
+ *
233
+ * @param {MetricInput} input - The input string or array
234
+ * @param {NormalizeFlags} [flags] - Normalization flags
235
+ * @returns {MetricInput} - The normalized input
236
+ */
237
+ normalize(input, flags) {
238
+ return Normalizer.normalize(input, flags ?? this.options.flags ?? '');
239
+ }
240
+ /**
241
+ * Applies all active filters to the input string or array.
242
+ *
243
+ * @param {MetricInput} input - The input string or array
244
+ * @param {string} [hook='input'] - The filter hook
245
+ * @returns {MetricInput} - The filtered string(s)
246
+ */
247
+ filter(input, hook) {
248
+ return Filter.apply(hook, input);
249
+ }
250
+ /**
251
+ * Prepares the input by normalizing and filtering.
252
+ *
253
+ * @param {MetricInput} [input] - The input string or array
254
+ * @param {CmpStrOptions} [opt] - Optional options to use
255
+ * @returns {MetricInput} - The prepared input
256
+ */
257
+ prepare(input, opt) {
258
+ const { flags, processors } = opt ?? this.options;
259
+ // Normalize the input using flags (i.e., 'itw')
260
+ if (flags?.length) input = this.normalize(input, flags);
261
+ // Filter the input using hooked up filters
262
+ input = this.filter(input, 'input');
263
+ // Apply phonetic processors if configured
264
+ if (processors?.phonetic) input = this.index(input, processors.phonetic);
265
+ return input;
266
+ }
267
+ /**
268
+ * Post-process the results of the metric computation.
269
+ *
270
+ * @param {MetricResult<R>} result - The metric result
271
+ * @returns {MetricResult<R>} - The post-processed results
272
+ */
273
+ postProcess(result, opt) {
274
+ // Remove "zero similarity" from batch results if configured
275
+ if (opt?.removeZero && Array.isArray(result))
276
+ result = result.filter((r) => r.res > 0);
277
+ return result;
278
+ }
279
+ /**
280
+ * Computes the phonetic index for the given input using the specified phonetic algorithm.
281
+ *
282
+ * @param {MetricInput} input - The input string or array
283
+ * @param {{ algo: string, opt?: PhoneticOptions }} options - The phonetic algorithm and options
284
+ * @returns {MetricInput} - The phonetic index for the given input
285
+ */
286
+ index(input, { algo, opt }) {
287
+ this.assert('phonetic', algo);
288
+ const phonetic = factory.phonetic(algo, opt);
289
+ const delimiter = opt?.delimiter ?? ' ';
290
+ return Array.isArray(input)
291
+ ? input.map((s) => phonetic.getIndex(s).join(delimiter))
292
+ : phonetic.getIndex(input).join(delimiter);
293
+ }
294
+ /**
295
+ * Computes the metric result for the given inputs, applying normalization and
296
+ * filtering as configured.
297
+ *
298
+ * @template T - The type of the metric result
299
+ * @param {MetricInput} a - The first input string or array
300
+ * @param {MetricInput} b - The second input string or array
301
+ * @param {CmpStrOptions} [opt] - Optional options to use
302
+ * @param {MetricMode} [mode='single'] - The metric mode to use
303
+ * @param {boolean} [raw=false] - Whether to return raw results
304
+ * @param {boolean} [skip=false] - Whether to skip normalization and filtering
305
+ * @returns {T} - The computed metric result
306
+ */
307
+ compute(a, b, opt, mode, raw, skip) {
308
+ const resolved = this.resolveOptions(opt);
309
+ this.assert('metric', resolved.metric);
310
+ // Prepare the input
311
+ const A = skip ? a : this.prepare(a, resolved);
312
+ const B = skip ? b : this.prepare(b, resolved);
313
+ // Get the metric class
314
+ const metric = factory.metric(resolved.metric, A, B, resolved.opt);
315
+ // Pass the original inputs to the metric
316
+ if (resolved.output !== 'prep') metric.setOriginal(a, b);
317
+ // Compute the metric result
318
+ metric.run(mode);
319
+ // Post-process the results
320
+ const result = this.postProcess(metric.getResults(), resolved);
321
+ // Resolve and return the result based on the raw flag
322
+ return this.output(result, raw ?? resolved.raw);
323
+ }
324
+ /**
325
+ * Resolves the result format (raw or formatted).
326
+ *
327
+ * @template T - The type of the metric result
328
+ * @param {MetricResult<R>} result - The metric result
329
+ * @param {boolean} [raw] - Whether to return raw results
330
+ * @returns {T} - The resolved result
331
+ */
332
+ output(result, raw) {
333
+ return (raw ?? this.options.raw)
334
+ ? result
335
+ : Array.isArray(result)
336
+ ? result.map((r) => ({ source: r.a, target: r.b, match: r.res }))
337
+ : { source: result.a, target: result.b, match: result.res };
338
+ }
339
+ /**
340
+ * ---------------------------------------------------------------------------------
341
+ * Managing methods for CmpStr
342
+ * ---------------------------------------------------------------------------------
343
+ *
344
+ * These methods provides an interface to set and get properties of the CmpStr
345
+ * instance, such as options, metric, phonetic algorithm, and more.
346
+ */
347
+ /**
348
+ * Creates a shallow clone of the current instance.
349
+ *
350
+ * @returns {CmpStr<R>} - The cloned instance
351
+ */
352
+ clone() {
353
+ return Object.assign(Object.create(Object.getPrototypeOf(this)), this);
354
+ }
355
+ /**
356
+ * Resets the instance, clearing all data and options.
357
+ *
358
+ * @returns {this}
359
+ */
360
+ reset() {
361
+ for (const k in this.options) delete this.options[k];
362
+ return this;
363
+ }
364
+ /**
365
+ * Sets / replaces the full options object.
366
+ *
367
+ * @param {CmpStrOptions} opt - The options
368
+ * @returns {this}
369
+ */
370
+ setOptions(opt) {
371
+ this.options = opt;
372
+ return this;
373
+ }
374
+ /**
375
+ * Deep merges and sets new options.
376
+ *
377
+ * @param {CmpStrOptions} opt - The options to merge
378
+ * @returns {this}
379
+ */
380
+ mergeOptions(opt) {
381
+ merge(this.options, opt);
382
+ return this;
383
+ }
384
+ /**
385
+ * Sets the serialized options from a JSON string.
386
+ *
387
+ * @param {string} opt - The serialized options
388
+ * @returns {this}
389
+ */
390
+ setSerializedOptions(opt) {
391
+ this.options = JSON.parse(opt);
392
+ return this;
393
+ }
394
+ /**
395
+ * Sets a specific option at the given path.
396
+ *
397
+ * @param {string} path - The path to the option
398
+ * @param {any} value - The value to set
399
+ * @returns {this}
400
+ */
401
+ setOption(path, value) {
402
+ set(this.options, path, value);
403
+ return this;
404
+ }
405
+ /**
406
+ * Removes an option at the given path.
407
+ *
408
+ * @param {string} path - The path to the option
409
+ * @returns {this}
410
+ */
411
+ rmvOption(path) {
412
+ rmv(this.options, path);
413
+ return this;
414
+ }
415
+ /**
416
+ * Enable or disable raw output.
417
+ *
418
+ * @param {boolean} enable - Whether to enable or disable raw output
419
+ * @returns {this}
420
+ */
421
+ setRaw(enable) {
422
+ return this.setOption('raw', enable);
423
+ }
424
+ /**
425
+ * Sets the similatity metric to use (e.g., 'levenshtein', 'dice').
426
+ *
427
+ * @param {string} name - The metric name
428
+ * @returns {this}
429
+ */
430
+ setMetric(name) {
431
+ return this.setOption('metric', name);
432
+ }
433
+ /**
434
+ * Sets the normalization flags (e.g., 'itw', 'nfc').
435
+ *
436
+ * @param {NormalizeFlags} flags - The normalization flags
437
+ * @returns {this}
438
+ */
439
+ setFlags(flags) {
440
+ return this.setOption('flags', flags);
441
+ }
442
+ /**
443
+ * Removes the normalization flags entirely.
444
+ *
445
+ * @return {this}
446
+ */
447
+ rmvFlags() {
448
+ return this.rmvOption('flags');
449
+ }
450
+ /**
451
+ * Sets the pre-processors to use for preparing the input.
452
+ *
453
+ * @param {CmpStrProcessors} opt - The processors to set
454
+ * @returns {this}
455
+ */
456
+ setProcessors(opt) {
457
+ return this.setOption('processors', opt);
458
+ }
459
+ /**
460
+ * Removes the processors entirely.
461
+ *
462
+ * @returns {this}
463
+ */
464
+ rmvProcessors() {
465
+ return this.rmvOption('processors');
466
+ }
467
+ /**
468
+ * Returns the current options object.
469
+ *
470
+ * @returns {CmpStrOptions} - The options
471
+ */
472
+ getOptions() {
473
+ return this.options;
474
+ }
475
+ /**
476
+ * Returns the options as a JSON string.
477
+ *
478
+ * @returns {string} - The serialized options
479
+ */
480
+ getSerializedOptions() {
481
+ return JSON.stringify(this.options);
482
+ }
483
+ /**
484
+ * Returns a specific option value by path.
485
+ *
486
+ * @param {string} path - The path to the option
487
+ * @returns {any} - The option value
488
+ */
489
+ getOption(path) {
490
+ return get(this.options, path);
491
+ }
492
+ /**
493
+ * ---------------------------------------------------------------------------------
494
+ * Public core methods for string comparison
495
+ * ---------------------------------------------------------------------------------
496
+ *
497
+ * These methods provide the core functionality of the CmpStr class, allowing for
498
+ * string comparison, phonetic indexing, filtering, and text search.
499
+ */
500
+ /**
501
+ * Performs a single metric comparison between the source and target.
502
+ *
503
+ * @template T - The type of the metric result
504
+ * @param {string} a - The source string
505
+ * @param {string} b - The target string
506
+ * @param {CmpStrOptions} [opt] - Optional options
507
+ * @returns {T} - The metric result
508
+ */
509
+ test(a, b, opt) {
510
+ return this.compute(a, b, opt, 'single');
511
+ }
512
+ /**
513
+ * Performs a single metric comparison and returns only the numeric score.
514
+ *
515
+ * @param {string} a - The source string
516
+ * @param {string} b - The target string
517
+ * @param {CmpStrOptions} [opt] - Optional options
518
+ * @returns {number} - The similarity score (0..1)
519
+ */
520
+ compare(a, b, opt) {
521
+ return this.compute(a, b, opt, 'single', true).res;
522
+ }
523
+ /**
524
+ * Performs a batch metric comparison between source and target strings
525
+ * or array of strings.
526
+ *
527
+ * @template T - The type of the metric result
528
+ * @param {MetricInput} a - The source string or array of strings
529
+ * @param {MetricInput} b - The target string or array of strings
530
+ * @param {CmpStrOptions} [opt] - Optional options
531
+ * @returns {T} - The batch metric results
532
+ */
533
+ batchTest(a, b, opt) {
534
+ return this.compute(a, b, opt, 'batch');
535
+ }
536
+ /**
537
+ * Performs a batch metric comparison and returns results sorted by score.
538
+ *
539
+ * @template T - The type of the metric result
540
+ * @param {MetricInput} a - The source string or array of strings
541
+ * @param {MetricInput} b - The target string or array of strings
542
+ * @param {'desc'|'asc'} [dir='desc'] - Sort direction (desc, asc)
543
+ * @param {CmpStrOptions} [opt] - Optional options
544
+ * @returns {T} - The sorted batch results
545
+ */
546
+ batchSorted(a, b, dir = 'desc', opt) {
547
+ return this.output(
548
+ this.compute(a, b, opt, 'batch', true).sort((a, b) =>
549
+ dir === 'asc' ? a.res - b.res : b.res - a.res
550
+ ),
551
+ opt?.raw ?? this.options.raw
552
+ );
553
+ }
554
+ /**
555
+ * Performs a pairwise metric comparison between source and target strings
556
+ * or array of strings.
557
+ *
558
+ * Input arrays needs of the same length to perform pairwise comparison,
559
+ * otherwise the method will throw an error.
560
+ *
561
+ * @template T - The type of the metric result
562
+ * @param {MetricInput} a - The source string or array of strings
563
+ * @param {MetricInput} b - The target string or array of strings
564
+ * @param {CmpStrOptions} [opt] - Optional options
565
+ * @returns {T} - The pairwise metric results
566
+ */
567
+ pairs(a, b, opt) {
568
+ return this.compute(a, b, opt, 'pairwise');
569
+ }
570
+ /**
571
+ * Performs a batch comparison and returns only results above the threshold.
572
+ *
573
+ * @template T - The type of the metric result
574
+ * @param {MetricInput} a - The source string or array of strings
575
+ * @param {MetricInput} b - The target string or array of strings
576
+ * @param {number} threshold - The similarity threshold (0..1)
577
+ * @param {CmpStrOptions} [opt] - Optional options
578
+ * @returns {T} - The filtered batch results
579
+ */
580
+ match(a, b, threshold, opt) {
581
+ return this.output(
582
+ this.compute(a, b, opt, 'batch', true)
583
+ .filter((r) => r.res >= threshold)
584
+ .sort((a, b) => b.res - a.res),
585
+ opt?.raw ?? this.options.raw
586
+ );
587
+ }
588
+ /**
589
+ * Returns the n closest matches from a batch comparison.
590
+ *
591
+ * @template T - The type of the metric result
592
+ * @param {MetricInput} a - The source string or array of strings
593
+ * @param {MetricInput} b - The target string or array of strings
594
+ * @param {number} [n=1] - Number of closest matches
595
+ * @param {CmpStrOptions} [opt] - Optional options
596
+ * @returns {T} - The closest matches
597
+ */
598
+ closest(a, b, n = 1, opt) {
599
+ return this.batchSorted(a, b, 'desc', opt).slice(0, n);
600
+ }
601
+ /**
602
+ * Returns the n furthest matches from a batch comparison.
603
+ *
604
+ * @template T - The type of the metric result
605
+ * @param {MetricInput} a - The source string or array of strings
606
+ * @param {MetricInput} b - The target string or array of strings
607
+ * @param {number} [n=1] - Number of furthest matches
608
+ * @param {CmpStrOptions} [opt] - Optional options
609
+ * @returns {T} - The furthest matches
610
+ */
611
+ furthest(a, b, n = 1, opt) {
612
+ return this.batchSorted(a, b, 'asc', opt).slice(0, n);
613
+ }
614
+ /**
615
+ * Performs a normalized and filtered substring search.
616
+ *
617
+ * @param {string} needle - The search string
618
+ * @param {string[]} haystack - The array to search in
619
+ * @param {NormalizeFlags} [flags] - Normalization flags
620
+ * @param {CmpStrProcessors} [processors] - Pre-processors to apply
621
+ * @returns {string[]} - Array of matching entries
622
+ */
623
+ search(needle, haystack, flags, processors) {
624
+ const resolved = this.resolveOptions({ flags, processors });
625
+ // Prepare the needle and haystack, normalizing and filtering them
626
+ const test = this.prepare(needle, resolved);
627
+ const hstk = this.prepare(haystack, resolved);
628
+ // Filter the haystack based on the normalized test string
629
+ return haystack.filter((_, i) => hstk[i].includes(test));
630
+ }
631
+ /**
632
+ * Computes a similarity matrix for the given input array.
633
+ *
634
+ * @param {string[]} input - The input array
635
+ * @param {CmpStrOptions} [opt] - Optional options
636
+ * @returns {number[][]} - The similarity matrix
637
+ */
638
+ matrix(input, opt) {
639
+ input = this.prepare(input, this.resolveOptions(opt));
640
+ return input.map((a) =>
641
+ this.compute(a, input, undefined, 'batch', true, true).map(
642
+ (b) => b.res ?? 0
643
+ )
644
+ );
645
+ }
646
+ /**
647
+ * Computes the phonetic index for a string using the configured
648
+ * or given algorithm.
649
+ *
650
+ * @param {string} [input] - The input string
651
+ * @param {string} [algo] - The phonetic algorithm to use
652
+ * @param {PhoneticOptions} [opt] - Optional phonetic options
653
+ * @returns {string} - The phonetic index as a string
654
+ */
655
+ phoneticIndex(input, algo, opt) {
656
+ const { algo: a, opt: o } = this.options.processors?.phonetic ?? {};
657
+ return this.index(input, { algo: algo ?? a, opt: opt ?? o });
658
+ }
659
+ }
660
+
661
+ export { CmpStr };
662
+ //# sourceMappingURL=CmpStr.js.map