esi-cap 1.7.32 → 1.7.34

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.
@@ -0,0 +1,474 @@
1
+ # esi-cap Utilities API Reference
2
+
3
+ > **Module:** `utils`
4
+ > **Purpose:** Core utility belt — date validation, XML parsing, JSON manipulation, array operations, and UUID generation/parsing.
5
+
6
+ ---
7
+
8
+ ## Table of Contents
9
+
10
+ - [Dependencies](#dependencies)
11
+ - [Exports](#exports)
12
+ - [Class: `date`](#class-date)
13
+ - [date.isValid(sDate)](#dateisvalidsdate)
14
+ - [Class: `xml`](#class-xml)
15
+ - [xml.isValid(oXML)](#xmlisvalidoxml)
16
+ - [Class: `json`](#class-json)
17
+ - [json.isValid(oJson)](#jsonisvalidojson)
18
+ - [json.copy(oJson)](#jsoncopyojson)
19
+ - [json.replace(oJson, sOldValue, sNewValue, oEvaluate?)](#jsonreplaceojson-soldvalue-snewvalue-oevaluate)
20
+ - [json.getValue(oJson, sPropertyPath)](#jsongetvalueojson-spropertypath)
21
+ - [json.unique(oNestedArray)](#jsonuniqueonnestedarray)
22
+ - [json.order(oJson, oKeyOrder)](#jsonorderojson-okeyorder)
23
+ - [json.projection(oJson, oColumns, bHasAssociattion?)](#jsonprojectionojson-ocolumns-bhasassociattion)
24
+ - [json.map(oJson, oMap)](#jsonmapojson-omap)
25
+ - [json.merge(oJson1, oJson2)](#jsonmergeojson1-ojson2)
26
+ - [json.flat(oJson, sFlattenedProperty)](#jsonflatojson-sflattenedproperty)
27
+ - [json.stripUndefined(oSourceJson)](#jsonstripundefinedosourcejson)
28
+ - [Class: `array`](#class-array)
29
+ - [array.add(oArray, oItem)](#arrayaddoarray-oitem)
30
+ - [array.topN(oSortedArray, iTop)](#arraytopnosortedarray-itop)
31
+ - [array.flat(oArray, sFlattenedProperty)](#arrayflatoarray-sflattenedproperty)
32
+ - [array.unique(oArray)](#arrayuniqueoarray)
33
+ - [array.order(oArray, oOrder)](#arrayorderoarray-oorder)
34
+ - [array.projection(oArray, oColumns, bHasAssociattion?)](#arrayprojectionoarray-ocolumns-bhasassociattion)
35
+ - [array.map(oArray, oMap)](#arraymapoarray-omap)
36
+ - [array.sort(oArray, oOrderBy)](#arraysortoarray-oorderby)
37
+ - [array.filter(oArray, oFilterCondition)](#arrayfilteroarray-ofiltercondition)
38
+ - [array.hasElement(oArray, oElement)](#arrayhaselementoarray-oelement)
39
+ - [array.toArray(oArray)](#arraytoarrayoarray)
40
+ - [array.toDisArray(oArray)](#arraytodisarrayoarray)
41
+ - [array.toInterleavedArray(oArray, oElement)](#arraytointerleavedarray-oarray-oelement)
42
+ - [array.toArrayProjection(oArray, sProjectionFieldName)](#arraytoarrayprojectionoarray-sprojectionfieldname)
43
+ - [array.findProperty(oArray, sProjectionFieldName)](#arrayfindpropertyoarray-sprojectionfieldname)
44
+ - [array.toGroupByPropertyName(oArray, sPropertyName)](#arraytogroupbypropertynameoarray-spropertyname)
45
+ - [array.toGroupByPropertyList(oArray, oPropertyList)](#arraytogroupbypropertylistoarray-opropertylist)
46
+ - [Class: `UUID`](#class-uuid)
47
+ - [constructor()](#constructor)
48
+ - [converse(oJsonData)](#converseoJsondata)
49
+ - [inverse(sUUID)](#inversesuuid)
50
+
51
+ ---
52
+
53
+ ## Dependencies
54
+
55
+ | Package | Purpose |
56
+ |----------|-------------------------------------------------|
57
+ | `xml2js` | XML string parsing and validation |
58
+ | `uuid` | UUID format validation |
59
+ | `lodash` | Deep merge, orderBy, uniqWith, and isEqual |
60
+
61
+ ---
62
+
63
+ ## Exports
64
+
65
+ ```js
66
+ module.exports = { date, xml, json, array, UUID };
67
+ ```
68
+
69
+ ---
70
+
71
+ ## Class: `date`
72
+
73
+ Date-related validation helpers. All methods are `static`.
74
+
75
+ ### `date.isValid(sDate)`
76
+
77
+ | Parameter | Type | Description |
78
+ |-----------|----------|--------------------------------------|
79
+ | `sDate` | `string` | Date string to validate |
80
+ | **Returns** | `Promise<boolean>` | `true` if valid date |
81
+
82
+ **Behavior:** Parses the string via `new Date()` and verifies the result is a real Date (not `NaN`). Logs errors via the framework logger.
83
+
84
+ ```js
85
+ await date.isValid("2026-04-20"); // true
86
+ await date.isValid("not-a-date"); // false
87
+ ```
88
+
89
+ ---
90
+
91
+ ## Class: `xml`
92
+
93
+ XML parsing and validation helpers. All methods are `static`.
94
+
95
+ ### `xml.isValid(oXML)`
96
+
97
+ | Parameter | Type | Description |
98
+ |-----------|------------------|-----------------------------|
99
+ | `oXML` | `string\|object` | XML content to validate |
100
+ | **Returns** | `Promise<boolean>` | `true` if well-formed XML |
101
+
102
+ **Behavior:** Uses `xml2js.Parser.parseStringPromise` to attempt parsing. Logs the parsed result on success and errors on failure.
103
+
104
+ ```js
105
+ await xml.isValid("<root><item>val</item></root>"); // true
106
+ await xml.isValid("not xml"); // false
107
+ ```
108
+
109
+ ---
110
+
111
+ ## Class: `json`
112
+
113
+ Comprehensive JSON/object manipulation utilities. All methods are `static`.
114
+
115
+ ### `json.isValid(oJson)`
116
+
117
+ Checks if the input can be parsed as JSON via `JSON.parse`.
118
+
119
+ | Parameter | Type | Returns |
120
+ |-----------|------------------|------------|
121
+ | `oJson` | `string\|object` | `boolean` |
122
+
123
+ ---
124
+
125
+ ### `json.copy(oJson)`
126
+
127
+ Creates a deep clone using `structuredClone`. Falls back to returning the original reference if the input isn't valid JSON.
128
+
129
+ | Parameter | Type | Returns |
130
+ |-----------|----------|----------|
131
+ | `oJson` | `object` | `object` |
132
+
133
+ ---
134
+
135
+ ### `json.replace(oJson, sOldValue, sNewValue, oEvaluate?)`
136
+
137
+ Recursively walks objects and arrays, replacing all string occurrences of `sOldValue` with `sNewValue`. **Mutates the input in place.**
138
+
139
+ | Parameter | Type | Default | Description |
140
+ |-------------|----------|-------------|----------------------------------------------------------|
141
+ | `oJson` | `object\|Array` | — | Target structure |
142
+ | `sOldValue` | `string` | — | Substring to find |
143
+ | `sNewValue` | `string` | — | Replacement substring |
144
+ | `oEvaluate` | `object` | `undefined` | Optional context; when set, resolved string is evaluated as a property path via `json.getValue` |
145
+
146
+ ```js
147
+ const data = { msg: "Hello {{name}}", nested: { msg: "Hi {{name}}" } };
148
+ json.replace(data, "{{name}}", "World");
149
+ // data → { msg: "Hello World", nested: { msg: "Hi World" } }
150
+ ```
151
+
152
+ ---
153
+
154
+ ### `json.getValue(oJson, sPropertyPath)`
155
+
156
+ Resolves a dot-separated property path to its value.
157
+
158
+ | Parameter | Type | Returns |
159
+ |-----------------|----------|---------|
160
+ | `oJson` | `object` | `*` |
161
+ | `sPropertyPath` | `string` | Value or `undefined` |
162
+
163
+ ```js
164
+ json.getValue({ a: { b: { c: 42 } } }, "a.b.c"); // 42
165
+ json.getValue({ a: 1 }, "x.y"); // undefined
166
+ ```
167
+
168
+ ---
169
+
170
+ ### `json.unique(oNestedArray)`
171
+
172
+ Flattens a nested array and removes duplicates using JSON serialization for deep equality.
173
+
174
+ | Parameter | Type | Returns |
175
+ |----------------|---------|---------|
176
+ | `oNestedArray` | `any[]` | `any[]` |
177
+
178
+ ---
179
+
180
+ ### `json.order(oJson, oKeyOrder)`
181
+
182
+ Returns a new object with keys reordered: specified keys first, then the rest.
183
+
184
+ | Parameter | Type | Returns |
185
+ |------------|------------|----------|
186
+ | `oJson` | `object` | `object` |
187
+ | `oKeyOrder` | `string[]` | — |
188
+
189
+ ```js
190
+ json.order({ c: 3, a: 1, b: 2 }, ["a", "b"]); // { a: 1, b: 2, c: 3 }
191
+ ```
192
+
193
+ ---
194
+
195
+ ### `json.projection(oJson, oColumns, bHasAssociattion?)`
196
+
197
+ Filters an object to include only the specified properties.
198
+
199
+ | Parameter | Type | Default | Description |
200
+ |-------------------|------------|---------|----------------------------------------------|
201
+ | `oJson` | `object` | — | Source object |
202
+ | `oColumns` | `string[]` | — | Property names to keep |
203
+ | `bHasAssociattion` | `boolean` | `false` | Also include keys prefixed with column names |
204
+
205
+ ---
206
+
207
+ ### `json.map(oJson, oMap)`
208
+
209
+ Creates a new object by mapping source properties via a definition object.
210
+
211
+ | Parameter | Type | Description |
212
+ |-----------|----------|-------------------------------------------------------|
213
+ | `oJson` | `object` | Source data |
214
+ | `oMap` | `object` | `{ targetKey: "source.path" }` mapping definition |
215
+
216
+ ```js
217
+ json.map({ user: { name: "John" } }, { fullName: "user.name" }); // { fullName: "John" }
218
+ ```
219
+
220
+ ---
221
+
222
+ ### `json.merge(oJson1, oJson2)`
223
+
224
+ Deep-merges two objects using Lodash `_.merge`. Returns `{}` if either argument is not an object.
225
+
226
+ ---
227
+
228
+ ### `json.flat(oJson, sFlattenedProperty)`
229
+
230
+ Promotes a nested property's contents to the top level of the object.
231
+
232
+ ```js
233
+ json.flat({ id: 1, details: { name: "A", desc: "B" } }, "details");
234
+ // { id: 1, name: "A", desc: "B" }
235
+ ```
236
+
237
+ ---
238
+
239
+ ### `json.stripUndefined(oSourceJson)`
240
+
241
+ Removes properties where the value is `undefined`, `null`, or an empty string.
242
+
243
+ ---
244
+
245
+ ## Class: `array`
246
+
247
+ Array operations with automatic fallback to the `json` class for single-object inputs. All methods are `static`.
248
+
249
+ ### `array.add(oArray, oItem)`
250
+
251
+ Appends item(s) to an array. Accepts single values or arrays.
252
+
253
+ ---
254
+
255
+ ### `array.topN(oSortedArray, iTop)`
256
+
257
+ Returns the first `iTop` elements via `Array.slice`.
258
+
259
+ ---
260
+
261
+ ### `array.flat(oArray, sFlattenedProperty)`
262
+
263
+ Flattens a nested property for each element. Delegates to `json.flat` for single objects.
264
+
265
+ ---
266
+
267
+ ### `array.unique(oArray)`
268
+
269
+ Deduplicates using Lodash `_.uniqWith` with `_.isEqual` for deep comparison.
270
+
271
+ ---
272
+
273
+ ### `array.order(oArray, oOrder)`
274
+
275
+ Reorders keys for every object in the array per the specified key order.
276
+
277
+ ---
278
+
279
+ ### `array.projection(oArray, oColumns, bHasAssociattion?)`
280
+
281
+ Projects each element to only contain the listed columns.
282
+
283
+ ---
284
+
285
+ ### `array.map(oArray, oMap)`
286
+
287
+ Applies a property mapping to every element in the array.
288
+
289
+ ---
290
+
291
+ ### `array.sort(oArray, oOrderBy)`
292
+
293
+ Multi-column sort with type coercion support.
294
+
295
+ | `oOrderBy` entry | Property | Type | Description |
296
+ |---|---|---|---|
297
+ | `ref` | `string[]` | Required | Column path |
298
+ | `sort` | `'asc'\|'desc'` | Optional (default `'asc'`) | Sort direction |
299
+ | `function` | `'Date'\|'parseFloat'` | Optional | Value coercion |
300
+
301
+ ```js
302
+ array.sort(items, [
303
+ { ref: ["date"], sort: "desc", function: "Date" },
304
+ { ref: ["price"], sort: "asc", function: "parseFloat" }
305
+ ]);
306
+ ```
307
+
308
+ ---
309
+
310
+ ### `array.filter(oArray, oFilterCondition)`
311
+
312
+ Filters array elements based on a list of filter conditions (AND logic).
313
+
314
+ **FilterCondition:**
315
+ | Property | Type | Description |
316
+ |---|---|---|
317
+ | `name` | `string` | Property name to filter by |
318
+ | `op` | `'='\|'!='\|'>'\|'<'\|'>='\|'<='` | Comparison operator |
319
+ | `value` | `string\|number\|boolean` | Value to compare against |
320
+
321
+ ```js
322
+ array.filter(employees, [
323
+ { name: "age", op: ">=", value: 30 },
324
+ { name: "dept", op: "=", value: "Engineering" }
325
+ ]);
326
+ ```
327
+
328
+ ---
329
+
330
+ ### `array.hasElement(oArray, oElement)`
331
+
332
+ Returns `true` if the element is found (strict `===` via `Array.includes`).
333
+
334
+ ---
335
+
336
+ ### `array.toArray(value)`
337
+
338
+ Normalizes any value into an array: `undefined` → `[]`, non-array → `[value]`, array → as-is.
339
+
340
+ ---
341
+
342
+ ### `array.toDisArray(oArray)`
343
+
344
+ Unwraps a single-element array to its value. Multi-element arrays pass through.
345
+
346
+ ---
347
+
348
+ ### `array.toInterleavedArray(oArray, oElement)`
349
+
350
+ Inserts a separator element between consecutive items.
351
+
352
+ ```js
353
+ array.toInterleavedArray(["a", "b", "c"], "|"); // ["a", ["|"], "b", ["|"], "c"]
354
+ ```
355
+
356
+ ---
357
+
358
+ ### `array.toArrayProjection(oArray, sProjectionFieldName)`
359
+
360
+ Extracts a single field from each element into a flat array.
361
+
362
+ ```js
363
+ array.toArrayProjection([{ id: 1 }, { id: 2 }], "id"); // [1, 2]
364
+ ```
365
+
366
+ ---
367
+
368
+ ### `array.findProperty(oArray, sProjectionFieldName)`
369
+
370
+ Recursively searches nested structures for all values of a named property. Returns a deduplicated array.
371
+
372
+ ---
373
+
374
+ ### `array.toGroupByPropertyName(oArray, sPropertyName)`
375
+
376
+ Groups elements into an object keyed by a single property's value.
377
+
378
+ ```js
379
+ array.toGroupByPropertyName(
380
+ [{ type: "A", v: 1 }, { type: "B", v: 2 }, { type: "A", v: 3 }],
381
+ "type"
382
+ );
383
+ // { A: [{...}, {...}], B: [{...}] }
384
+ ```
385
+
386
+ ---
387
+
388
+ ### `array.toGroupByPropertyList(oArray, oPropertyList)`
389
+
390
+ Groups elements by a composite key derived from multiple properties (joined with `##`). Supports dot-notation paths and recursive deep property lookup.
391
+
392
+ ```js
393
+ array.toGroupByPropertyList(data, ["region", "details.category"]);
394
+ // { "US##Electronics": [...], "EU##Clothing": [...] }
395
+ ```
396
+
397
+ ---
398
+
399
+ ## Class: `UUID`
400
+
401
+ Singleton class for deterministic UUID generation and parsing based on a fixed field configuration. Encodes/decodes structured business data into RFC-4122-compliant UUIDs.
402
+
403
+ ### Constructor
404
+
405
+ ```js
406
+ const uuidHelper = new UUID();
407
+ ```
408
+
409
+ Creates a singleton instance. Subsequent `new UUID()` calls return the same instance.
410
+
411
+ ---
412
+
413
+ ### `converse(oJsonData)`
414
+
415
+ Encodes structured JSON data into a deterministic UUID.
416
+
417
+ | Parameter | Type | Description |
418
+ |------------|----------|-------------------------------------------|
419
+ | `oJsonData` | `object` | Object |
420
+ | **Returns** | `string` | A valid UUID string |
421
+ | **Throws** | `Error` | If any field has an invalid format or the generated UUID fails validation |
422
+
423
+ ```js
424
+ const uid = new UUID();
425
+ uid.converse({
426
+ ABC: "AB12",
427
+ MNO: "I1234567",
428
+ XYZ: "000000012345"
429
+ });
430
+ // Returns a valid UUID string e.g., "c0656612-2e12-4345-8670-000000012345"
431
+ ```
432
+
433
+ ---
434
+
435
+ ### `inverse(sUUID)`
436
+
437
+ Decodes a previously generated UUID back into its original structured data.
438
+
439
+ | Parameter | Type | Description |
440
+ |-----------|----------|------------------------------------|
441
+ | `sUUID` | `string` | A UUID previously created by `converse` |
442
+ | **Returns** | `object` | `{ ABC, MNO, XYZ }` or `{}` if invalid |
443
+
444
+ ```js
445
+ const uid = new UUID();
446
+ uid.inverse("c0656612-2e12-4345-8670-000000012345");
447
+ // { ABC: "AB12", MNO: "I1234567", XYZ: "000000012345" }
448
+ ```
449
+
450
+ ---
451
+
452
+ ## Quick Usage Examples
453
+
454
+ ```js
455
+ const { date, xml, json, array, UUID } = require('esi-cap').utils;
456
+
457
+ // Validate & transform
458
+ const valid = await date.isValid("2026-04-20");
459
+ const items = [{ id: 1, name: "A" }, { id: 2, name: "B" }];
460
+
461
+ // Project, sort, filter
462
+ const names = array.toArrayProjection(items, "name"); // ["A", "B"]
463
+ const sorted = array.sort(items, [{ ref: ["id"], sort: "desc" }]);
464
+ const filtered = array.filter(items, [{ name: "id", op: ">", value: 1 }]);
465
+
466
+ // Group & merge
467
+ const grouped = array.toGroupByPropertyName(items, "name");
468
+ const merged = json.merge({ a: 1 }, { b: 2 }); // { a: 1, b: 2 }
469
+
470
+ // UUID round-trip
471
+ const uid = new UUID();
472
+ const uuidStr = uid.converse({ ABC: "AB12", MNO: "I1234567", XYZ: "000000012345" });
473
+ const original = uid.inverse(uuidStr);
474
+ ```