cmpstr 3.2.1 → 3.3.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 (155) hide show
  1. package/README.md +24 -18
  2. package/dist/CmpStr.esm.js +1904 -1211
  3. package/dist/CmpStr.esm.min.js +2 -3
  4. package/dist/CmpStr.umd.js +1924 -1236
  5. package/dist/CmpStr.umd.min.js +2 -3
  6. package/dist/cjs/CmpStr.cjs +134 -64
  7. package/dist/cjs/CmpStrAsync.cjs +60 -37
  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 +90 -53
  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 +80 -48
  25. package/dist/cjs/phonetic/Soundex.cjs +1 -2
  26. package/dist/cjs/root.cjs +6 -3
  27. package/dist/cjs/utils/DeepMerge.cjs +109 -99
  28. package/dist/cjs/utils/DiffChecker.cjs +1 -2
  29. package/dist/cjs/utils/Errors.cjs +106 -0
  30. package/dist/cjs/utils/Filter.cjs +97 -37
  31. package/dist/cjs/utils/HashTable.cjs +44 -30
  32. package/dist/cjs/utils/Normalizer.cjs +84 -35
  33. package/dist/cjs/utils/OptionsValidator.cjs +211 -0
  34. package/dist/cjs/utils/Pool.cjs +57 -19
  35. package/dist/cjs/utils/Profiler.cjs +41 -28
  36. package/dist/cjs/utils/Registry.cjs +48 -24
  37. package/dist/cjs/utils/StructuredData.cjs +95 -57
  38. package/dist/cjs/utils/TextAnalyzer.cjs +1 -2
  39. package/dist/esm/CmpStr.mjs +133 -61
  40. package/dist/esm/CmpStrAsync.mjs +56 -33
  41. package/dist/esm/index.mjs +1 -2
  42. package/dist/esm/metric/Cosine.mjs +1 -2
  43. package/dist/esm/metric/DamerauLevenshtein.mjs +1 -2
  44. package/dist/esm/metric/DiceSorensen.mjs +1 -2
  45. package/dist/esm/metric/Hamming.mjs +5 -4
  46. package/dist/esm/metric/Jaccard.mjs +1 -2
  47. package/dist/esm/metric/JaroWinkler.mjs +1 -2
  48. package/dist/esm/metric/LCS.mjs +1 -2
  49. package/dist/esm/metric/Levenshtein.mjs +1 -2
  50. package/dist/esm/metric/Metric.mjs +92 -53
  51. package/dist/esm/metric/NeedlemanWunsch.mjs +1 -2
  52. package/dist/esm/metric/QGram.mjs +1 -2
  53. package/dist/esm/metric/SmithWaterman.mjs +1 -2
  54. package/dist/esm/phonetic/Caverphone.mjs +1 -2
  55. package/dist/esm/phonetic/Cologne.mjs +1 -2
  56. package/dist/esm/phonetic/Metaphone.mjs +1 -2
  57. package/dist/esm/phonetic/Phonetic.mjs +83 -48
  58. package/dist/esm/phonetic/Soundex.mjs +1 -2
  59. package/dist/esm/root.mjs +5 -4
  60. package/dist/esm/utils/DeepMerge.mjs +109 -95
  61. package/dist/esm/utils/DiffChecker.mjs +1 -2
  62. package/dist/esm/utils/Errors.mjs +106 -0
  63. package/dist/esm/utils/Filter.mjs +97 -37
  64. package/dist/esm/utils/HashTable.mjs +44 -30
  65. package/dist/esm/utils/Normalizer.mjs +84 -35
  66. package/dist/esm/utils/OptionsValidator.mjs +210 -0
  67. package/dist/esm/utils/Pool.mjs +53 -19
  68. package/dist/esm/utils/Profiler.mjs +41 -28
  69. package/dist/esm/utils/Registry.mjs +48 -24
  70. package/dist/esm/utils/StructuredData.mjs +95 -57
  71. package/dist/esm/utils/TextAnalyzer.mjs +1 -2
  72. package/dist/types/CmpStr.d.ts +25 -14
  73. package/dist/types/CmpStrAsync.d.ts +4 -0
  74. package/dist/types/index.d.ts +3 -2
  75. package/dist/types/metric/Metric.d.ts +15 -14
  76. package/dist/types/phonetic/Phonetic.d.ts +7 -4
  77. package/dist/types/root.d.ts +4 -2
  78. package/dist/types/utils/DeepMerge.d.ts +80 -58
  79. package/dist/types/utils/Errors.d.ts +154 -0
  80. package/dist/types/utils/Filter.d.ts +8 -1
  81. package/dist/types/utils/HashTable.d.ts +12 -11
  82. package/dist/types/utils/Normalizer.d.ts +5 -1
  83. package/dist/types/utils/OptionsValidator.d.ts +193 -0
  84. package/dist/types/utils/Pool.d.ts +2 -0
  85. package/dist/types/utils/Profiler.d.ts +9 -28
  86. package/dist/types/utils/Registry.d.ts +3 -3
  87. package/dist/types/utils/StructuredData.d.ts +6 -1
  88. package/dist/types/utils/Types.d.ts +39 -1
  89. package/package.json +20 -11
  90. package/dist/CmpStr.esm.js.map +0 -1
  91. package/dist/CmpStr.esm.min.js.map +0 -1
  92. package/dist/CmpStr.umd.js.map +0 -1
  93. package/dist/CmpStr.umd.min.js.map +0 -1
  94. package/dist/cjs/CmpStr.cjs.map +0 -1
  95. package/dist/cjs/CmpStrAsync.cjs.map +0 -1
  96. package/dist/cjs/index.cjs.map +0 -1
  97. package/dist/cjs/metric/Cosine.cjs.map +0 -1
  98. package/dist/cjs/metric/DamerauLevenshtein.cjs.map +0 -1
  99. package/dist/cjs/metric/DiceSorensen.cjs.map +0 -1
  100. package/dist/cjs/metric/Hamming.cjs.map +0 -1
  101. package/dist/cjs/metric/Jaccard.cjs.map +0 -1
  102. package/dist/cjs/metric/JaroWinkler.cjs.map +0 -1
  103. package/dist/cjs/metric/LCS.cjs.map +0 -1
  104. package/dist/cjs/metric/Levenshtein.cjs.map +0 -1
  105. package/dist/cjs/metric/Metric.cjs.map +0 -1
  106. package/dist/cjs/metric/NeedlemanWunsch.cjs.map +0 -1
  107. package/dist/cjs/metric/QGram.cjs.map +0 -1
  108. package/dist/cjs/metric/SmithWaterman.cjs.map +0 -1
  109. package/dist/cjs/phonetic/Caverphone.cjs.map +0 -1
  110. package/dist/cjs/phonetic/Cologne.cjs.map +0 -1
  111. package/dist/cjs/phonetic/Metaphone.cjs.map +0 -1
  112. package/dist/cjs/phonetic/Phonetic.cjs.map +0 -1
  113. package/dist/cjs/phonetic/Soundex.cjs.map +0 -1
  114. package/dist/cjs/root.cjs.map +0 -1
  115. package/dist/cjs/utils/DeepMerge.cjs.map +0 -1
  116. package/dist/cjs/utils/DiffChecker.cjs.map +0 -1
  117. package/dist/cjs/utils/Filter.cjs.map +0 -1
  118. package/dist/cjs/utils/HashTable.cjs.map +0 -1
  119. package/dist/cjs/utils/Normalizer.cjs.map +0 -1
  120. package/dist/cjs/utils/Pool.cjs.map +0 -1
  121. package/dist/cjs/utils/Profiler.cjs.map +0 -1
  122. package/dist/cjs/utils/Registry.cjs.map +0 -1
  123. package/dist/cjs/utils/StructuredData.cjs.map +0 -1
  124. package/dist/cjs/utils/TextAnalyzer.cjs.map +0 -1
  125. package/dist/esm/CmpStr.mjs.map +0 -1
  126. package/dist/esm/CmpStrAsync.mjs.map +0 -1
  127. package/dist/esm/index.mjs.map +0 -1
  128. package/dist/esm/metric/Cosine.mjs.map +0 -1
  129. package/dist/esm/metric/DamerauLevenshtein.mjs.map +0 -1
  130. package/dist/esm/metric/DiceSorensen.mjs.map +0 -1
  131. package/dist/esm/metric/Hamming.mjs.map +0 -1
  132. package/dist/esm/metric/Jaccard.mjs.map +0 -1
  133. package/dist/esm/metric/JaroWinkler.mjs.map +0 -1
  134. package/dist/esm/metric/LCS.mjs.map +0 -1
  135. package/dist/esm/metric/Levenshtein.mjs.map +0 -1
  136. package/dist/esm/metric/Metric.mjs.map +0 -1
  137. package/dist/esm/metric/NeedlemanWunsch.mjs.map +0 -1
  138. package/dist/esm/metric/QGram.mjs.map +0 -1
  139. package/dist/esm/metric/SmithWaterman.mjs.map +0 -1
  140. package/dist/esm/phonetic/Caverphone.mjs.map +0 -1
  141. package/dist/esm/phonetic/Cologne.mjs.map +0 -1
  142. package/dist/esm/phonetic/Metaphone.mjs.map +0 -1
  143. package/dist/esm/phonetic/Phonetic.mjs.map +0 -1
  144. package/dist/esm/phonetic/Soundex.mjs.map +0 -1
  145. package/dist/esm/root.mjs.map +0 -1
  146. package/dist/esm/utils/DeepMerge.mjs.map +0 -1
  147. package/dist/esm/utils/DiffChecker.mjs.map +0 -1
  148. package/dist/esm/utils/Filter.mjs.map +0 -1
  149. package/dist/esm/utils/HashTable.mjs.map +0 -1
  150. package/dist/esm/utils/Normalizer.mjs.map +0 -1
  151. package/dist/esm/utils/Pool.mjs.map +0 -1
  152. package/dist/esm/utils/Profiler.mjs.map +0 -1
  153. package/dist/esm/utils/Registry.mjs.map +0 -1
  154. package/dist/esm/utils/StructuredData.mjs.map +0 -1
  155. package/dist/esm/utils/TextAnalyzer.mjs.map +0 -1
@@ -1,7 +1,8 @@
1
- // CmpStr v3.2.1 build-3439ccb-260130 by Paul Köhler @komed3 / MIT License
1
+ // CmpStr v3.3.0 build-3699f85-260318 by Paul Köhler @komed3 / MIT License
2
2
  'use strict';
3
3
 
4
4
  var DeepMerge = require('../utils/DeepMerge.cjs');
5
+ var Errors = require('../utils/Errors.cjs');
5
6
  var HashTable = require('../utils/HashTable.cjs');
6
7
  var Profiler = require('../utils/Profiler.cjs');
7
8
  var Registry = require('../utils/Registry.cjs');
@@ -14,16 +15,26 @@ class Phonetic {
14
15
  options;
15
16
  optKey;
16
17
  map;
17
- static clear = () => this.cache.clear();
18
+ ignoreSet;
19
+ static clear() {
20
+ this.cache.clear();
21
+ }
18
22
  constructor(algo, opt = {}) {
19
23
  const defaults = this.constructor.default ?? {};
20
24
  const mapId = opt.map ?? defaults.map;
21
- if (!mapId) throw new Error(`No mapping specified for phonetic algorithm`);
25
+ if (!mapId)
26
+ throw new Errors.CmpStrNotFoundError(
27
+ `No mapping specified for phonetic algorithm`,
28
+ { algo }
29
+ );
22
30
  const map = PhoneticMappingRegistry.get(algo, mapId);
23
31
  if (map === undefined)
24
- throw new Error(`Requested mapping <${mapId}> is not declared`);
25
- this.options = DeepMerge.merge(
26
- DeepMerge.merge(defaults, map.options ?? {}),
32
+ throw new Errors.CmpStrNotFoundError(
33
+ `Requested mapping <${mapId}> is not declared`,
34
+ { algo, mapId }
35
+ );
36
+ this.options = DeepMerge.DeepMerge.merge(
37
+ DeepMerge.DeepMerge.merge(defaults, map.options ?? {}),
27
38
  opt
28
39
  );
29
40
  this.optKey = HashTable.Hasher.fastFNV1a(
@@ -31,28 +42,32 @@ class Phonetic {
31
42
  ).toString();
32
43
  this.algo = algo;
33
44
  this.map = map;
45
+ this.ignoreSet = new Set(map.ignore ?? []);
34
46
  }
35
47
  applyPattern(word) {
36
48
  const { patterns = [] } = this.map;
37
- if (!patterns || !patterns.length) return word;
49
+ if (!patterns.length) return word;
38
50
  for (const { pattern, replace, all = false } of patterns) {
39
- word = word[all ? 'replaceAll' : 'replace'](pattern, replace);
51
+ word = all
52
+ ? word.replaceAll(pattern, replace)
53
+ : word.replace(pattern, replace);
40
54
  }
41
55
  return word;
42
56
  }
43
57
  applyRules(char, i, chars, charLen) {
44
58
  const { ruleset = [] } = this.map;
45
- if (!ruleset || !ruleset.length) return undefined;
59
+ if (!ruleset.length) return undefined;
46
60
  const prev = chars[i - 1] || '',
47
61
  prev2 = chars[i - 2] || '';
48
62
  const next = chars[i + 1] || '',
49
63
  next2 = chars[i + 2] || '';
64
+ const str = chars.join('');
50
65
  for (const rule of ruleset) {
51
66
  if (rule.char && rule.char !== char) continue;
52
67
  if (rule.position === 'start' && i !== 0) continue;
53
68
  if (rule.position === 'middle' && (i === 0 || i === charLen - 1))
54
69
  continue;
55
- if (rule.position === 'end' && i !== charLen) continue;
70
+ if (rule.position === 'end' && i !== charLen - 1) continue;
56
71
  if (rule.prev && !rule.prev.includes(prev)) continue;
57
72
  if (rule.prevNot && rule.prevNot.includes(prev)) continue;
58
73
  if (rule.prev2 && !rule.prev2.includes(prev2)) continue;
@@ -63,12 +78,12 @@ class Phonetic {
63
78
  if (rule.next2Not && rule.next2Not.includes(next2)) continue;
64
79
  if (
65
80
  rule.leading &&
66
- !rule.leading.includes(chars.slice(0, rule.leading.length).join(''))
81
+ !rule.leading.includes(str.slice(0, rule.leading.length))
67
82
  )
68
83
  continue;
69
84
  if (
70
85
  rule.trailing &&
71
- !rule.trailing.includes(chars.slice(-rule.trailing.length).join(''))
86
+ !rule.trailing.includes(str.slice(-rule.trailing.length))
72
87
  )
73
88
  continue;
74
89
  if (rule.match && !rule.match.every((c, j) => chars[i + j] === c))
@@ -78,7 +93,7 @@ class Phonetic {
78
93
  return undefined;
79
94
  }
80
95
  encode(word) {
81
- const { map = {}, ignore = [] } = this.map;
96
+ const { map = {} } = this.map;
82
97
  word = this.applyPattern(word);
83
98
  const chars = this.word2Chars(word);
84
99
  const charLen = chars.length;
@@ -86,7 +101,7 @@ class Phonetic {
86
101
  lastCode = null;
87
102
  for (let i = 0; i < charLen; i++) {
88
103
  const char = chars[i];
89
- if (ignore.includes(char)) continue;
104
+ if (this.ignoreSet.has(char)) continue;
90
105
  const mapped = this.mapChar(char, i, chars, charLen, lastCode, map);
91
106
  if (mapped === undefined) continue;
92
107
  ((code += mapped), (lastCode = mapped));
@@ -105,7 +120,9 @@ class Phonetic {
105
120
  ? input
106
121
  : (input + pad.repeat(length)).slice(0, length);
107
122
  }
108
- word2Chars = (word) => word.toLowerCase().split('');
123
+ word2Chars(word) {
124
+ return Array.from(word.toLowerCase());
125
+ }
109
126
  exitEarly(code, i) {
110
127
  const { length = -1 } = this.options;
111
128
  return length > 0 && code.length >= length;
@@ -114,37 +131,52 @@ class Phonetic {
114
131
  return code;
115
132
  }
116
133
  loop(words) {
117
- const index = [];
118
- for (const word of words) {
119
- const key = Phonetic.cache.key(this.algo, [word]) + this.optKey;
120
- const code =
121
- Phonetic.cache.get(key || '') ??
122
- (() => {
123
- const res = this.encode(word);
124
- if (key) Phonetic.cache.set(key, res);
125
- return res;
126
- })();
127
- if (code && code.length) index.push(this.equalLen(code));
128
- }
129
- return index;
134
+ return Errors.ErrorUtil.wrap(
135
+ () => {
136
+ const index = [];
137
+ for (const word of words) {
138
+ let key = Phonetic.cache.key(this.algo, [word]);
139
+ if (key) key += this.optKey;
140
+ const code =
141
+ Phonetic.cache.get(key || '') ??
142
+ (() => {
143
+ const res = this.encode(word);
144
+ if (key) Phonetic.cache.set(key, res);
145
+ return res;
146
+ })();
147
+ if (code && code.length) index.push(this.equalLen(code));
148
+ }
149
+ return index;
150
+ },
151
+ `Failed to generate phonetic index`,
152
+ { algo: this.algo, words }
153
+ );
130
154
  }
131
155
  async loopAsync(words) {
132
- const index = [];
133
- for (const word of words) {
134
- const key = Phonetic.cache.key(this.algo, [word]) + this.optKey;
135
- const code = await Promise.resolve(
136
- Phonetic.cache.get(key || '') ??
137
- (() => {
138
- const res = this.encode(word);
139
- if (key) Phonetic.cache.set(key, res);
140
- return res;
141
- })()
142
- );
143
- if (code && code.length) index.push(this.equalLen(code));
144
- }
145
- return index;
156
+ return Errors.ErrorUtil.wrapAsync(
157
+ async () => {
158
+ const index = [];
159
+ for (const word of words) {
160
+ const key = Phonetic.cache.key(this.algo, [word]) + this.optKey;
161
+ const code = await Promise.resolve(
162
+ Phonetic.cache.get(key || '') ??
163
+ (() => {
164
+ const res = this.encode(word);
165
+ if (key) Phonetic.cache.set(key, res);
166
+ return res;
167
+ })()
168
+ );
169
+ if (code && code.length) index.push(this.equalLen(code));
170
+ }
171
+ return index;
172
+ },
173
+ `Failed to generate phonetic index asynchronously`,
174
+ { algo: this.algo, words }
175
+ );
176
+ }
177
+ getAlgoName() {
178
+ return this.algo;
146
179
  }
147
- getAlgoName = () => this.algo;
148
180
  getIndex(input) {
149
181
  const { delimiter = ' ' } = this.options;
150
182
  return profiler.run(() =>
@@ -167,10 +199,11 @@ const PhoneticMappingRegistry = (() => {
167
199
  return Object.freeze({
168
200
  add(algo, id, map, update = false) {
169
201
  const mappings = maps(algo);
170
- if (!update && id in mappings)
171
- throw new Error(
172
- `Entry <${id}> already exists / use <update=true> to overwrite`
173
- );
202
+ Errors.ErrorUtil.assert(
203
+ !(!id || id in mappings) || update,
204
+ `Entry <${id}> already exists / use <update=true> to overwrite`,
205
+ { algo, id }
206
+ );
174
207
  mappings[id] = map;
175
208
  },
176
209
  remove(algo, id) {
@@ -191,4 +224,3 @@ const PhoneticMappingRegistry = (() => {
191
224
  exports.Phonetic = Phonetic;
192
225
  exports.PhoneticMappingRegistry = PhoneticMappingRegistry;
193
226
  exports.PhoneticRegistry = PhoneticRegistry;
194
- //# sourceMappingURL=Phonetic.cjs.map
@@ -1,4 +1,4 @@
1
- // CmpStr v3.2.1 build-3439ccb-260130 by Paul Köhler @komed3 / MIT License
1
+ // CmpStr v3.3.0 build-3699f85-260318 by Paul Köhler @komed3 / MIT License
2
2
  'use strict';
3
3
 
4
4
  var Phonetic = require('./Phonetic.cjs');
@@ -86,4 +86,3 @@ Phonetic.PhoneticMappingRegistry.add('soundex', 'de', {
86
86
  });
87
87
 
88
88
  exports.Soundex = Soundex;
89
- //# sourceMappingURL=Soundex.cjs.map
package/dist/cjs/root.cjs CHANGED
@@ -1,4 +1,4 @@
1
- // CmpStr v3.2.1 build-3439ccb-260130 by Paul Köhler @komed3 / MIT License
1
+ // CmpStr v3.3.0 build-3699f85-260318 by Paul Köhler @komed3 / MIT License
2
2
  'use strict';
3
3
 
4
4
  var CmpStr = require('./CmpStr.cjs');
@@ -24,8 +24,10 @@ require('./phonetic/Metaphone.cjs');
24
24
  require('./phonetic/Soundex.cjs');
25
25
  var Phonetic = require('./phonetic/Phonetic.cjs');
26
26
  var DeepMerge = require('./utils/DeepMerge.cjs');
27
+ var Errors = require('./utils/Errors.cjs');
27
28
  var Filter = require('./utils/Filter.cjs');
28
29
  var HashTable = require('./utils/HashTable.cjs');
30
+ var OptionsValidator = require('./utils/OptionsValidator.cjs');
29
31
  var Pool = require('./utils/Pool.cjs');
30
32
  var Profiler = require('./utils/Profiler.cjs');
31
33
  var StructuredData = require('./utils/StructuredData.cjs');
@@ -40,11 +42,12 @@ exports.MetricRegistry = Metric.MetricRegistry;
40
42
  exports.Phonetic = Phonetic.Phonetic;
41
43
  exports.PhoneticMappingRegistry = Phonetic.PhoneticMappingRegistry;
42
44
  exports.PhoneticRegistry = Phonetic.PhoneticRegistry;
43
- exports.DeepMerge = DeepMerge;
45
+ exports.DeepMerge = DeepMerge.DeepMerge;
46
+ exports.CmpStrError = Errors;
44
47
  exports.Filter = Filter.Filter;
45
48
  exports.HashTable = HashTable.HashTable;
46
49
  exports.Hasher = HashTable.Hasher;
50
+ exports.OptionsValidator = OptionsValidator.OptionsValidator;
47
51
  exports.Pool = Pool.Pool;
48
52
  exports.Profiler = Profiler.Profiler;
49
53
  exports.StructuredData = StructuredData.StructuredData;
50
- //# sourceMappingURL=root.cjs.map
@@ -1,108 +1,118 @@
1
- // CmpStr v3.2.1 build-3439ccb-260130 by Paul Köhler @komed3 / MIT License
1
+ // CmpStr v3.3.0 build-3699f85-260318 by Paul Köhler @komed3 / MIT License
2
2
  'use strict';
3
3
 
4
- const BRACKET_PATTERN = /\[(\d+)]/g;
5
- const PATH_CACHE = new Map();
6
- function parse(p) {
7
- let cached = PATH_CACHE.get(p);
8
- if (cached) return cached;
9
- const parsed = p
10
- .replace(BRACKET_PATTERN, '.$1')
11
- .split('.')
12
- .map((s) => {
13
- const n = Number(s);
14
- return Number.isInteger(n) && String(n) === s ? n : s;
15
- });
16
- PATH_CACHE.set(p, parsed);
17
- return parsed;
18
- }
19
- function get(t, path, fb) {
20
- let o = t;
21
- for (const k of parse(path)) {
22
- if (o == null || !(k in o)) return fb;
23
- o = o[k];
4
+ var Errors = require('./Errors.cjs');
5
+
6
+ class DeepMerge {
7
+ static BRACKET_PATTERN = /\[(\d+)]/g;
8
+ static PATH_CACHE = new Map();
9
+ static walk(obj, keys) {
10
+ let o = obj;
11
+ for (let i = 0; i < keys.length; i++) {
12
+ const k = keys[i];
13
+ if (o == null || !(k in o)) return { exists: false };
14
+ o = o[k];
15
+ }
16
+ return { exists: true, value: o };
24
17
  }
25
- return o;
26
- }
27
- function has(t, path) {
28
- let o = t;
29
- for (const k of parse(path)) {
30
- if (o == null || !(k in o)) return false;
31
- o = o[k];
18
+ static parse(p) {
19
+ const cached = DeepMerge.PATH_CACHE.get(p);
20
+ if (cached) return cached;
21
+ const parsed = p
22
+ .replace(DeepMerge.BRACKET_PATTERN, '.$1')
23
+ .split('.')
24
+ .map((s) => {
25
+ const n = Number(s);
26
+ return Number.isInteger(n) && String(n) === s ? n : s;
27
+ });
28
+ if (DeepMerge.PATH_CACHE.size > 2000) DeepMerge.PATH_CACHE.clear();
29
+ DeepMerge.PATH_CACHE.set(p, parsed);
30
+ return parsed;
32
31
  }
33
- return true;
34
- }
35
- function set(t, path, value) {
36
- if (path === '') return value;
37
- const keys = parse(path);
38
- if (t !== undefined && (typeof t !== 'object' || t === null))
39
- throw Error(`Cannot set property <${keys[0]}> of <${JSON.stringify(t)}>`);
40
- const root = t ?? (typeof keys[0] === 'number' ? [] : Object.create(null));
41
- let cur = root;
42
- for (let i = 0; i < keys.length - 1; i++) {
43
- const k = keys[i];
44
- let n = cur[k];
45
- if (n != null && typeof n !== 'object')
46
- throw Error(
47
- `Cannot set property <${keys[i + 1]}> of <${JSON.stringify(n)}>`
48
- );
49
- if (n == null)
50
- n = cur[k] = typeof keys[i + 1] === 'number' ? [] : Object.create(null);
51
- cur = n;
32
+ static has(t, path) {
33
+ return DeepMerge.walk(t, DeepMerge.parse(path)).exists;
52
34
  }
53
- cur[keys[keys.length - 1]] = value;
54
- return root;
55
- }
56
- function merge(
57
- t = Object.create(null),
58
- o = Object.create(null),
59
- mergeUndefined = false
60
- ) {
61
- const target = t ?? Object.create(null);
62
- Object.keys(o).forEach((k) => {
63
- const val = o[k];
64
- if (!mergeUndefined && val === undefined) return;
65
- if (k === '__proto__' || k === 'constructor') return;
66
- if (val !== null && typeof val === 'object' && !Array.isArray(val)) {
67
- const existing = target[k];
68
- target[k] = merge(
69
- existing !== null &&
70
- typeof existing === 'object' &&
71
- !Array.isArray(existing)
72
- ? existing
73
- : Object.create(null),
74
- val,
75
- mergeUndefined
35
+ static get(t, path, fb) {
36
+ const r = DeepMerge.walk(t, DeepMerge.parse(path));
37
+ return r.exists ? r.value : fb;
38
+ }
39
+ static set(t, path, value) {
40
+ if (path === '') return value;
41
+ const keys = DeepMerge.parse(path);
42
+ Errors.ErrorUtil.assert(
43
+ t === undefined || (typeof t === 'object' && t !== null),
44
+ `Cannot set property <${keys[0]}> of <${JSON.stringify(t)}>`,
45
+ { path: keys[0], target: t }
46
+ );
47
+ const root = t ?? (typeof keys[0] === 'number' ? [] : Object.create(null));
48
+ let cur = root;
49
+ for (let i = 0; i < keys.length - 1; i++) {
50
+ const k = keys[i];
51
+ let n = cur[k];
52
+ Errors.ErrorUtil.assert(
53
+ n == null || typeof n === 'object',
54
+ `Cannot set property <${keys[i + 1]}> of <${JSON.stringify(n)}>`,
55
+ { path: keys.slice(0, i + 2), value: n }
76
56
  );
77
- } else target[k] = val;
78
- });
79
- return target;
80
- }
81
- function rmv(t, path, preserveEmpty = false) {
82
- const keys = parse(path);
83
- const remove = (obj, i = 0) => {
84
- const key = keys[i];
85
- if (!obj || typeof obj !== 'object') return false;
86
- if (i === keys.length - 1) return delete obj[key];
87
- if (!remove(obj[key], i + 1)) return false;
88
- if (!preserveEmpty) {
89
- const val = obj[key];
90
- if (
91
- typeof val === 'object' &&
92
- ((Array.isArray(val) && val.every((v) => v == null)) ||
93
- (!Array.isArray(val) && Object.keys(val).length === 0))
94
- )
95
- delete obj[key];
57
+ if (n == null)
58
+ n = cur[k] = typeof keys[i + 1] === 'number' ? [] : Object.create(null);
59
+ cur = n;
60
+ }
61
+ cur[keys[keys.length - 1]] = value;
62
+ return root;
63
+ }
64
+ static rmv(t, path, preserveEmpty = false) {
65
+ const keys = DeepMerge.parse(path);
66
+ const remove = (obj, i = 0) => {
67
+ const key = keys[i];
68
+ if (!obj || typeof obj !== 'object') return false;
69
+ if (i === keys.length - 1) return delete obj[key];
70
+ if (!remove(obj[key], i + 1)) return false;
71
+ if (!preserveEmpty) {
72
+ const val = obj[key];
73
+ let empty = true;
74
+ if (typeof val === 'object') {
75
+ if (Array.isArray(val))
76
+ for (let i = 0; i < val.length; i++) {
77
+ if (val[i] != null) {
78
+ empty = false;
79
+ break;
80
+ }
81
+ }
82
+ else empty = false;
83
+ }
84
+ if (empty) delete obj[key];
85
+ }
86
+ return true;
87
+ };
88
+ remove(t);
89
+ return t;
90
+ }
91
+ static merge(
92
+ t = Object.create(null),
93
+ o = Object.create(null),
94
+ mergeUndefined = false
95
+ ) {
96
+ const target = t ?? Object.create(null);
97
+ for (const k in o) {
98
+ const val = o[k];
99
+ if (!mergeUndefined && val === undefined) continue;
100
+ if (k === '__proto__' || k === 'constructor') continue;
101
+ if (val !== null && typeof val === 'object' && !Array.isArray(val)) {
102
+ const existing = target[k];
103
+ target[k] = DeepMerge.merge(
104
+ existing !== null &&
105
+ typeof existing === 'object' &&
106
+ !Array.isArray(existing)
107
+ ? existing
108
+ : Object.create(null),
109
+ val,
110
+ mergeUndefined
111
+ );
112
+ } else target[k] = val;
96
113
  }
97
- return true;
98
- };
99
- remove(t);
100
- return t;
114
+ return target;
115
+ }
101
116
  }
102
117
 
103
- exports.get = get;
104
- exports.has = has;
105
- exports.merge = merge;
106
- exports.rmv = rmv;
107
- exports.set = set;
108
- //# sourceMappingURL=DeepMerge.cjs.map
118
+ exports.DeepMerge = DeepMerge;
@@ -1,4 +1,4 @@
1
- // CmpStr v3.2.1 build-3439ccb-260130 by Paul Köhler @komed3 / MIT License
1
+ // CmpStr v3.3.0 build-3699f85-260318 by Paul Köhler @komed3 / MIT License
2
2
  'use strict';
3
3
 
4
4
  class DiffChecker {
@@ -297,4 +297,3 @@ class DiffChecker {
297
297
  }
298
298
 
299
299
  exports.DiffChecker = DiffChecker;
300
- //# sourceMappingURL=DiffChecker.cjs.map
@@ -0,0 +1,106 @@
1
+ // CmpStr v3.3.0 build-3699f85-260318 by Paul Köhler @komed3 / MIT License
2
+ 'use strict';
3
+
4
+ class CmpStrError extends Error {
5
+ code;
6
+ meta;
7
+ when = new Date().toISOString();
8
+ constructor(code, message, meta, cause) {
9
+ super(message, cause !== undefined ? { cause } : undefined);
10
+ this.name = this.constructor.name;
11
+ this.code = code;
12
+ this.meta = meta;
13
+ if (typeof Error.captureStackTrace === 'function') {
14
+ Error.captureStackTrace(this, this.constructor);
15
+ }
16
+ }
17
+ format(stack = false) {
18
+ const parts = [`${this.name} [${this.code}]`, this.message];
19
+ if (this.meta)
20
+ for (const _ in this.meta) {
21
+ parts.push(JSON.stringify(this.meta));
22
+ break;
23
+ }
24
+ return (
25
+ parts.join(' - ') +
26
+ (stack && this.stack ? `\nStack Trace:\n${this.stack}` : '')
27
+ );
28
+ }
29
+ toString() {
30
+ return this.format(false);
31
+ }
32
+ toJSON(stack = false) {
33
+ return {
34
+ name: this.name,
35
+ code: this.code,
36
+ message: this.message,
37
+ meta: this.meta,
38
+ when: this.when,
39
+ cause:
40
+ this.cause instanceof Error
41
+ ? {
42
+ name: this.cause.name,
43
+ message: this.cause.message,
44
+ stack: stack && this.cause.stack
45
+ }
46
+ : this.cause
47
+ };
48
+ }
49
+ }
50
+ class CmpStrValidationError extends CmpStrError {
51
+ constructor(message, meta, cause) {
52
+ super('E_VALIDATION', message, meta, cause);
53
+ }
54
+ }
55
+ class CmpStrNotFoundError extends CmpStrError {
56
+ constructor(message, meta, cause) {
57
+ super('E_NOT_FOUND', message, meta, cause);
58
+ }
59
+ }
60
+ class CmpStrUsageError extends CmpStrError {
61
+ constructor(message, meta, cause) {
62
+ super('E_USAGE', message, meta, cause);
63
+ }
64
+ }
65
+ class CmpStrInternalError extends CmpStrError {
66
+ constructor(message, meta, cause) {
67
+ super('E_INTERNAL', message, meta, cause);
68
+ }
69
+ }
70
+ class ErrorUtil {
71
+ static assert(condition, message, meta) {
72
+ if (!condition) throw new CmpStrUsageError(message, meta);
73
+ }
74
+ static rethrow(err, message, meta) {
75
+ if (err instanceof CmpStrError) throw err;
76
+ throw new CmpStrInternalError(message, meta, err);
77
+ }
78
+ static format(err) {
79
+ if (err instanceof CmpStrError) return err.toString();
80
+ if (err instanceof Error) return `${err.name}: ${err.message}`;
81
+ return String(err);
82
+ }
83
+ static wrap(fn, message, meta) {
84
+ try {
85
+ return fn();
86
+ } catch (err) {
87
+ if (err instanceof CmpStrError) throw err;
88
+ throw new CmpStrInternalError(message, meta, err);
89
+ }
90
+ }
91
+ static async wrapAsync(fn, message, meta) {
92
+ try {
93
+ return await fn();
94
+ } catch (err) {
95
+ if (err instanceof CmpStrError) throw err;
96
+ throw new CmpStrInternalError(message, meta, err);
97
+ }
98
+ }
99
+ }
100
+
101
+ exports.CmpStrError = CmpStrError;
102
+ exports.CmpStrInternalError = CmpStrInternalError;
103
+ exports.CmpStrNotFoundError = CmpStrNotFoundError;
104
+ exports.CmpStrUsageError = CmpStrUsageError;
105
+ exports.CmpStrValidationError = CmpStrValidationError;
106
+ exports.ErrorUtil = ErrorUtil;