@hkdigital/lib-sveltekit 0.0.42 → 0.0.44
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.
- package/README.md +2 -2
- package/dist/classes/data/IterableTree.d.ts +51 -0
- package/dist/classes/data/IterableTree.js +243 -0
- package/dist/classes/data/Selector.d.ts +28 -0
- package/dist/classes/data/Selector.js +188 -0
- package/dist/classes/data/index.d.ts +2 -0
- package/dist/classes/data/index.js +2 -0
- package/dist/classes/index.d.ts +1 -0
- package/dist/classes/index.js +1 -0
- package/dist/index.js +1 -1
- package/dist/util/array/index.d.ts +171 -0
- package/dist/util/array/index.js +432 -0
- package/dist/util/compare/index.d.ts +68 -0
- package/dist/util/compare/index.js +247 -0
- package/dist/util/expect/index.d.ts +113 -2
- package/dist/util/expect/index.js +215 -28
- package/dist/util/is/index.d.ts +67 -0
- package/dist/util/is/index.js +154 -0
- package/dist/util/iterate/index.d.ts +131 -0
- package/dist/util/iterate/index.js +234 -0
- package/dist/util/object/index.d.ts +326 -0
- package/dist/util/object/index.js +1361 -0
- package/dist/util/string/index.d.ts +60 -0
- package/dist/util/string/index.js +184 -0
- package/package.json +1 -1
package/README.md
CHANGED
@@ -40,7 +40,7 @@ All exports are in subfolders.
|
|
40
40
|
For example to import a constant from `constants/regexp/index.js`
|
41
41
|
|
42
42
|
```svelte
|
43
|
-
import { CHAR } from '@hkdigital/lib-sveltekit
|
43
|
+
import { CHAR } from '@hkdigital/lib-sveltekit/constants/regexp';
|
44
44
|
```
|
45
45
|
|
46
46
|
### Import CSS
|
@@ -51,7 +51,7 @@ For example:
|
|
51
51
|
|
52
52
|
```css
|
53
53
|
/* src/app.css */
|
54
|
-
@import '../node_modules/@hkdigital/lib-sveltekit
|
54
|
+
@import '../node_modules/@hkdigital/lib-sveltekit/dist/css/utilities.postcss';
|
55
55
|
```
|
56
56
|
|
57
57
|
### Enable tailwind processing
|
@@ -0,0 +1,51 @@
|
|
1
|
+
/**
|
2
|
+
* @typedef {object} Options
|
3
|
+
* @property {boolean} walkArrays
|
4
|
+
* @property {boolean} ignoreEmptyObjectLeaves
|
5
|
+
* @property {boolean} expandPathKeys
|
6
|
+
* @property {boolean} outputIntermediateNodes
|
7
|
+
*/
|
8
|
+
export default class IterableTree {
|
9
|
+
/**
|
10
|
+
* Construct an object that can be used to iterate paths and values in
|
11
|
+
* an object.
|
12
|
+
* - Returns path-value pairs for all leaves of the object (tree)
|
13
|
+
* - Iterates "own properties" only (not inherited properties)
|
14
|
+
*
|
15
|
+
* @param {object} obj - Object to iterate
|
16
|
+
* @param {Options} [options]
|
17
|
+
* @param {string[]} [_parentArrPath]
|
18
|
+
*
|
19
|
+
*
|
20
|
+
* @return {Iterator} iterable object
|
21
|
+
*/
|
22
|
+
constructor(obj: object, options?: Options, _parentArrPath?: string[]);
|
23
|
+
obj: any;
|
24
|
+
_parentArrPath: string[];
|
25
|
+
/**
|
26
|
+
* Get an iterator to iterate over all object [ path, value ] entries
|
27
|
+
*
|
28
|
+
* @returns {Iterator} object entries iterator
|
29
|
+
*/
|
30
|
+
entries(): Iterator<any, any, any>;
|
31
|
+
/**
|
32
|
+
* Get an iterator to iterate over all object paths
|
33
|
+
*
|
34
|
+
* @returns {Iterator} object path iterator
|
35
|
+
*/
|
36
|
+
paths(): Iterator<any, any, any>;
|
37
|
+
/**
|
38
|
+
* Get an iterator to iterate over all values at the leaves of the paths in
|
39
|
+
* the object
|
40
|
+
*
|
41
|
+
* @returns {Iterator} object value iterator
|
42
|
+
*/
|
43
|
+
values(): Iterator<any, any, any>;
|
44
|
+
#private;
|
45
|
+
}
|
46
|
+
export type Options = {
|
47
|
+
walkArrays: boolean;
|
48
|
+
ignoreEmptyObjectLeaves: boolean;
|
49
|
+
expandPathKeys: boolean;
|
50
|
+
outputIntermediateNodes: boolean;
|
51
|
+
};
|
@@ -0,0 +1,243 @@
|
|
1
|
+
/* ------------------------------------------------------------------ Imports */
|
2
|
+
|
3
|
+
import * as expect from '../../util/expect/index.js';
|
4
|
+
|
5
|
+
import { PATH_SEPARATOR } from '../../util/object/index.js';
|
6
|
+
|
7
|
+
/* ------------------------------------------------------------------ Typedef */
|
8
|
+
|
9
|
+
/**
|
10
|
+
* @typedef {object} Options
|
11
|
+
* @property {boolean} walkArrays
|
12
|
+
* @property {boolean} ignoreEmptyObjectLeaves
|
13
|
+
* @property {boolean} expandPathKeys
|
14
|
+
* @property {boolean} outputIntermediateNodes
|
15
|
+
*/
|
16
|
+
|
17
|
+
/* ------------------------------------------------------------------ Exports */
|
18
|
+
|
19
|
+
export default class IterableTree {
|
20
|
+
/**
|
21
|
+
* @type {Options}
|
22
|
+
*/
|
23
|
+
#options;
|
24
|
+
|
25
|
+
/**
|
26
|
+
* Construct an object that can be used to iterate paths and values in
|
27
|
+
* an object.
|
28
|
+
* - Returns path-value pairs for all leaves of the object (tree)
|
29
|
+
* - Iterates "own properties" only (not inherited properties)
|
30
|
+
*
|
31
|
+
* @param {object} obj - Object to iterate
|
32
|
+
* @param {Options} [options]
|
33
|
+
* @param {string[]} [_parentArrPath]
|
34
|
+
*
|
35
|
+
*
|
36
|
+
* @return {Iterator} iterable object
|
37
|
+
*/
|
38
|
+
constructor(obj, options, _parentArrPath) {
|
39
|
+
//super( ...arguments );
|
40
|
+
|
41
|
+
expect.object(obj);
|
42
|
+
|
43
|
+
this.obj = obj;
|
44
|
+
|
45
|
+
this.#options = Object.assign(
|
46
|
+
{
|
47
|
+
walkArrays: false,
|
48
|
+
ignoreEmptyObjectLeaves: false,
|
49
|
+
expandPathKeys: false,
|
50
|
+
outputIntermediateNodes: false
|
51
|
+
},
|
52
|
+
options
|
53
|
+
);
|
54
|
+
|
55
|
+
this._parentArrPath = _parentArrPath || null;
|
56
|
+
}
|
57
|
+
|
58
|
+
/* --------------------------------------------------------- Public methods */
|
59
|
+
|
60
|
+
// -------------------------------------------------------------------- Method
|
61
|
+
|
62
|
+
/**
|
63
|
+
* Get an iterator to iterate over all object [ path, value ] entries
|
64
|
+
*
|
65
|
+
* @returns {Iterator} object entries iterator
|
66
|
+
*/
|
67
|
+
*entries() {
|
68
|
+
const obj = this.obj;
|
69
|
+
const parentArrPath = this._parentArrPath;
|
70
|
+
|
71
|
+
const options = this.options;
|
72
|
+
|
73
|
+
let { expandPathKeys, ignoreEmptyObjectLeaves, outputIntermediateNodes } = this.#options;
|
74
|
+
|
75
|
+
if (parentArrPath) {
|
76
|
+
// Never expand keys if not in root object
|
77
|
+
expandPathKeys = false;
|
78
|
+
}
|
79
|
+
|
80
|
+
// @note keys are own properties only
|
81
|
+
const keys = Object.keys(obj);
|
82
|
+
|
83
|
+
let pathKeys;
|
84
|
+
|
85
|
+
if (expandPathKeys) {
|
86
|
+
pathKeys = [];
|
87
|
+
}
|
88
|
+
|
89
|
+
// -- STEP 1: Normal object iteration (and gather path keys)
|
90
|
+
|
91
|
+
for (let j = 0, n = keys.length; j < n; j = j + 1) {
|
92
|
+
const key = keys[j];
|
93
|
+
|
94
|
+
if (expandPathKeys && key.includes(PATH_SEPARATOR)) {
|
95
|
+
// Gather pathKeys
|
96
|
+
pathKeys.push(key);
|
97
|
+
continue;
|
98
|
+
}
|
99
|
+
|
100
|
+
const valueAtPath = obj[key];
|
101
|
+
|
102
|
+
if (undefined === valueAtPath) {
|
103
|
+
// Ignore path-value pair if valueAtPath is undefined
|
104
|
+
continue;
|
105
|
+
}
|
106
|
+
|
107
|
+
let path;
|
108
|
+
|
109
|
+
if (parentArrPath) {
|
110
|
+
path = parentArrPath.slice(0);
|
111
|
+
path.push(key);
|
112
|
+
} else {
|
113
|
+
path = [key];
|
114
|
+
}
|
115
|
+
|
116
|
+
// No recursion >>
|
117
|
+
|
118
|
+
if (!this.#shouldRecurse(valueAtPath)) {
|
119
|
+
if (
|
120
|
+
ignoreEmptyObjectLeaves &&
|
121
|
+
valueAtPath instanceof Object &&
|
122
|
+
0 === Object.keys(valueAtPath).length
|
123
|
+
) {
|
124
|
+
// Ignore empty object leave
|
125
|
+
continue;
|
126
|
+
}
|
127
|
+
|
128
|
+
yield [path, valueAtPath];
|
129
|
+
continue;
|
130
|
+
}
|
131
|
+
|
132
|
+
// Recursion >>
|
133
|
+
|
134
|
+
// console.log( { path, valueAtPath, outputIntermediateNodes } );
|
135
|
+
|
136
|
+
if (outputIntermediateNodes) {
|
137
|
+
// outputIntermediateNodes=true
|
138
|
+
// -> Output itermediate node
|
139
|
+
|
140
|
+
if (Array.isArray(valueAtPath)) {
|
141
|
+
// Intermediate node is an array
|
142
|
+
yield [path, []];
|
143
|
+
} else {
|
144
|
+
// Intermediate node is plain object
|
145
|
+
yield [path, {}];
|
146
|
+
}
|
147
|
+
}
|
148
|
+
|
149
|
+
const objectIterator = new IterableTree(valueAtPath, options, path);
|
150
|
+
|
151
|
+
for (const entry of objectIterator.entries()) {
|
152
|
+
yield entry;
|
153
|
+
}
|
154
|
+
} // end for
|
155
|
+
|
156
|
+
// -- STEP 2: Output entries from "path keys"
|
157
|
+
|
158
|
+
if (!pathKeys || !pathKeys.length) {
|
159
|
+
// No path keys -> done
|
160
|
+
return;
|
161
|
+
}
|
162
|
+
|
163
|
+
for (let j = 0, n = pathKeys.length; j < n; j = j + 1) {
|
164
|
+
// @note path keys do not output intermediate nodes
|
165
|
+
|
166
|
+
const key = pathKeys[j];
|
167
|
+
|
168
|
+
const valueAtPath = obj[key];
|
169
|
+
const path = key.split(PATH_SEPARATOR);
|
170
|
+
|
171
|
+
yield [path, valueAtPath];
|
172
|
+
}
|
173
|
+
}
|
174
|
+
|
175
|
+
// -------------------------------------------------------------------- Method
|
176
|
+
|
177
|
+
/**
|
178
|
+
* Get an iterator to iterate over all object paths
|
179
|
+
*
|
180
|
+
* @returns {Iterator} object path iterator
|
181
|
+
*/
|
182
|
+
*paths() {
|
183
|
+
for (const entry of this.entries()) {
|
184
|
+
yield entry[0];
|
185
|
+
}
|
186
|
+
}
|
187
|
+
|
188
|
+
// -------------------------------------------------------------------- Method
|
189
|
+
|
190
|
+
/**
|
191
|
+
* Get an iterator to iterate over all values at the leaves of the paths in
|
192
|
+
* the object
|
193
|
+
*
|
194
|
+
* @returns {Iterator} object value iterator
|
195
|
+
*/
|
196
|
+
*values() {
|
197
|
+
for (const entry of this.entries()) {
|
198
|
+
yield entry[1];
|
199
|
+
}
|
200
|
+
}
|
201
|
+
|
202
|
+
// -------------------------------------------------------------------- Method
|
203
|
+
|
204
|
+
/**
|
205
|
+
* Returns true if the iterator should recurse into the specified value
|
206
|
+
*
|
207
|
+
* @param {string} value
|
208
|
+
*
|
209
|
+
* @return {boolean} true if the value should be iterated
|
210
|
+
*/
|
211
|
+
#shouldRecurse(value) {
|
212
|
+
if (!(value instanceof Object)) {
|
213
|
+
// not an object -> no recursion
|
214
|
+
return false;
|
215
|
+
}
|
216
|
+
|
217
|
+
const walkArrays = this.#options.walkArrays;
|
218
|
+
|
219
|
+
if (walkArrays && Array.isArray(value)) {
|
220
|
+
// walkArrays=true AND isArray
|
221
|
+
|
222
|
+
if (!value.length) {
|
223
|
+
// Array is empty -> no recursion
|
224
|
+
return false;
|
225
|
+
}
|
226
|
+
|
227
|
+
return true;
|
228
|
+
}
|
229
|
+
|
230
|
+
if ('[object Object]' !== value.toString()) {
|
231
|
+
// Not a plain object -> no recursion
|
232
|
+
return false;
|
233
|
+
}
|
234
|
+
|
235
|
+
if (Object.keys(value).length) {
|
236
|
+
// Object is not empty -> recursion
|
237
|
+
return true;
|
238
|
+
}
|
239
|
+
|
240
|
+
// Otherwise -> no recursion
|
241
|
+
return false;
|
242
|
+
}
|
243
|
+
} // end class
|
@@ -0,0 +1,28 @@
|
|
1
|
+
/**
|
2
|
+
* Construct a Selector class
|
3
|
+
*/
|
4
|
+
export default class Selector {
|
5
|
+
/**
|
6
|
+
* Constructor
|
7
|
+
*
|
8
|
+
* @param {object|null} selector
|
9
|
+
*/
|
10
|
+
constructor(selector: object | null);
|
11
|
+
/**
|
12
|
+
* Returns the first item from the list of items that matches the selector
|
13
|
+
*
|
14
|
+
* @param {object[]|null} items
|
15
|
+
*
|
16
|
+
* @returns {object|null} item or null if not found
|
17
|
+
*/
|
18
|
+
findFirst(items: object[] | null): object | null;
|
19
|
+
/**
|
20
|
+
* Returns all items from the list of items that match the selector
|
21
|
+
*
|
22
|
+
* @param {object[]|null} items
|
23
|
+
*
|
24
|
+
* @returns {object|null} item or null if not found
|
25
|
+
*/
|
26
|
+
findAll(items: object[] | null): object | null;
|
27
|
+
#private;
|
28
|
+
}
|
@@ -0,0 +1,188 @@
|
|
1
|
+
/**
|
2
|
+
* Selector.js
|
3
|
+
*
|
4
|
+
* @description
|
5
|
+
* This file contains a class that can be used to select items from lists of
|
6
|
+
* objects.
|
7
|
+
*
|
8
|
+
* @TODO
|
9
|
+
* Allow other selection criteria than exact key-value pair matches
|
10
|
+
*
|
11
|
+
* @example
|
12
|
+
*
|
13
|
+
* import Selector from "./Selector.js";
|
14
|
+
*
|
15
|
+
* const selector = new Selector( { age: 42 } );
|
16
|
+
*
|
17
|
+
* const items =
|
18
|
+
* [
|
19
|
+
* { name: "Maria", age: 41 },
|
20
|
+
* { name: "John", age: 42 },
|
21
|
+
* { name: "Max", age: 43 }
|
22
|
+
* ]
|
23
|
+
*
|
24
|
+
* const item = selector.findFirst( items );
|
25
|
+
*
|
26
|
+
* console.log( item );
|
27
|
+
*/
|
28
|
+
|
29
|
+
/* ------------------------------------------------------------------ Imports */
|
30
|
+
|
31
|
+
import * as expect from '../../util/expect/index.js';
|
32
|
+
|
33
|
+
/* ------------------------------------------------------------------- Export */
|
34
|
+
|
35
|
+
/**
|
36
|
+
* Construct a Selector class
|
37
|
+
*/
|
38
|
+
export default class Selector {
|
39
|
+
/** @type {function|null} test function */
|
40
|
+
#testFn = null;
|
41
|
+
|
42
|
+
/**
|
43
|
+
* Constructor
|
44
|
+
*
|
45
|
+
* @param {object|null} selector
|
46
|
+
*/
|
47
|
+
constructor(selector) {
|
48
|
+
this.#updateTestFn(selector);
|
49
|
+
}
|
50
|
+
|
51
|
+
// -------------------------------------------------------------------- Method
|
52
|
+
|
53
|
+
/**
|
54
|
+
* Returns the first item from the list of items that matches the selector
|
55
|
+
*
|
56
|
+
* @param {object[]|null} items
|
57
|
+
*
|
58
|
+
* @returns {object|null} item or null if not found
|
59
|
+
*/
|
60
|
+
findFirst(items) {
|
61
|
+
if (!items) {
|
62
|
+
return null;
|
63
|
+
}
|
64
|
+
|
65
|
+
for (const item of items) {
|
66
|
+
if (this.#testFn(item)) {
|
67
|
+
return item;
|
68
|
+
}
|
69
|
+
}
|
70
|
+
|
71
|
+
return null;
|
72
|
+
}
|
73
|
+
|
74
|
+
// -------------------------------------------------------------------- Method
|
75
|
+
|
76
|
+
/**
|
77
|
+
* Returns all items from the list of items that match the selector
|
78
|
+
*
|
79
|
+
* @param {object[]|null} items
|
80
|
+
*
|
81
|
+
* @returns {object|null} item or null if not found
|
82
|
+
*/
|
83
|
+
findAll(items) {
|
84
|
+
const result = [];
|
85
|
+
|
86
|
+
if (!items) {
|
87
|
+
return result;
|
88
|
+
}
|
89
|
+
|
90
|
+
for (const item of items) {
|
91
|
+
if (this.#testFn(item)) {
|
92
|
+
result.push(item);
|
93
|
+
}
|
94
|
+
}
|
95
|
+
|
96
|
+
return result;
|
97
|
+
}
|
98
|
+
|
99
|
+
/* ------------------------------------------------------- Internal methods */
|
100
|
+
|
101
|
+
/**
|
102
|
+
* Update the internal selector function
|
103
|
+
*/
|
104
|
+
#updateTestFn(selector) {
|
105
|
+
// > Case A: selector=null
|
106
|
+
|
107
|
+
if (null === selector) {
|
108
|
+
this.#testFn = this.#returnTrue;
|
109
|
+
return;
|
110
|
+
}
|
111
|
+
|
112
|
+
// > Validate selector
|
113
|
+
|
114
|
+
expect.objectOrNull(selector);
|
115
|
+
|
116
|
+
const keys = Object.keys(selector);
|
117
|
+
const n = keys.length;
|
118
|
+
|
119
|
+
// > Case B: selector has not properties
|
120
|
+
|
121
|
+
if (!n) {
|
122
|
+
this.#testFn = this.#returnTrue;
|
123
|
+
return;
|
124
|
+
}
|
125
|
+
|
126
|
+
// > Case C: selector with single key-value pair
|
127
|
+
|
128
|
+
if (1 === n) {
|
129
|
+
const key = keys[0];
|
130
|
+
const value = selector[key];
|
131
|
+
|
132
|
+
this.#testFn = this.#testKeyValue.bind(this, key, value);
|
133
|
+
}
|
134
|
+
|
135
|
+
// > Case D: selector with multiple key-value pairs
|
136
|
+
|
137
|
+
const selectorValues = [];
|
138
|
+
|
139
|
+
for (const key of keys) {
|
140
|
+
selectorValues.push(selector[key]);
|
141
|
+
}
|
142
|
+
|
143
|
+
this.#testFn = this.#testMultipleKeyValues.bind(this, keys, selectorValues);
|
144
|
+
}
|
145
|
+
|
146
|
+
// -------------------------------------------------------------------- Method
|
147
|
+
|
148
|
+
/**
|
149
|
+
* Always return true
|
150
|
+
* - This function is used if the test function should always return true
|
151
|
+
*
|
152
|
+
* @returns {boolean} true
|
153
|
+
*/
|
154
|
+
#returnTrue() {
|
155
|
+
return true;
|
156
|
+
}
|
157
|
+
|
158
|
+
// -------------------------------------------------------------------- Method
|
159
|
+
|
160
|
+
/**
|
161
|
+
* Return true if the item matches the key-value pair
|
162
|
+
* - This function is used if the test function should test a
|
163
|
+
* single key-value pair
|
164
|
+
*/
|
165
|
+
#testKeyValue(key, value, item) {
|
166
|
+
return value === item[key];
|
167
|
+
}
|
168
|
+
|
169
|
+
// -------------------------------------------------------------------- Method
|
170
|
+
|
171
|
+
/**
|
172
|
+
* Return true if the item matches all key-value pairs
|
173
|
+
* - This function is used if the test function should test multiple
|
174
|
+
* key-value pairs
|
175
|
+
*/
|
176
|
+
#testMultipleKeyValues(keys, values, item) {
|
177
|
+
let isMatch = true;
|
178
|
+
|
179
|
+
for (let j = 0, n = keys.length; j < n; j = j + 1) {
|
180
|
+
if (values[j] !== item[keys[j]]) {
|
181
|
+
isMatch = false;
|
182
|
+
break;
|
183
|
+
}
|
184
|
+
} // end for
|
185
|
+
|
186
|
+
return isMatch;
|
187
|
+
}
|
188
|
+
} // end class
|
package/dist/classes/index.d.ts
CHANGED
package/dist/classes/index.js
CHANGED