@kizmann/pico-js 1.0.13 → 2.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.
- package/README.md +27 -7
- package/dist/pico-js.browser.js +2 -0
- package/dist/pico-js.browser.js.map +1 -0
- package/dist/pico-js.esm.js +2 -0
- package/dist/pico-js.esm.js.map +1 -0
- package/package.json +20 -7
- package/src/dom/DomAttribute.js +374 -0
- package/src/dom/DomBuilder.js +152 -0
- package/src/dom/DomEvent.js +253 -0
- package/src/dom/DomFinder.js +669 -0
- package/src/dom/DomForm.js +57 -0
- package/src/dom/DomGlobal.js +193 -0
- package/src/dom/DomInview.js +332 -0
- package/src/dom/DomMeta.js +66 -0
- package/src/dom/DomObserver.js +57 -0
- package/src/dom/DomRectangle.js +657 -0
- package/src/format/FormatFile.js +54 -0
- package/src/format/FormatOption.js +108 -0
- package/src/format/FormatParam.js +107 -0
- package/src/format/FormatParser.js +156 -0
- package/src/format/FormatUrl.js +75 -0
- package/src/index.browser.js +10 -0
- package/src/index.esm.js +138 -0
- package/src/now/NowDefault.js +533 -0
- package/src/now/NowFormat.js +196 -0
- package/src/now/NowGrid.js +251 -0
- package/src/now/NowHuman.js +118 -0
- package/src/now/NowMatch.js +175 -0
- package/src/now/NowRange.js +70 -0
- package/src/now/NowWalker.js +544 -0
- package/src/tool/scope.js +103 -0
- package/src/utils/Array.js +986 -0
- package/src/utils/Cookie.js +184 -0
- package/src/utils/Data.js +200 -0
- package/src/utils/Dom.js +208 -0
- package/src/utils/Event.js +140 -0
- package/src/utils/Format.js +62 -0
- package/src/utils/Hash.js +164 -0
- package/src/utils/Locale.js +229 -0
- package/src/utils/Mixed.js +887 -0
- package/src/utils/Now.js +234 -0
- package/src/utils/Number.js +238 -0
- package/src/utils/Object.js +655 -0
- package/src/utils/Route.js +67 -0
- package/src/utils/Runner.js +327 -0
- package/src/utils/String.js +618 -0
- package/src/{library/element.js → wip/Element.js} +90 -16
- package/src/{library/map.js → wip/Map.js} +256 -40
- package/types/dom/DomAttribute.d.ts +137 -0
- package/types/dom/DomBuilder.d.ts +67 -0
- package/types/dom/DomEvent.d.ts +103 -0
- package/types/dom/DomFinder.d.ts +321 -0
- package/types/dom/DomForm.d.ts +21 -0
- package/types/dom/DomGlobal.d.ts +79 -0
- package/types/dom/DomInview.d.ts +114 -0
- package/types/dom/DomMeta.d.ts +29 -0
- package/types/dom/DomObserver.d.ts +21 -0
- package/types/dom/DomRectangle.d.ts +270 -0
- package/types/format/FormatFile.d.ts +18 -0
- package/types/format/FormatOption.d.ts +40 -0
- package/types/format/FormatParam.d.ts +39 -0
- package/types/format/FormatParser.d.ts +46 -0
- package/types/format/FormatUrl.d.ts +17 -0
- package/types/index.browser.d.ts +1 -0
- package/types/index.esm.d.ts +52 -0
- package/types/now/NowDefault.d.ts +183 -0
- package/types/now/NowFormat.d.ts +70 -0
- package/types/now/NowGrid.d.ts +107 -0
- package/types/now/NowHuman.d.ts +37 -0
- package/types/now/NowMatch.d.ts +108 -0
- package/types/now/NowRange.d.ts +21 -0
- package/types/now/NowWalker.d.ts +301 -0
- package/types/tool/scope.d.ts +24 -0
- package/types/utils/Array.d.ts +480 -0
- package/types/utils/Cookie.d.ts +60 -0
- package/types/utils/Data.d.ts +91 -0
- package/types/utils/Dom.d.ts +138 -0
- package/types/utils/Event.d.ts +58 -0
- package/types/utils/Format.d.ts +37 -0
- package/types/utils/Hash.d.ts +81 -0
- package/types/utils/Locale.d.ts +115 -0
- package/types/utils/Mixed.d.ts +469 -0
- package/types/utils/Now.d.ts +125 -0
- package/types/utils/Number.d.ts +127 -0
- package/types/utils/Object.d.ts +255 -0
- package/types/utils/Route.d.ts +37 -0
- package/types/utils/Runner.d.ts +139 -0
- package/types/utils/String.d.ts +330 -0
- package/types/wip/Element.d.ts +119 -0
- package/types/wip/Map.d.ts +254 -0
- package/dist/.ignore.js +0 -0
- package/dist/pico-js.js +0 -2
- package/dist/pico-js.js.map +0 -1
- package/src/element/default.js +0 -46
- package/src/element/example.js +0 -58
- package/src/index.js +0 -90
- package/src/library/cookie.js +0 -123
- package/src/library/data.js +0 -111
- package/src/library/event.js +0 -91
- package/src/library/locale.js +0 -84
- package/src/library/queue.js +0 -64
- package/src/library/route.js +0 -28
- package/src/utility/any.js +0 -369
- package/src/utility/array.js +0 -410
- package/src/utility/dom.js +0 -1425
- package/src/utility/now.js +0 -544
- package/src/utility/number.js +0 -128
- package/src/utility/object.js +0 -429
- package/src/utility/string.js +0 -328
- package/types/index.d.ts +0 -77
- package/types/library/cookie.d.ts +0 -10
- package/types/library/data.d.ts +0 -15
- package/types/library/element.d.ts +0 -22
- package/types/library/event.d.ts +0 -13
- package/types/library/locale.d.ts +0 -14
- package/types/library/map.d.ts +0 -43
- package/types/library/queue.d.ts +0 -18
- package/types/library/route.d.ts +0 -11
- package/types/utility/any.d.ts +0 -35
- package/types/utility/array.d.ts +0 -46
- package/types/utility/dom.d.ts +0 -101
- package/types/utility/now.d.ts +0 -79
- package/types/utility/number.d.ts +0 -17
- package/types/utility/object.d.ts +0 -29
- package/types/utility/string.d.ts +0 -26
|
@@ -0,0 +1,655 @@
|
|
|
1
|
+
import { go, Mix, Arr } from "#src/index.esm.js";
|
|
2
|
+
|
|
3
|
+
export class PicoObject
|
|
4
|
+
{
|
|
5
|
+
/**
|
|
6
|
+
* Normalize key path to array
|
|
7
|
+
*
|
|
8
|
+
* @example Obj.keyoptim("a.b") // => ["a","b"]
|
|
9
|
+
* @example Obj.keyoptim(["a","b"]) // => ["a","b"]
|
|
10
|
+
*
|
|
11
|
+
* @param {any} keys Key path
|
|
12
|
+
* @param {boolean} [flatten] Flatten keys
|
|
13
|
+
* @param {boolean|null} [isstr] Is string flag
|
|
14
|
+
* @returns {Array<any>} Key segments
|
|
15
|
+
*/
|
|
16
|
+
static keyoptim(keys, flatten = false, isstr = null)
|
|
17
|
+
{
|
|
18
|
+
if ( isstr === null ) {
|
|
19
|
+
isstr = Mix.isStr(keys);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if ( !isstr && flatten ) {
|
|
23
|
+
keys = keys.join('.');
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return isstr || flatten ? keys.split('.') : keys;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Check if nested key exists
|
|
31
|
+
*
|
|
32
|
+
* @example Obj.has({a:{b:1}}, "a.b") // => true
|
|
33
|
+
* @example Obj.has({a:{}}, "a.b") // => false
|
|
34
|
+
*
|
|
35
|
+
* @param {any} target Target object
|
|
36
|
+
* @param {any} keys Key path
|
|
37
|
+
* @param {boolean} [flatten] Flatten keys
|
|
38
|
+
* @returns {boolean} True if exists
|
|
39
|
+
*/
|
|
40
|
+
static has(target, keys, flatten = false)
|
|
41
|
+
{
|
|
42
|
+
if ( target == null || keys == null ) {
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if ( typeof keys === 'number' ) {
|
|
47
|
+
keys = Mix.str(keys);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const isstr = typeof keys === 'string';
|
|
51
|
+
|
|
52
|
+
if ( isstr && target && target[keys] !== undefined ) {
|
|
53
|
+
return target[keys] !== undefined;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
keys = this.keyoptim(keys, flatten, isstr);
|
|
57
|
+
|
|
58
|
+
let [list, index, length] = [
|
|
59
|
+
keys.pop(), 0, keys.length
|
|
60
|
+
];
|
|
61
|
+
|
|
62
|
+
if ( length === 0 ) {
|
|
63
|
+
return target[list] !== undefined;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
while ( target != null && index < length ) {
|
|
67
|
+
target = target[keys[index ++]];
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if ( target == null ) {
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return target[list] !== undefined;
|
|
75
|
+
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Get nested value or fallback
|
|
80
|
+
*
|
|
81
|
+
* @example Obj.get({a:{b:1}}, "a.b") // => 1
|
|
82
|
+
* @example Obj.get({}, "a.b", null) // => null
|
|
83
|
+
*
|
|
84
|
+
* @param {any} target Target object
|
|
85
|
+
* @param {any} keys Key path
|
|
86
|
+
* @param {any} [fallback] Fallback value
|
|
87
|
+
* @param {boolean} [flatten] Flatten keys
|
|
88
|
+
* @returns {any} Nested value
|
|
89
|
+
*/
|
|
90
|
+
static get(target, keys, fallback = null, flatten = false)
|
|
91
|
+
{
|
|
92
|
+
if ( target == null || keys == null ) {
|
|
93
|
+
return fallback;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if ( typeof keys === 'number' ) {
|
|
97
|
+
keys = Mix.str(keys);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const isstr = typeof keys === 'string';
|
|
101
|
+
|
|
102
|
+
if ( isstr && target && target[keys] !== undefined ) {
|
|
103
|
+
return target[keys];
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
keys = this.keyoptim(keys, flatten, isstr);
|
|
107
|
+
|
|
108
|
+
let index = 0, length = keys.length;
|
|
109
|
+
|
|
110
|
+
if ( length === 0 ) {
|
|
111
|
+
return fallback;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
while ( target != null && index < length ) {
|
|
115
|
+
target = target[keys[index ++]];
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if ( target == null ) {
|
|
119
|
+
return fallback;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return target;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Set nested value (mutates)
|
|
127
|
+
*
|
|
128
|
+
* @example Obj.set({}, "a.b", 1) // => object
|
|
129
|
+
* @example Obj.set({}, ["a","b"], 1) // => object
|
|
130
|
+
*
|
|
131
|
+
* @param {any} target Target object
|
|
132
|
+
* @param {any} keys Key path
|
|
133
|
+
* @param {any} value Value to set
|
|
134
|
+
* @param {boolean} [flatten] Flatten keys
|
|
135
|
+
* @returns {any} Mutated target
|
|
136
|
+
*/
|
|
137
|
+
static set(target, keys, value, flatten = false)
|
|
138
|
+
{
|
|
139
|
+
if ( keys == null ) {
|
|
140
|
+
return target;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if ( typeof keys === 'number' ) {
|
|
144
|
+
keys = Mix.str(keys);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const isstr = typeof keys === 'string';
|
|
148
|
+
|
|
149
|
+
if ( isstr && target && target[keys] !== undefined ) {
|
|
150
|
+
return (target[keys] = value, target);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
keys = this.keyoptim(keys, flatten, isstr);
|
|
154
|
+
|
|
155
|
+
if ( keys.length === 0 ) {
|
|
156
|
+
return target;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
let nested = target;
|
|
160
|
+
|
|
161
|
+
for ( let mod, src, i = 0; i < keys.length; i++) {
|
|
162
|
+
|
|
163
|
+
mod = src = String(keys[i]);
|
|
164
|
+
|
|
165
|
+
if ( src.indexOf('[]') !== -1 ) {
|
|
166
|
+
mod = src.replace('[]', '');
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if ( nested[mod] == null ) {
|
|
170
|
+
nested[mod] = mod === src ? {} : [];
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
if ( mod !== src ) {
|
|
174
|
+
Arr.insert(keys, i + 1, nested[mod].length);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
if ( keys.length - 1 === i ) {
|
|
178
|
+
nested[mod] = value;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
nested = nested[mod];
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
return target;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Unset nested value (mutates)
|
|
189
|
+
*
|
|
190
|
+
* @example Obj.unset({a:{b:1}}, "a.b")
|
|
191
|
+
* @example Obj.unset({a:{b:1}}, ["a","b"])
|
|
192
|
+
*
|
|
193
|
+
* @param {any} target Target object
|
|
194
|
+
* @param {any} keys Key path
|
|
195
|
+
* @param {boolean} [flatten] Flatten keys
|
|
196
|
+
* @returns {any} Mutated target
|
|
197
|
+
*/
|
|
198
|
+
static unset(target, keys, flatten = false)
|
|
199
|
+
{
|
|
200
|
+
if ( keys == null ) {
|
|
201
|
+
return target;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
if ( typeof keys === 'number' ) {
|
|
205
|
+
keys = Mix.str(keys);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const isstr = typeof keys === 'string';
|
|
209
|
+
|
|
210
|
+
if ( isstr && target && target[keys] !== undefined ) {
|
|
211
|
+
return (delete target[keys], target);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
keys = this.keyoptim(keys, flatten, isstr);
|
|
215
|
+
|
|
216
|
+
let [list, index, length, nested] = [
|
|
217
|
+
keys.pop(), 0, keys.length, target
|
|
218
|
+
];
|
|
219
|
+
|
|
220
|
+
if ( length === 0 ) {
|
|
221
|
+
return target;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
while ( nested != null && index < length ) {
|
|
225
|
+
nested = nested[keys[index ++]];
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
if ( nested == null ) {
|
|
229
|
+
return target;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
return (delete nested[list], target);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Check if nested value is empty
|
|
237
|
+
*
|
|
238
|
+
* @example Obj.empty({a:null}, "a") // => true
|
|
239
|
+
* @example Obj.empty({a:1}, "a") // => false
|
|
240
|
+
*
|
|
241
|
+
* @param {any} target Target object
|
|
242
|
+
* @param {any} key Key path
|
|
243
|
+
* @returns {boolean} True if empty
|
|
244
|
+
*/
|
|
245
|
+
static empty(target, key)
|
|
246
|
+
{
|
|
247
|
+
return Mix.isEmpty(this.get(target, key));
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Unset multiple keys (mutates)
|
|
252
|
+
*
|
|
253
|
+
* @example Obj.remove({a:1,b:2}, ["a"]) // => object
|
|
254
|
+
*
|
|
255
|
+
* @param {any} target Target object
|
|
256
|
+
* @param {any} keys Keys list
|
|
257
|
+
* @returns {any} Mutated target
|
|
258
|
+
*/
|
|
259
|
+
static remove(target, keys)
|
|
260
|
+
{
|
|
261
|
+
if ( ! Mix.isArr(keys) ) {
|
|
262
|
+
return target;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
for ( let key of keys ) {
|
|
266
|
+
this.unset(target, key);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
return target;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Map object values to object
|
|
274
|
+
*
|
|
275
|
+
* @example Obj.each({a:1}, v => v+1) // => {a:2}
|
|
276
|
+
*
|
|
277
|
+
* @param {any} value Source object
|
|
278
|
+
* @param {function} cb Map callback
|
|
279
|
+
* @param {any} [retval] Forced return
|
|
280
|
+
* @returns {any} Mapped object
|
|
281
|
+
*/
|
|
282
|
+
static each(value, cb, retval = null)
|
|
283
|
+
{
|
|
284
|
+
let result = {};
|
|
285
|
+
|
|
286
|
+
for ( let key of Mix.keys(value) ) {
|
|
287
|
+
result[key] = cb(value[key], key);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
if ( retval != null ) {
|
|
291
|
+
return retval;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
return result;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* Map object values to object
|
|
299
|
+
*
|
|
300
|
+
* @example Obj.map({a:1}, v => v+1) // => {a:2}
|
|
301
|
+
*
|
|
302
|
+
* @param {any} value Source object
|
|
303
|
+
* @param {function} cb Map callback
|
|
304
|
+
* @returns {Record<string, any>} Mapped object
|
|
305
|
+
*/
|
|
306
|
+
static map(value, cb)
|
|
307
|
+
{
|
|
308
|
+
let result = {};
|
|
309
|
+
|
|
310
|
+
for ( let key of Mix.keys(value) ) {
|
|
311
|
+
result[key] = cb(value[key], key);
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
return result;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* Get filtered key indexes
|
|
319
|
+
*
|
|
320
|
+
* @example Obj.filterIndex({a:1,b:null}) // => ["a"]
|
|
321
|
+
*
|
|
322
|
+
* @param {any} value Source object
|
|
323
|
+
* @param {any} [filter] Filter spec
|
|
324
|
+
* @returns {Array<any>} Key list
|
|
325
|
+
*/
|
|
326
|
+
static filterIndex(value, filter = null)
|
|
327
|
+
{
|
|
328
|
+
return Arr.filterIndex(value, filter);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/**
|
|
332
|
+
* Filter object by key filter
|
|
333
|
+
*
|
|
334
|
+
* @example Obj.filter({a:1,b:null}) // => {a:1}
|
|
335
|
+
*
|
|
336
|
+
* @param {any} value Source object
|
|
337
|
+
* @param {any} [filter] Filter spec
|
|
338
|
+
* @returns {Record<string, any>} Filtered object
|
|
339
|
+
*/
|
|
340
|
+
static filter(value, filter = null)
|
|
341
|
+
{
|
|
342
|
+
let result = {};
|
|
343
|
+
|
|
344
|
+
for (let key of this.filterIndex(value, filter)) {
|
|
345
|
+
result[key] = value[key];
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
return result;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/**
|
|
352
|
+
* Flatten object into dot keys
|
|
353
|
+
*
|
|
354
|
+
* @example Obj.flatten({a:{b:1}}) // => {"a.b":1}
|
|
355
|
+
*
|
|
356
|
+
* @param {any} value Source object
|
|
357
|
+
* @param {string} [prefix] Key prefix
|
|
358
|
+
* @param {Record<string, any>} [result] Result map
|
|
359
|
+
* @returns {Record<string, any>} Flat map
|
|
360
|
+
*/
|
|
361
|
+
static flatten(value, prefix = '', result = {})
|
|
362
|
+
{
|
|
363
|
+
if ( typeof value !== 'object' ) {
|
|
364
|
+
return result[prefix] = value;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
if ( prefix !== '' ) {
|
|
368
|
+
prefix += '.';
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
for ( let key of Mix.keys(value) ) {
|
|
372
|
+
this.flatten(value[key], prefix + key, result);
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
return result;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
/**
|
|
379
|
+
* Flatten object into form keys
|
|
380
|
+
*
|
|
381
|
+
* @example Obj.flattenForm({a:{b:1}}) // => {"a[b]":1}
|
|
382
|
+
*
|
|
383
|
+
* @param {any} value Source object
|
|
384
|
+
* @param {string} [prefix] Key prefix
|
|
385
|
+
* @param {Record<string, any>} [result] Result map
|
|
386
|
+
* @returns {Record<string, any>} Flat map
|
|
387
|
+
*/
|
|
388
|
+
static flattenForm(value, prefix = '', result = {})
|
|
389
|
+
{
|
|
390
|
+
if ( typeof value !== 'object' ) {
|
|
391
|
+
return result[prefix] = value;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
let fn = (key) => {
|
|
395
|
+
return prefix ? `${prefix}[${key}]` : key;
|
|
396
|
+
};
|
|
397
|
+
|
|
398
|
+
for ( let key of Mix.keys(value) ) {
|
|
399
|
+
this.flattenForm(value[key], fn(key), result);
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
return result;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
/**
|
|
406
|
+
* Unpack dotted keys into object
|
|
407
|
+
*
|
|
408
|
+
* @example Obj.unpack({"a.b":1}) // => {a:{b:1}}
|
|
409
|
+
*
|
|
410
|
+
* @param {any} value Flat key map
|
|
411
|
+
* @param {Record<string, any>} [result] Result object
|
|
412
|
+
* @returns {Record<string, any>} Unpacked object
|
|
413
|
+
*/
|
|
414
|
+
static unpack(value, result = {})
|
|
415
|
+
{
|
|
416
|
+
Arr.each(Mix.keys(value), (key) => {
|
|
417
|
+
this.set(result, key, value[key]);
|
|
418
|
+
});
|
|
419
|
+
|
|
420
|
+
return result;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
/**
|
|
424
|
+
* Assign objects (Object.assign)
|
|
425
|
+
*
|
|
426
|
+
* @example Obj.assign({}, {a:1}) // => {a:1}
|
|
427
|
+
*
|
|
428
|
+
* @param {...any} args Assign args
|
|
429
|
+
* @returns {any} Assigned object
|
|
430
|
+
*/
|
|
431
|
+
static assign(...args)
|
|
432
|
+
{
|
|
433
|
+
return Object.assign(...args);
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
/**
|
|
437
|
+
* Deep clone primitive/array/object
|
|
438
|
+
*
|
|
439
|
+
* @example Obj.clone({a:{b:1}}) // => new object
|
|
440
|
+
*
|
|
441
|
+
* @param {any} value Value to clone
|
|
442
|
+
* @param {any} [merge] Merge values
|
|
443
|
+
* @returns {any} Cloned value
|
|
444
|
+
*/
|
|
445
|
+
static clone(value, merge = null)
|
|
446
|
+
{
|
|
447
|
+
if ( Mix.isPrim(value) ) {
|
|
448
|
+
return value;
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
if ( Mix.isArr(value) ) {
|
|
452
|
+
return Arr.clone(value);
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
if ( ! Mix.isObj(value) ) {
|
|
456
|
+
return value;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
let result = {};
|
|
460
|
+
|
|
461
|
+
for ( let key of Mix.keys(value) ) {
|
|
462
|
+
result[key] = this.clone(value[key]);
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
if ( merge != null ) {
|
|
466
|
+
return this.assign(result, merge);
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
return result;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
/**
|
|
473
|
+
* Get and remove nested value
|
|
474
|
+
*
|
|
475
|
+
* @example Obj.pluck({a:1}, "a") // => 1
|
|
476
|
+
*
|
|
477
|
+
* @param {any} value Source object
|
|
478
|
+
* @param {any} key Key path
|
|
479
|
+
* @param {any} [fallback] Fallback value
|
|
480
|
+
* @returns {any} Plucked value
|
|
481
|
+
*/
|
|
482
|
+
static pluck(value, key, fallback = null)
|
|
483
|
+
{
|
|
484
|
+
let result = this.get(value, key, fallback);
|
|
485
|
+
|
|
486
|
+
this.unset(value, key);
|
|
487
|
+
|
|
488
|
+
return result;
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
/**
|
|
492
|
+
* Pick only given keys
|
|
493
|
+
*
|
|
494
|
+
* @example Obj.only({a:1,b:2}, ["a"]) // => {a:1}
|
|
495
|
+
*
|
|
496
|
+
* @param {any} value Source object
|
|
497
|
+
* @param {Array<any>} keys Allowed keys
|
|
498
|
+
* @param {any} [merge] Merge values
|
|
499
|
+
* @returns {Record<string, any>} Picked object
|
|
500
|
+
*/
|
|
501
|
+
static only(value, keys, merge = null)
|
|
502
|
+
{
|
|
503
|
+
let result = {};
|
|
504
|
+
|
|
505
|
+
this.each(value, (val, key) => {
|
|
506
|
+
if ( Arr.has(keys, key) ) result[key] = val;
|
|
507
|
+
});
|
|
508
|
+
|
|
509
|
+
if ( merge == null ) {
|
|
510
|
+
return result;
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
return this.assign(result, merge);
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
/**
|
|
517
|
+
* Pick all keys except given
|
|
518
|
+
*
|
|
519
|
+
* @example Obj.except({a:1,b:2}, ["a"]) // => {b:2}
|
|
520
|
+
*
|
|
521
|
+
* @param {any} value Source object
|
|
522
|
+
* @param {Array<any>} keys Excluded keys
|
|
523
|
+
* @param {any} [merge] Merge values
|
|
524
|
+
* @returns {Record<string, any>} Picked object
|
|
525
|
+
*/
|
|
526
|
+
static except(value, keys, merge = null)
|
|
527
|
+
{
|
|
528
|
+
let result = {};
|
|
529
|
+
|
|
530
|
+
this.each(value, (val, key) => {
|
|
531
|
+
if ( ! Arr.has(keys, key) ) result[key] = val;
|
|
532
|
+
});
|
|
533
|
+
|
|
534
|
+
if ( merge == null ) {
|
|
535
|
+
return result;
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
return this.assign(result, merge);
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
/**
|
|
542
|
+
* Check if value includes search
|
|
543
|
+
*
|
|
544
|
+
* @example Obj.includes({a:1}, {a:1}) // => true
|
|
545
|
+
* @example Obj.includes({a:1}, {a:2}) // => false
|
|
546
|
+
*
|
|
547
|
+
* @param {any} value Source value
|
|
548
|
+
* @param {any} search Search spec
|
|
549
|
+
* @returns {boolean} True if includes
|
|
550
|
+
*/
|
|
551
|
+
static includes(value, search)
|
|
552
|
+
{
|
|
553
|
+
if ( Mix.isArr(search) ) {
|
|
554
|
+
return Arr.includes(value, search);
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
if ( ! Mix.isObj(search) ) {
|
|
558
|
+
return value === search;
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
let keys = Mix.keys(search);
|
|
562
|
+
|
|
563
|
+
let [result, length] = [
|
|
564
|
+
true, keys.length,
|
|
565
|
+
];
|
|
566
|
+
|
|
567
|
+
for ( let i = 0; result === true && i < length; i++) {
|
|
568
|
+
result = this.includes(...[
|
|
569
|
+
value[keys[i]], search[keys[i]]
|
|
570
|
+
]);
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
return result;
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
/**
|
|
577
|
+
* Check if value matches search
|
|
578
|
+
*
|
|
579
|
+
* @example Obj.matches({a:1}, {a:1}) // => true
|
|
580
|
+
* @example Obj.matches({a:1}, {b:1}) // => false
|
|
581
|
+
*
|
|
582
|
+
* @param {any} value Source value
|
|
583
|
+
* @param {any} search Search spec
|
|
584
|
+
* @returns {boolean} True if matches
|
|
585
|
+
*/
|
|
586
|
+
static matches(value, search)
|
|
587
|
+
{
|
|
588
|
+
if ( Mix.isArr(search) ) {
|
|
589
|
+
return Arr.matches(value, search);
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
if ( ! Mix.isObj(value) ) {
|
|
593
|
+
return value === search;
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
let keys = Arr.unique([
|
|
597
|
+
...Mix.keys(search), ...Mix.keys(value)
|
|
598
|
+
]);
|
|
599
|
+
|
|
600
|
+
let [result, length] = [
|
|
601
|
+
true, keys.length,
|
|
602
|
+
];
|
|
603
|
+
|
|
604
|
+
for ( let i = 0; result === true && i < length; i++) {
|
|
605
|
+
result &&= this.matches(...[
|
|
606
|
+
value[keys[i]], search[keys[i]]
|
|
607
|
+
]);
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
return result;
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
/**
|
|
616
|
+
* @see PicoMixed.vals
|
|
617
|
+
*/
|
|
618
|
+
PicoObject.values = (...args) => {
|
|
619
|
+
console.warn('Obj.values() is deprecated, use Mix.vals() instead.');
|
|
620
|
+
return Mix.vals(...args);
|
|
621
|
+
};
|
|
622
|
+
|
|
623
|
+
/**
|
|
624
|
+
* @see PicoArray.find
|
|
625
|
+
*/
|
|
626
|
+
PicoObject.find = (...args) => {
|
|
627
|
+
console.warn('Obj.find() is deprecated, use Arr.find() instead.');
|
|
628
|
+
return Arr.find(...args);
|
|
629
|
+
};
|
|
630
|
+
|
|
631
|
+
/**
|
|
632
|
+
* @see PicoArray.findIndex
|
|
633
|
+
*/
|
|
634
|
+
PicoObject.findIndex = (...args) => {
|
|
635
|
+
console.warn('Obj.findIndex() is deprecated, use Arr.findIndex() instead.');
|
|
636
|
+
return Arr.findIndex(...args);
|
|
637
|
+
};
|
|
638
|
+
|
|
639
|
+
/**
|
|
640
|
+
* @see PicoArray.sort
|
|
641
|
+
*/
|
|
642
|
+
PicoObject.sort = (...args) => {
|
|
643
|
+
console.warn('Obj.sort() is deprecated, use Arr.sort() instead.');
|
|
644
|
+
return Arr.sort(...args);
|
|
645
|
+
};
|
|
646
|
+
|
|
647
|
+
/**
|
|
648
|
+
* @see PicoArray.sortDeep
|
|
649
|
+
*/
|
|
650
|
+
PicoObject.sortString = (...args) => {
|
|
651
|
+
console.warn('Obj.sortString() is deprecated, use Arr.sortDeep() instead.');
|
|
652
|
+
return Arr.sortDeep(...args);
|
|
653
|
+
};
|
|
654
|
+
|
|
655
|
+
export default PicoObject
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { Arr, For, Locale, Mix, Obj } from "#src/index.esm.js";
|
|
2
|
+
|
|
3
|
+
export class PicoRoute
|
|
4
|
+
{
|
|
5
|
+
|
|
6
|
+
static $routes = {};
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Store route template by key
|
|
10
|
+
*
|
|
11
|
+
* @example Route.set("home", "/") // stores
|
|
12
|
+
*
|
|
13
|
+
* @param {string} key Route key
|
|
14
|
+
* @param {string} value Route template
|
|
15
|
+
* @returns {void} No return value
|
|
16
|
+
*/
|
|
17
|
+
static set(key, value)
|
|
18
|
+
{
|
|
19
|
+
this.$routes[key] = value;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Build route URL from template
|
|
24
|
+
*
|
|
25
|
+
* @example Route.get("home") // => "/"
|
|
26
|
+
* @example Route.get("/u/:id", {id:1}) // => "/u/1"
|
|
27
|
+
*
|
|
28
|
+
* @param {string} key Route key or url
|
|
29
|
+
* @param {any} [values] Token values
|
|
30
|
+
* @param {any} [query] Query params
|
|
31
|
+
* @returns {string} Built url
|
|
32
|
+
*/
|
|
33
|
+
static get(key, values = null, query = null)
|
|
34
|
+
{
|
|
35
|
+
let route = key;
|
|
36
|
+
|
|
37
|
+
if ( ! /^https?:\/\//.test(route) ) {
|
|
38
|
+
route = this.$routes[key] || key
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
route = Locale.replace(route, values);
|
|
42
|
+
|
|
43
|
+
if ( ! Mix.isEmpty(query) ) {
|
|
44
|
+
route += '?' + For.castParams(values);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return route;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Navigate to built route URL
|
|
52
|
+
*
|
|
53
|
+
* @example Route.goto("home")
|
|
54
|
+
*
|
|
55
|
+
* @param {string} key Route key or url
|
|
56
|
+
* @param {any} [values] Token values
|
|
57
|
+
* @param {any} [params] Query params
|
|
58
|
+
* @returns {void} No return value
|
|
59
|
+
*/
|
|
60
|
+
static goto(key, values = null, params = null)
|
|
61
|
+
{
|
|
62
|
+
window.location.href = this.get(key, values, params);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export default PicoRoute;
|