cmpstr 3.2.2 → 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 (86) hide show
  1. package/dist/CmpStr.esm.js +2149 -1721
  2. package/dist/CmpStr.esm.min.js +2 -2
  3. package/dist/CmpStr.umd.js +2028 -1604
  4. package/dist/CmpStr.umd.min.js +2 -2
  5. package/dist/cjs/CmpStr.cjs +100 -51
  6. package/dist/cjs/CmpStrAsync.cjs +35 -18
  7. package/dist/cjs/index.cjs +1 -1
  8. package/dist/cjs/metric/Cosine.cjs +1 -1
  9. package/dist/cjs/metric/DamerauLevenshtein.cjs +1 -1
  10. package/dist/cjs/metric/DiceSorensen.cjs +1 -1
  11. package/dist/cjs/metric/Hamming.cjs +1 -1
  12. package/dist/cjs/metric/Jaccard.cjs +1 -1
  13. package/dist/cjs/metric/JaroWinkler.cjs +1 -1
  14. package/dist/cjs/metric/LCS.cjs +1 -1
  15. package/dist/cjs/metric/Levenshtein.cjs +1 -1
  16. package/dist/cjs/metric/Metric.cjs +40 -22
  17. package/dist/cjs/metric/NeedlemanWunsch.cjs +1 -1
  18. package/dist/cjs/metric/QGram.cjs +1 -1
  19. package/dist/cjs/metric/SmithWaterman.cjs +1 -1
  20. package/dist/cjs/phonetic/Caverphone.cjs +1 -1
  21. package/dist/cjs/phonetic/Cologne.cjs +1 -1
  22. package/dist/cjs/phonetic/Metaphone.cjs +1 -1
  23. package/dist/cjs/phonetic/Phonetic.cjs +27 -15
  24. package/dist/cjs/phonetic/Soundex.cjs +1 -1
  25. package/dist/cjs/root.cjs +4 -2
  26. package/dist/cjs/utils/DeepMerge.cjs +102 -97
  27. package/dist/cjs/utils/DiffChecker.cjs +1 -1
  28. package/dist/cjs/utils/Errors.cjs +22 -19
  29. package/dist/cjs/utils/Filter.cjs +59 -24
  30. package/dist/cjs/utils/HashTable.cjs +44 -29
  31. package/dist/cjs/utils/Normalizer.cjs +57 -28
  32. package/dist/cjs/utils/OptionsValidator.cjs +211 -0
  33. package/dist/cjs/utils/Pool.cjs +27 -13
  34. package/dist/cjs/utils/Profiler.cjs +41 -27
  35. package/dist/cjs/utils/Registry.cjs +5 -5
  36. package/dist/cjs/utils/StructuredData.cjs +83 -53
  37. package/dist/cjs/utils/TextAnalyzer.cjs +1 -1
  38. package/dist/esm/CmpStr.mjs +101 -52
  39. package/dist/esm/CmpStrAsync.mjs +35 -18
  40. package/dist/esm/index.mjs +1 -1
  41. package/dist/esm/metric/Cosine.mjs +1 -1
  42. package/dist/esm/metric/DamerauLevenshtein.mjs +1 -1
  43. package/dist/esm/metric/DiceSorensen.mjs +1 -1
  44. package/dist/esm/metric/Hamming.mjs +1 -1
  45. package/dist/esm/metric/Jaccard.mjs +1 -1
  46. package/dist/esm/metric/JaroWinkler.mjs +1 -1
  47. package/dist/esm/metric/LCS.mjs +1 -1
  48. package/dist/esm/metric/Levenshtein.mjs +1 -1
  49. package/dist/esm/metric/Metric.mjs +40 -22
  50. package/dist/esm/metric/NeedlemanWunsch.mjs +1 -1
  51. package/dist/esm/metric/QGram.mjs +1 -1
  52. package/dist/esm/metric/SmithWaterman.mjs +1 -1
  53. package/dist/esm/phonetic/Caverphone.mjs +1 -1
  54. package/dist/esm/phonetic/Cologne.mjs +1 -1
  55. package/dist/esm/phonetic/Metaphone.mjs +1 -1
  56. package/dist/esm/phonetic/Phonetic.mjs +30 -15
  57. package/dist/esm/phonetic/Soundex.mjs +1 -1
  58. package/dist/esm/root.mjs +3 -3
  59. package/dist/esm/utils/DeepMerge.mjs +103 -94
  60. package/dist/esm/utils/DiffChecker.mjs +1 -1
  61. package/dist/esm/utils/Errors.mjs +22 -19
  62. package/dist/esm/utils/Filter.mjs +59 -24
  63. package/dist/esm/utils/HashTable.mjs +44 -29
  64. package/dist/esm/utils/Normalizer.mjs +57 -28
  65. package/dist/esm/utils/OptionsValidator.mjs +210 -0
  66. package/dist/esm/utils/Pool.mjs +27 -13
  67. package/dist/esm/utils/Profiler.mjs +41 -27
  68. package/dist/esm/utils/Registry.mjs +5 -5
  69. package/dist/esm/utils/StructuredData.mjs +83 -53
  70. package/dist/esm/utils/TextAnalyzer.mjs +1 -1
  71. package/dist/types/CmpStr.d.ts +22 -15
  72. package/dist/types/CmpStrAsync.d.ts +3 -0
  73. package/dist/types/index.d.ts +3 -3
  74. package/dist/types/metric/Metric.d.ts +9 -9
  75. package/dist/types/phonetic/Phonetic.d.ts +4 -3
  76. package/dist/types/root.d.ts +3 -2
  77. package/dist/types/utils/DeepMerge.d.ts +80 -58
  78. package/dist/types/utils/Errors.d.ts +25 -8
  79. package/dist/types/utils/Filter.d.ts +4 -1
  80. package/dist/types/utils/HashTable.d.ts +12 -11
  81. package/dist/types/utils/Normalizer.d.ts +2 -1
  82. package/dist/types/utils/OptionsValidator.d.ts +193 -0
  83. package/dist/types/utils/Profiler.d.ts +9 -28
  84. package/dist/types/utils/StructuredData.d.ts +3 -0
  85. package/dist/types/utils/Types.d.ts +13 -1
  86. package/package.json +14 -5
@@ -1,4 +1,4 @@
1
- // CmpStr v3.2.2 build-bb61120-260311 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 Metric = require('./Metric.cjs');
@@ -1,4 +1,4 @@
1
- // CmpStr v3.2.2 build-bb61120-260311 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 Pool = require('../utils/Pool.cjs');
@@ -1,4 +1,4 @@
1
- // CmpStr v3.2.2 build-bb61120-260311 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 Pool = require('../utils/Pool.cjs');
@@ -1,4 +1,4 @@
1
- // CmpStr v3.2.2 build-bb61120-260311 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 Pool = require('../utils/Pool.cjs');
@@ -1,4 +1,4 @@
1
- // CmpStr v3.2.2 build-bb61120-260311 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 Pool = require('../utils/Pool.cjs');
@@ -1,4 +1,4 @@
1
- // CmpStr v3.2.2 build-bb61120-260311 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 Errors = require('../utils/Errors.cjs');
@@ -18,9 +18,15 @@ class Metric {
18
18
  optKey;
19
19
  symmetric;
20
20
  results;
21
- static clear = () => this.cache.clear();
22
- static swap = (a, b, m, n) => (m > n ? [b, a, n, m] : [a, b, m, n]);
23
- static clamp = (res) => Math.max(0, Math.min(1, res));
21
+ static clear() {
22
+ this.cache.clear();
23
+ }
24
+ static swap(a, b, m, n) {
25
+ return m > n ? [b, a, n, m] : [a, b, m, n];
26
+ }
27
+ static clamp(res) {
28
+ return Math.max(0, Math.min(1, res));
29
+ }
24
30
  constructor(metric, a, b, opt = {}, symmetric = false) {
25
31
  this.metric = metric;
26
32
  this.a = Array.isArray(a) ? a : [a];
@@ -59,13 +65,13 @@ class Metric {
59
65
  if (!result) {
60
66
  result = profiler.run(() => {
61
67
  if (this.symmetric) [A, B, m, n] = Metric.swap(A, B, m, n);
62
- const key =
63
- Metric.cache.key(this.metric, [A, B], this.symmetric) +
64
- this.optKey;
68
+ let key = Metric.cache.key(this.metric, [A, B], this.symmetric);
69
+ if (key) key += this.optKey;
65
70
  return (
66
71
  Metric.cache.get(key || '') ??
67
72
  (() => {
68
- const res = this.compute(A, B, m, n, Math.max(m, n));
73
+ const maxLen = m > n ? m : n;
74
+ const res = this.compute(A, B, m, n, maxLen);
69
75
  if (key) Metric.cache.set(key, res);
70
76
  return res;
71
77
  })()
@@ -74,8 +80,8 @@ class Metric {
74
80
  }
75
81
  return {
76
82
  metric: this.metric,
77
- a: this.origA[i] ?? a,
78
- b: this.origB[j] ?? b,
83
+ a: this.origA.length > i ? this.origA[i] : a,
84
+ b: this.origB.length > j ? this.origB[j] : b,
79
85
  ...result
80
86
  };
81
87
  },
@@ -94,11 +100,11 @@ class Metric {
94
100
  this.results = results;
95
101
  }
96
102
  async runBatchAsync() {
97
- const results = [];
103
+ const tasks = [];
98
104
  for (let i = 0; i < this.a.length; i++)
99
105
  for (let j = 0; j < this.b.length; j++)
100
- results.push(await this.runSingleAsync(i, j));
101
- this.results = results;
106
+ tasks.push(this.runSingleAsync(i, j));
107
+ this.results = await Promise.all(tasks);
102
108
  }
103
109
  runPairwise() {
104
110
  const results = [];
@@ -106,18 +112,22 @@ class Metric {
106
112
  this.results = results;
107
113
  }
108
114
  async runPairwiseAsync() {
109
- const results = [];
115
+ const tasks = [];
110
116
  for (let i = 0; i < this.a.length; i++)
111
- results.push(await this.runSingleAsync(i, i));
112
- this.results = results;
117
+ tasks.push(this.runSingleAsync(i, i));
118
+ this.results = await Promise.all(tasks);
113
119
  }
114
120
  setOriginal(a, b) {
115
121
  if (a) this.origA = Array.isArray(a) ? a : [a];
116
122
  if (b) this.origB = Array.isArray(b) ? b : [b];
117
123
  return this;
118
124
  }
119
- isBatch = () => this.a.length > 1 || this.b.length > 1;
120
- isSingle = () => !this.isBatch();
125
+ isBatch() {
126
+ return this.a.length > 1 || this.b.length > 1;
127
+ }
128
+ isSingle() {
129
+ return !this.isBatch();
130
+ }
121
131
  isPairwise(safe = false) {
122
132
  return this.isBatch() && this.a.length === this.b.length
123
133
  ? true
@@ -129,9 +139,15 @@ class Metric {
129
139
  );
130
140
  })();
131
141
  }
132
- isSymmetrical = () => this.symmetric;
133
- whichMode = (mode) => mode ?? this.options?.mode ?? 'default';
134
- clear = () => (this.results = undefined);
142
+ isSymmetrical() {
143
+ return this.symmetric;
144
+ }
145
+ whichMode(mode) {
146
+ return mode ?? this.options.mode ?? 'default';
147
+ }
148
+ clear() {
149
+ this.results = undefined;
150
+ }
135
151
  run(mode, clear = true) {
136
152
  if (clear) this.clear();
137
153
  switch (this.whichMode(mode)) {
@@ -176,7 +192,9 @@ class Metric {
176
192
  );
177
193
  }
178
194
  }
179
- getMetricName = () => this.metric;
195
+ getMetricName() {
196
+ return this.metric;
197
+ }
180
198
  getResults() {
181
199
  Errors.ErrorUtil.assert(
182
200
  this.results !== undefined,
@@ -1,4 +1,4 @@
1
- // CmpStr v3.2.2 build-bb61120-260311 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 Pool = require('../utils/Pool.cjs');
@@ -1,4 +1,4 @@
1
- // CmpStr v3.2.2 build-bb61120-260311 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 Pool = require('../utils/Pool.cjs');
@@ -1,4 +1,4 @@
1
- // CmpStr v3.2.2 build-bb61120-260311 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 Pool = require('../utils/Pool.cjs');
@@ -1,4 +1,4 @@
1
- // CmpStr v3.2.2 build-bb61120-260311 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');
@@ -1,4 +1,4 @@
1
- // CmpStr v3.2.2 build-bb61120-260311 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');
@@ -1,4 +1,4 @@
1
- // CmpStr v3.2.2 build-bb61120-260311 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');
@@ -1,4 +1,4 @@
1
- // CmpStr v3.2.2 build-bb61120-260311 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');
@@ -15,7 +15,10 @@ class Phonetic {
15
15
  options;
16
16
  optKey;
17
17
  map;
18
- static clear = () => this.cache.clear();
18
+ ignoreSet;
19
+ static clear() {
20
+ this.cache.clear();
21
+ }
19
22
  constructor(algo, opt = {}) {
20
23
  const defaults = this.constructor.default ?? {};
21
24
  const mapId = opt.map ?? defaults.map;
@@ -30,8 +33,8 @@ class Phonetic {
30
33
  `Requested mapping <${mapId}> is not declared`,
31
34
  { algo, mapId }
32
35
  );
33
- this.options = DeepMerge.merge(
34
- DeepMerge.merge(defaults, map.options ?? {}),
36
+ this.options = DeepMerge.DeepMerge.merge(
37
+ DeepMerge.DeepMerge.merge(defaults, map.options ?? {}),
35
38
  opt
36
39
  );
37
40
  this.optKey = HashTable.Hasher.fastFNV1a(
@@ -39,28 +42,32 @@ class Phonetic {
39
42
  ).toString();
40
43
  this.algo = algo;
41
44
  this.map = map;
45
+ this.ignoreSet = new Set(map.ignore ?? []);
42
46
  }
43
47
  applyPattern(word) {
44
48
  const { patterns = [] } = this.map;
45
- if (!patterns || !patterns.length) return word;
49
+ if (!patterns.length) return word;
46
50
  for (const { pattern, replace, all = false } of patterns) {
47
- word = word[all ? 'replaceAll' : 'replace'](pattern, replace);
51
+ word = all
52
+ ? word.replaceAll(pattern, replace)
53
+ : word.replace(pattern, replace);
48
54
  }
49
55
  return word;
50
56
  }
51
57
  applyRules(char, i, chars, charLen) {
52
58
  const { ruleset = [] } = this.map;
53
- if (!ruleset || !ruleset.length) return undefined;
59
+ if (!ruleset.length) return undefined;
54
60
  const prev = chars[i - 1] || '',
55
61
  prev2 = chars[i - 2] || '';
56
62
  const next = chars[i + 1] || '',
57
63
  next2 = chars[i + 2] || '';
64
+ const str = chars.join('');
58
65
  for (const rule of ruleset) {
59
66
  if (rule.char && rule.char !== char) continue;
60
67
  if (rule.position === 'start' && i !== 0) continue;
61
68
  if (rule.position === 'middle' && (i === 0 || i === charLen - 1))
62
69
  continue;
63
- if (rule.position === 'end' && i !== charLen) continue;
70
+ if (rule.position === 'end' && i !== charLen - 1) continue;
64
71
  if (rule.prev && !rule.prev.includes(prev)) continue;
65
72
  if (rule.prevNot && rule.prevNot.includes(prev)) continue;
66
73
  if (rule.prev2 && !rule.prev2.includes(prev2)) continue;
@@ -71,12 +78,12 @@ class Phonetic {
71
78
  if (rule.next2Not && rule.next2Not.includes(next2)) continue;
72
79
  if (
73
80
  rule.leading &&
74
- !rule.leading.includes(chars.slice(0, rule.leading.length).join(''))
81
+ !rule.leading.includes(str.slice(0, rule.leading.length))
75
82
  )
76
83
  continue;
77
84
  if (
78
85
  rule.trailing &&
79
- !rule.trailing.includes(chars.slice(-rule.trailing.length).join(''))
86
+ !rule.trailing.includes(str.slice(-rule.trailing.length))
80
87
  )
81
88
  continue;
82
89
  if (rule.match && !rule.match.every((c, j) => chars[i + j] === c))
@@ -86,7 +93,7 @@ class Phonetic {
86
93
  return undefined;
87
94
  }
88
95
  encode(word) {
89
- const { map = {}, ignore = [] } = this.map;
96
+ const { map = {} } = this.map;
90
97
  word = this.applyPattern(word);
91
98
  const chars = this.word2Chars(word);
92
99
  const charLen = chars.length;
@@ -94,7 +101,7 @@ class Phonetic {
94
101
  lastCode = null;
95
102
  for (let i = 0; i < charLen; i++) {
96
103
  const char = chars[i];
97
- if (ignore.includes(char)) continue;
104
+ if (this.ignoreSet.has(char)) continue;
98
105
  const mapped = this.mapChar(char, i, chars, charLen, lastCode, map);
99
106
  if (mapped === undefined) continue;
100
107
  ((code += mapped), (lastCode = mapped));
@@ -113,7 +120,9 @@ class Phonetic {
113
120
  ? input
114
121
  : (input + pad.repeat(length)).slice(0, length);
115
122
  }
116
- word2Chars = (word) => word.toLowerCase().split('');
123
+ word2Chars(word) {
124
+ return Array.from(word.toLowerCase());
125
+ }
117
126
  exitEarly(code, i) {
118
127
  const { length = -1 } = this.options;
119
128
  return length > 0 && code.length >= length;
@@ -126,7 +135,8 @@ class Phonetic {
126
135
  () => {
127
136
  const index = [];
128
137
  for (const word of words) {
129
- const key = Phonetic.cache.key(this.algo, [word]) + this.optKey;
138
+ let key = Phonetic.cache.key(this.algo, [word]);
139
+ if (key) key += this.optKey;
130
140
  const code =
131
141
  Phonetic.cache.get(key || '') ??
132
142
  (() => {
@@ -164,7 +174,9 @@ class Phonetic {
164
174
  { algo: this.algo, words }
165
175
  );
166
176
  }
167
- getAlgoName = () => this.algo;
177
+ getAlgoName() {
178
+ return this.algo;
179
+ }
168
180
  getIndex(input) {
169
181
  const { delimiter = ' ' } = this.options;
170
182
  return profiler.run(() =>
@@ -1,4 +1,4 @@
1
- // CmpStr v3.2.2 build-bb61120-260311 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');
package/dist/cjs/root.cjs CHANGED
@@ -1,4 +1,4 @@
1
- // CmpStr v3.2.2 build-bb61120-260311 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');
@@ -27,6 +27,7 @@ var DeepMerge = require('./utils/DeepMerge.cjs');
27
27
  var Errors = require('./utils/Errors.cjs');
28
28
  var Filter = require('./utils/Filter.cjs');
29
29
  var HashTable = require('./utils/HashTable.cjs');
30
+ var OptionsValidator = require('./utils/OptionsValidator.cjs');
30
31
  var Pool = require('./utils/Pool.cjs');
31
32
  var Profiler = require('./utils/Profiler.cjs');
32
33
  var StructuredData = require('./utils/StructuredData.cjs');
@@ -41,11 +42,12 @@ exports.MetricRegistry = Metric.MetricRegistry;
41
42
  exports.Phonetic = Phonetic.Phonetic;
42
43
  exports.PhoneticMappingRegistry = Phonetic.PhoneticMappingRegistry;
43
44
  exports.PhoneticRegistry = Phonetic.PhoneticRegistry;
44
- exports.DeepMerge = DeepMerge;
45
+ exports.DeepMerge = DeepMerge.DeepMerge;
45
46
  exports.CmpStrError = Errors;
46
47
  exports.Filter = Filter.Filter;
47
48
  exports.HashTable = HashTable.HashTable;
48
49
  exports.Hasher = HashTable.Hasher;
50
+ exports.OptionsValidator = OptionsValidator.OptionsValidator;
49
51
  exports.Pool = Pool.Pool;
50
52
  exports.Profiler = Profiler.Profiler;
51
53
  exports.StructuredData = StructuredData.StructuredData;
@@ -1,113 +1,118 @@
1
- // CmpStr v3.2.2 build-bb61120-260311 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 Errors = require('./Errors.cjs');
5
5
 
6
- const BRACKET_PATTERN = /\[(\d+)]/g;
7
- const PATH_CACHE = new Map();
8
- function parse(p) {
9
- let cached = PATH_CACHE.get(p);
10
- if (cached) return cached;
11
- const parsed = p
12
- .replace(BRACKET_PATTERN, '.$1')
13
- .split('.')
14
- .map((s) => {
15
- const n = Number(s);
16
- return Number.isInteger(n) && String(n) === s ? n : s;
17
- });
18
- PATH_CACHE.set(p, parsed);
19
- return parsed;
20
- }
21
- function get(t, path, fb) {
22
- let o = t;
23
- for (const k of parse(path)) {
24
- if (o == null || !(k in o)) return fb;
25
- o = o[k];
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 };
26
17
  }
27
- return o;
28
- }
29
- function has(t, path) {
30
- let o = t;
31
- for (const k of parse(path)) {
32
- if (o == null || !(k in o)) return false;
33
- 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;
34
31
  }
35
- return true;
36
- }
37
- function set(t, path, value) {
38
- if (path === '') return value;
39
- const keys = parse(path);
40
- if (t !== undefined && (typeof t !== 'object' || t === null))
41
- throw new Errors.CmpStrUsageError(
32
+ static has(t, path) {
33
+ return DeepMerge.walk(t, DeepMerge.parse(path)).exists;
34
+ }
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),
42
44
  `Cannot set property <${keys[0]}> of <${JSON.stringify(t)}>`,
43
45
  { path: keys[0], target: t }
44
46
  );
45
- const root = t ?? (typeof keys[0] === 'number' ? [] : Object.create(null));
46
- let cur = root;
47
- for (let i = 0; i < keys.length - 1; i++) {
48
- const k = keys[i];
49
- let n = cur[k];
50
- if (n != null && typeof n !== 'object')
51
- throw new Errors.CmpStrUsageError(
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',
52
54
  `Cannot set property <${keys[i + 1]}> of <${JSON.stringify(n)}>`,
53
55
  { path: keys.slice(0, i + 2), value: n }
54
56
  );
55
- if (n == null)
56
- n = cur[k] = typeof keys[i + 1] === 'number' ? [] : Object.create(null);
57
- cur = n;
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;
58
63
  }
59
- cur[keys[keys.length - 1]] = value;
60
- return root;
61
- }
62
- function merge(
63
- t = Object.create(null),
64
- o = Object.create(null),
65
- mergeUndefined = false
66
- ) {
67
- const target = t ?? Object.create(null);
68
- Object.keys(o).forEach((k) => {
69
- const val = o[k];
70
- if (!mergeUndefined && val === undefined) return;
71
- if (k === '__proto__' || k === 'constructor') return;
72
- if (val !== null && typeof val === 'object' && !Array.isArray(val)) {
73
- const existing = target[k];
74
- target[k] = merge(
75
- existing !== null &&
76
- typeof existing === 'object' &&
77
- !Array.isArray(existing)
78
- ? existing
79
- : Object.create(null),
80
- val,
81
- mergeUndefined
82
- );
83
- } else target[k] = val;
84
- });
85
- return target;
86
- }
87
- function rmv(t, path, preserveEmpty = false) {
88
- const keys = parse(path);
89
- const remove = (obj, i = 0) => {
90
- const key = keys[i];
91
- if (!obj || typeof obj !== 'object') return false;
92
- if (i === keys.length - 1) return delete obj[key];
93
- if (!remove(obj[key], i + 1)) return false;
94
- if (!preserveEmpty) {
95
- const val = obj[key];
96
- if (
97
- typeof val === 'object' &&
98
- ((Array.isArray(val) && val.every((v) => v == null)) ||
99
- (!Array.isArray(val) && Object.keys(val).length === 0))
100
- )
101
- delete obj[key];
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;
102
113
  }
103
- return true;
104
- };
105
- remove(t);
106
- return t;
114
+ return target;
115
+ }
107
116
  }
108
117
 
109
- exports.get = get;
110
- exports.has = has;
111
- exports.merge = merge;
112
- exports.rmv = rmv;
113
- exports.set = set;
118
+ exports.DeepMerge = DeepMerge;
@@ -1,4 +1,4 @@
1
- // CmpStr v3.2.2 build-bb61120-260311 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 {