@gesslar/toolkit 0.1.6 → 0.2.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/package.json +1 -1
- package/src/lib/Data.js +43 -35
- package/src/lib/TypeSpec.js +9 -6
package/package.json
CHANGED
package/src/lib/Data.js
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
import Sass from "./Sass.js"
|
|
10
10
|
import TypeSpec from "./TypeSpec.js"
|
|
11
|
+
import Util from "./Util.js"
|
|
11
12
|
import Valid from "./Valid.js"
|
|
12
13
|
|
|
13
14
|
export default class Data {
|
|
@@ -19,17 +20,17 @@ export default class Data {
|
|
|
19
20
|
*/
|
|
20
21
|
static primitives = Object.freeze([
|
|
21
22
|
// Primitives
|
|
22
|
-
"
|
|
23
|
-
"
|
|
24
|
-
"
|
|
25
|
-
"
|
|
26
|
-
"
|
|
27
|
-
"
|
|
28
|
-
"
|
|
23
|
+
"Undefined",
|
|
24
|
+
"Null",
|
|
25
|
+
"Boolean",
|
|
26
|
+
"Number",
|
|
27
|
+
"Bigint",
|
|
28
|
+
"String",
|
|
29
|
+
"Symbol",
|
|
29
30
|
|
|
30
31
|
// Object Categories from typeof
|
|
31
|
-
"
|
|
32
|
-
"
|
|
32
|
+
"Object",
|
|
33
|
+
"Function",
|
|
33
34
|
])
|
|
34
35
|
|
|
35
36
|
/**
|
|
@@ -67,7 +68,7 @@ export default class Data {
|
|
|
67
68
|
*/
|
|
68
69
|
static dataTypes = Object.freeze([
|
|
69
70
|
...Data.primitives,
|
|
70
|
-
...Data.constructors
|
|
71
|
+
...Data.constructors
|
|
71
72
|
])
|
|
72
73
|
|
|
73
74
|
/**
|
|
@@ -76,7 +77,7 @@ export default class Data {
|
|
|
76
77
|
*
|
|
77
78
|
* @type {Array<string>}
|
|
78
79
|
*/
|
|
79
|
-
static emptyableTypes = Object.freeze(["
|
|
80
|
+
static emptyableTypes = Object.freeze(["String", "Array", "Object"])
|
|
80
81
|
|
|
81
82
|
/**
|
|
82
83
|
* Appends a string to another string if it does not already end with it.
|
|
@@ -109,8 +110,11 @@ export default class Data {
|
|
|
109
110
|
* @returns {boolean} Whether all elements are of the specified type
|
|
110
111
|
*/
|
|
111
112
|
static isArrayUniform(arr, type) {
|
|
113
|
+
const checkType = type ? Util.capitalize(type) : null
|
|
114
|
+
|
|
112
115
|
return arr.every(
|
|
113
|
-
(item, _index, arr) =>
|
|
116
|
+
(item, _index, arr) =>
|
|
117
|
+
Data.typeOf(item) === (checkType || Data.typeOf(arr[0])),
|
|
114
118
|
)
|
|
115
119
|
}
|
|
116
120
|
|
|
@@ -197,10 +201,10 @@ export default class Data {
|
|
|
197
201
|
const result = {}
|
|
198
202
|
|
|
199
203
|
for(const [key, value] of Object.entries(obj)) {
|
|
200
|
-
if(Data.isType(value, "
|
|
204
|
+
if(Data.isType(value, "Array")) {
|
|
201
205
|
// Clone arrays by mapping over them
|
|
202
206
|
result[key] = value.map(item =>
|
|
203
|
-
Data.isType(item, "object") || Data.isType(item, "
|
|
207
|
+
Data.isType(item, "object") || Data.isType(item, "Array")
|
|
204
208
|
? Data.cloneObject(item)
|
|
205
209
|
: item
|
|
206
210
|
)
|
|
@@ -227,25 +231,25 @@ export default class Data {
|
|
|
227
231
|
workSpec = [],
|
|
228
232
|
result = {}
|
|
229
233
|
|
|
230
|
-
if(!Data.isType(source, "
|
|
234
|
+
if(!Data.isType(source, "Array", {allowEmpty: false}))
|
|
231
235
|
throw Sass.new("Source must be an array.")
|
|
232
236
|
|
|
233
237
|
workSource.push(...source)
|
|
234
238
|
|
|
235
239
|
if(
|
|
236
|
-
!Data.isType(spec, "
|
|
240
|
+
!Data.isType(spec, "Array", {allowEmpty: false}) &&
|
|
237
241
|
!Data.isType(spec, "function")
|
|
238
242
|
)
|
|
239
243
|
throw Sass.new("Spec must be an array or a function.")
|
|
240
244
|
|
|
241
|
-
if(Data.isType(spec, "
|
|
245
|
+
if(Data.isType(spec, "Function")) {
|
|
242
246
|
const specResult = await spec(workSource)
|
|
243
247
|
|
|
244
|
-
if(!Data.isType(specResult, "
|
|
248
|
+
if(!Data.isType(specResult, "Array"))
|
|
245
249
|
throw Sass.new("Spec resulting from function must be an array.")
|
|
246
250
|
|
|
247
251
|
workSpec.push(...specResult)
|
|
248
|
-
} else if(Data.isType(spec, "
|
|
252
|
+
} else if(Data.isType(spec, "Array", {allowEmpty: false})) {
|
|
249
253
|
workSpec.push(...spec)
|
|
250
254
|
}
|
|
251
255
|
|
|
@@ -256,7 +260,7 @@ export default class Data {
|
|
|
256
260
|
workSource.map((element, index, arr) => (arr[index] = String(element)))
|
|
257
261
|
|
|
258
262
|
// Check that all keys are strings
|
|
259
|
-
if(!Data.isArrayUniform(workSource, "
|
|
263
|
+
if(!Data.isArrayUniform(workSource, "String"))
|
|
260
264
|
throw Sass.new("Indices of an Object must be of type string.")
|
|
261
265
|
|
|
262
266
|
workSource.forEach((element, index) => (result[element] = workSpec[index]))
|
|
@@ -332,7 +336,13 @@ export default class Data {
|
|
|
332
336
|
* @returns {boolean} Whether the type is valid
|
|
333
337
|
*/
|
|
334
338
|
static isValidType(type) {
|
|
335
|
-
|
|
339
|
+
// Allow built-in types
|
|
340
|
+
if(Data.dataTypes.includes(type)) {
|
|
341
|
+
return true
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
// Allow custom classes (PascalCase starting with capital letter)
|
|
345
|
+
return /^[A-Z][a-zA-Z0-9]*$/.test(type)
|
|
336
346
|
}
|
|
337
347
|
|
|
338
348
|
/**
|
|
@@ -349,16 +359,13 @@ export default class Data {
|
|
|
349
359
|
return false
|
|
350
360
|
|
|
351
361
|
const valueType = Data.typeOf(value)
|
|
352
|
-
const normalizedType = type.toLowerCase()
|
|
353
362
|
|
|
354
363
|
// Special cases that need extra validation
|
|
355
|
-
switch(
|
|
356
|
-
case "
|
|
357
|
-
return valueType === "
|
|
358
|
-
case "object":
|
|
359
|
-
return valueType === "object" && value !== null && !Array.isArray(value) // Excludes arrays and null
|
|
364
|
+
switch(valueType) {
|
|
365
|
+
case "Number":
|
|
366
|
+
return valueType === "Number" && !isNaN(value) // Excludes NaN
|
|
360
367
|
default:
|
|
361
|
-
return valueType ===
|
|
368
|
+
return valueType === type
|
|
362
369
|
}
|
|
363
370
|
}
|
|
364
371
|
|
|
@@ -370,12 +377,13 @@ export default class Data {
|
|
|
370
377
|
*/
|
|
371
378
|
static typeOf(value) {
|
|
372
379
|
if(value === null)
|
|
373
|
-
return "
|
|
380
|
+
return "Null"
|
|
374
381
|
|
|
375
|
-
|
|
376
|
-
return "array"
|
|
382
|
+
const type = typeof value
|
|
377
383
|
|
|
378
|
-
return
|
|
384
|
+
return type === "object"
|
|
385
|
+
? value.constructor.name
|
|
386
|
+
: type.charAt(0).toUpperCase() + type.slice(1)
|
|
379
387
|
}
|
|
380
388
|
|
|
381
389
|
/**
|
|
@@ -412,12 +420,12 @@ export default class Data {
|
|
|
412
420
|
return false
|
|
413
421
|
|
|
414
422
|
switch(type) {
|
|
415
|
-
case "
|
|
423
|
+
case "Array":
|
|
416
424
|
return value.length === 0
|
|
417
|
-
case "
|
|
425
|
+
case "Object":
|
|
418
426
|
// null was already handled above, so this should only be real objects
|
|
419
427
|
return Object.keys(value).length === 0
|
|
420
|
-
case "
|
|
428
|
+
case "String":
|
|
421
429
|
return value.trim().length === 0
|
|
422
430
|
default:
|
|
423
431
|
return false
|
package/src/lib/TypeSpec.js
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
import Sass from "./Sass.js"
|
|
8
8
|
import Data from "./Data.js"
|
|
9
|
+
import Util from "./Util.js"
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* Type specification class for parsing and validating complex type definitions.
|
|
@@ -149,7 +150,7 @@ export default class TypeSpec {
|
|
|
149
150
|
// Now, let's do some checking with the types, respecting the array flag
|
|
150
151
|
// with the value
|
|
151
152
|
const valueType = Data.typeOf(value)
|
|
152
|
-
const isArray = valueType === "
|
|
153
|
+
const isArray = valueType === "Array"
|
|
153
154
|
|
|
154
155
|
// We need to ensure that we match the type and the consistency of the types
|
|
155
156
|
// in an array, if it is an array and an array is allowed.
|
|
@@ -166,8 +167,8 @@ export default class TypeSpec {
|
|
|
166
167
|
|
|
167
168
|
// Handle array values
|
|
168
169
|
if(isArray) {
|
|
169
|
-
// Special case for generic "
|
|
170
|
-
if(allowedType === "
|
|
170
|
+
// Special case for generic "Array" type
|
|
171
|
+
if(allowedType === "Array" && !allowedArray)
|
|
171
172
|
return allowEmpty || !empty
|
|
172
173
|
|
|
173
174
|
// Must be an array type specification
|
|
@@ -203,16 +204,18 @@ export default class TypeSpec {
|
|
|
203
204
|
const parts = string.split(delimiter)
|
|
204
205
|
|
|
205
206
|
this.#specs = parts.map(part => {
|
|
206
|
-
const typeMatches =
|
|
207
|
+
const typeMatches = /^(\w+)(\[\])?$/.exec(part)
|
|
207
208
|
|
|
208
209
|
if(!typeMatches || typeMatches.length !== 3)
|
|
209
210
|
throw Sass.new(`Invalid type: ${part}`)
|
|
210
211
|
|
|
211
|
-
|
|
212
|
+
const typeName = Util.capitalize(typeMatches[1])
|
|
213
|
+
|
|
214
|
+
if(!Data.isValidType(typeName))
|
|
212
215
|
throw Sass.new(`Invalid type: ${typeMatches[1]}`)
|
|
213
216
|
|
|
214
217
|
return {
|
|
215
|
-
typeName
|
|
218
|
+
typeName,
|
|
216
219
|
array: typeMatches[2] === "[]",
|
|
217
220
|
}
|
|
218
221
|
})
|