bare-script 2.3.2 → 3.0.1
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 +22 -4
- package/bin/bare.js +3 -16
- package/bin/baredoc.js +3 -16
- package/lib/bare.js +87 -84
- package/lib/baredoc.js +133 -59
- package/lib/data.js +155 -158
- package/lib/library.js +794 -291
- package/lib/model.js +3 -3
- package/lib/options.js +72 -0
- package/lib/optionsNode.js +70 -0
- package/lib/parser.js +72 -70
- package/lib/runtime.js +107 -88
- package/lib/runtimeAsync.js +112 -87
- package/lib/value.js +287 -0
- package/package.json +2 -2
package/lib/library.js
CHANGED
|
@@ -2,10 +2,12 @@
|
|
|
2
2
|
// https://github.com/craigahobbs/bare-script/blob/main/LICENSE
|
|
3
3
|
|
|
4
4
|
import {
|
|
5
|
-
addCalculatedField, aggregateData, filterData, joinData, parseCSV,
|
|
5
|
+
addCalculatedField, aggregateData, filterData, joinData, parseCSV, sortData, topData, validateData
|
|
6
6
|
} from './data.js';
|
|
7
7
|
import {validateType, validateTypeModel} from 'schema-markdown/lib/schema.js';
|
|
8
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
valueBoolean, valueCompare, valueIs, valueJSON, valueParseDatetime, valueParseInteger, valueParseNumber, valueString, valueType
|
|
10
|
+
} from './value.js';
|
|
9
11
|
import {parseSchemaMarkdown} from 'schema-markdown/lib/parser.js';
|
|
10
12
|
import {typeModel} from 'schema-markdown/lib/typeModel.js';
|
|
11
13
|
|
|
@@ -27,8 +29,12 @@ export const defaultMaxStatements = 1e9;
|
|
|
27
29
|
// $doc: Create a copy of an array
|
|
28
30
|
// $arg array: The array to copy
|
|
29
31
|
// $return: The array copy
|
|
30
|
-
function arrayCopy([array]) {
|
|
31
|
-
|
|
32
|
+
function arrayCopy([array = null]) {
|
|
33
|
+
if (valueType(array) !== 'array') {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return [...array];
|
|
32
38
|
}
|
|
33
39
|
|
|
34
40
|
|
|
@@ -38,10 +44,12 @@ function arrayCopy([array]) {
|
|
|
38
44
|
// $arg array: The array to extend
|
|
39
45
|
// $arg array2: The array to extend with
|
|
40
46
|
// $return: The extended array
|
|
41
|
-
function arrayExtend([array, array2]) {
|
|
42
|
-
if (
|
|
43
|
-
|
|
47
|
+
function arrayExtend([array = null, array2 = null]) {
|
|
48
|
+
if (valueType(array) !== 'array' || valueType(array2) !== 'array') {
|
|
49
|
+
return null;
|
|
44
50
|
}
|
|
51
|
+
|
|
52
|
+
array.push(...array2);
|
|
45
53
|
return array;
|
|
46
54
|
}
|
|
47
55
|
|
|
@@ -52,8 +60,13 @@ function arrayExtend([array, array2]) {
|
|
|
52
60
|
// $arg array: The array
|
|
53
61
|
// $arg index: The array element's index
|
|
54
62
|
// $return: The array element
|
|
55
|
-
function arrayGet([array, index]) {
|
|
56
|
-
|
|
63
|
+
function arrayGet([array = null, index = null]) {
|
|
64
|
+
if (valueType(array) !== 'array' ||
|
|
65
|
+
valueType(index) !== 'number' || Math.floor(index) !== index || index < 0 || index >= array.length) {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return array[index];
|
|
57
70
|
}
|
|
58
71
|
|
|
59
72
|
|
|
@@ -61,11 +74,24 @@ function arrayGet([array, index]) {
|
|
|
61
74
|
// $group: Array
|
|
62
75
|
// $doc: Find the index of a value in an array
|
|
63
76
|
// $arg array: The array
|
|
64
|
-
// $arg value: The value to find in the array
|
|
77
|
+
// $arg value: The value to find in the array, or a match function, f(value) -> bool
|
|
65
78
|
// $arg index: Optional (default is 0). The index at which to start the search.
|
|
66
79
|
// $return: The first index of the value in the array; -1 if not found.
|
|
67
|
-
function arrayIndexOf([array, value, index = 0]) {
|
|
68
|
-
|
|
80
|
+
function arrayIndexOf([array = null, value = null, index = 0], options) {
|
|
81
|
+
if (valueType(array) !== 'array' ||
|
|
82
|
+
valueType(index) !== 'number' || Math.floor(index) !== index || index < 0 || index >= array.length) {
|
|
83
|
+
return -1;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (valueType(value) === 'function') {
|
|
87
|
+
for (let ix = index; ix < array.length; ix += 1) {
|
|
88
|
+
if (valueBoolean(value([array[ix]], options))) {
|
|
89
|
+
return ix;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return array.indexOf(value, index);
|
|
69
95
|
}
|
|
70
96
|
|
|
71
97
|
|
|
@@ -75,8 +101,12 @@ function arrayIndexOf([array, value, index = 0]) {
|
|
|
75
101
|
// $arg array: The array
|
|
76
102
|
// $arg separator: The separator string
|
|
77
103
|
// $return: The joined string
|
|
78
|
-
function arrayJoin([array, separator]) {
|
|
79
|
-
|
|
104
|
+
function arrayJoin([array = null, separator = null]) {
|
|
105
|
+
if (valueType(array) !== 'array' || valueType(separator) !== 'string') {
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return array.map((value) => valueString(value)).join(separator);
|
|
80
110
|
}
|
|
81
111
|
|
|
82
112
|
|
|
@@ -84,11 +114,28 @@ function arrayJoin([array, separator]) {
|
|
|
84
114
|
// $group: Array
|
|
85
115
|
// $doc: Find the last index of a value in an array
|
|
86
116
|
// $arg array: The array
|
|
87
|
-
// $arg value: The value to find in the array
|
|
117
|
+
// $arg value: The value to find in the array, or a match function, f(value) -> bool
|
|
88
118
|
// $arg index: Optional (default is the end of the array). The index at which to start the search.
|
|
89
119
|
// $return: The last index of the value in the array; -1 if not found.
|
|
90
|
-
function arrayLastIndexOf([array, value,
|
|
91
|
-
|
|
120
|
+
function arrayLastIndexOf([array = null, value = null, indexArg = null], options) {
|
|
121
|
+
let index = indexArg;
|
|
122
|
+
if (valueType(array) === 'array' && index === null) {
|
|
123
|
+
index = array.length - 1;
|
|
124
|
+
}
|
|
125
|
+
if (valueType(array) !== 'array' ||
|
|
126
|
+
valueType(index) !== 'number' || Math.floor(index) !== index || index < 0 || index >= array.length) {
|
|
127
|
+
return -1;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (valueType(value) === 'function') {
|
|
131
|
+
for (let ix = index; ix >= 0; ix -= 1) {
|
|
132
|
+
if (valueBoolean(value([array[ix]], options))) {
|
|
133
|
+
return ix;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return array.lastIndexOf(value, index);
|
|
92
139
|
}
|
|
93
140
|
|
|
94
141
|
|
|
@@ -96,9 +143,13 @@ function arrayLastIndexOf([array, value, index = null]) {
|
|
|
96
143
|
// $group: Array
|
|
97
144
|
// $doc: Get the length of an array
|
|
98
145
|
// $arg array: The array
|
|
99
|
-
// $return: The array's length;
|
|
100
|
-
function arrayLength([array]) {
|
|
101
|
-
|
|
146
|
+
// $return: The array's length; zero if not an array
|
|
147
|
+
function arrayLength([array = null]) {
|
|
148
|
+
if (valueType(array) !== 'array') {
|
|
149
|
+
return 0;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
return array.length;
|
|
102
153
|
}
|
|
103
154
|
|
|
104
155
|
|
|
@@ -119,6 +170,10 @@ function arrayNew(values) {
|
|
|
119
170
|
// $arg value: Optional (default is 0). The value with which to fill the new array.
|
|
120
171
|
// $return: The new array
|
|
121
172
|
function arrayNewSize([size = 0, value = 0]) {
|
|
173
|
+
if (valueType(size) !== 'number' || Math.floor(size) !== size || size < 0) {
|
|
174
|
+
return null;
|
|
175
|
+
}
|
|
176
|
+
|
|
122
177
|
return new Array(size).fill(value);
|
|
123
178
|
}
|
|
124
179
|
|
|
@@ -128,8 +183,12 @@ function arrayNewSize([size = 0, value = 0]) {
|
|
|
128
183
|
// $doc: Remove the last element of the array and return it
|
|
129
184
|
// $arg array: The array
|
|
130
185
|
// $return: The last element of the array; null if the array is empty.
|
|
131
|
-
function arrayPop([array]) {
|
|
132
|
-
|
|
186
|
+
function arrayPop([array = null]) {
|
|
187
|
+
if (valueType(array) !== 'array' || array.length === 0) {
|
|
188
|
+
return null;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
return array.pop();
|
|
133
192
|
}
|
|
134
193
|
|
|
135
194
|
|
|
@@ -139,10 +198,12 @@ function arrayPop([array]) {
|
|
|
139
198
|
// $arg array: The array
|
|
140
199
|
// $arg values...: The values to add to the end of the array
|
|
141
200
|
// $return: The array
|
|
142
|
-
function arrayPush([array, ...values]) {
|
|
143
|
-
if (
|
|
144
|
-
|
|
201
|
+
function arrayPush([array = null, ...values]) {
|
|
202
|
+
if (valueType(array) !== 'array') {
|
|
203
|
+
return null;
|
|
145
204
|
}
|
|
205
|
+
|
|
206
|
+
array.push(...values);
|
|
146
207
|
return array;
|
|
147
208
|
}
|
|
148
209
|
|
|
@@ -154,10 +215,13 @@ function arrayPush([array, ...values]) {
|
|
|
154
215
|
// $arg index: The index of the element to set
|
|
155
216
|
// $arg value: The value to set
|
|
156
217
|
// $return: The value
|
|
157
|
-
function arraySet([array, index, value]) {
|
|
158
|
-
if (
|
|
159
|
-
|
|
218
|
+
function arraySet([array = null, index = null, value = null]) {
|
|
219
|
+
if (valueType(array) !== 'array' ||
|
|
220
|
+
valueType(index) !== 'number' || Math.floor(index) !== index || index < 0 || index >= array.length) {
|
|
221
|
+
return null;
|
|
160
222
|
}
|
|
223
|
+
|
|
224
|
+
array[index] = value;
|
|
161
225
|
return value;
|
|
162
226
|
}
|
|
163
227
|
|
|
@@ -167,8 +231,12 @@ function arraySet([array, index, value]) {
|
|
|
167
231
|
// $doc: Remove the first element of the array and return it
|
|
168
232
|
// $arg array: The array
|
|
169
233
|
// $return: The first element of the array; null if the array is empty.
|
|
170
|
-
function arrayShift([array]) {
|
|
171
|
-
|
|
234
|
+
function arrayShift([array = null]) {
|
|
235
|
+
if (valueType(array) !== 'array' || array.length === 0) {
|
|
236
|
+
return null;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
return array.shift();
|
|
172
240
|
}
|
|
173
241
|
|
|
174
242
|
|
|
@@ -179,8 +247,18 @@ function arrayShift([array]) {
|
|
|
179
247
|
// $arg start: Optional (default is 0). The start index of the slice.
|
|
180
248
|
// $arg end: Optional (default is the end of the array). The end index of the slice.
|
|
181
249
|
// $return: The new array slice
|
|
182
|
-
function arraySlice([array, start,
|
|
183
|
-
|
|
250
|
+
function arraySlice([array = null, start = 0, endArg = null]) {
|
|
251
|
+
let end = endArg;
|
|
252
|
+
if (valueType(array) === 'array' && end === null) {
|
|
253
|
+
end = array.length;
|
|
254
|
+
}
|
|
255
|
+
if (valueType(array) !== 'array' ||
|
|
256
|
+
valueType(start) !== 'number' || Math.floor(start) !== start || start < 0 || start > array.length ||
|
|
257
|
+
valueType(end) !== 'number' || Math.floor(end) !== end || end < 0 || end > array.length) {
|
|
258
|
+
return null;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
return array.slice(start, end);
|
|
184
262
|
}
|
|
185
263
|
|
|
186
264
|
|
|
@@ -190,8 +268,15 @@ function arraySlice([array, start, end]) {
|
|
|
190
268
|
// $arg array: The array
|
|
191
269
|
// $arg compareFn: Optional (default is null). The comparison function.
|
|
192
270
|
// $return: The sorted array
|
|
193
|
-
function arraySort([array, compareFn = null], options) {
|
|
194
|
-
|
|
271
|
+
function arraySort([array = null, compareFn = null], options) {
|
|
272
|
+
if (valueType(array) !== 'array' || (compareFn !== null && valueType(compareFn) !== 'function')) {
|
|
273
|
+
return null;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
if (compareFn === null) {
|
|
277
|
+
return array.sort(valueCompare);
|
|
278
|
+
}
|
|
279
|
+
return array.sort((...args) => compareFn(args, options));
|
|
195
280
|
}
|
|
196
281
|
|
|
197
282
|
|
|
@@ -204,10 +289,14 @@ function arraySort([array, compareFn = null], options) {
|
|
|
204
289
|
// $group: Data
|
|
205
290
|
// $doc: Aggregate a data array
|
|
206
291
|
// $arg data: The data array
|
|
207
|
-
// $arg aggregation: The [aggregation model](
|
|
292
|
+
// $arg aggregation: The [aggregation model](model.html#var.vName='Aggregation')
|
|
208
293
|
// $return: The aggregated data array
|
|
209
|
-
function dataAggregate([data, aggregation]) {
|
|
210
|
-
|
|
294
|
+
function dataAggregate([data = null, aggregation = null]) {
|
|
295
|
+
if (valueType(data) !== 'array' || (aggregation !== null && valueType(aggregation) !== 'object')) {
|
|
296
|
+
return null;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
return aggregateData(data, aggregation);
|
|
211
300
|
}
|
|
212
301
|
|
|
213
302
|
|
|
@@ -219,7 +308,12 @@ function dataAggregate([data, aggregation]) {
|
|
|
219
308
|
// $arg expr: The calculated field expression
|
|
220
309
|
// $arg variables: Optional (default is null). A variables object the expression evaluation.
|
|
221
310
|
// $return: The updated data array
|
|
222
|
-
function dataCalculatedField([data, fieldName, expr, variables = null], options) {
|
|
311
|
+
function dataCalculatedField([data = null, fieldName = null, expr = null, variables = null], options) {
|
|
312
|
+
if (valueType(data) !== 'array' || valueType(fieldName) !== 'string' || valueType(expr) !== 'string' ||
|
|
313
|
+
(variables !== null && valueType(variables) !== 'object')) {
|
|
314
|
+
return null;
|
|
315
|
+
}
|
|
316
|
+
|
|
223
317
|
return addCalculatedField(data, fieldName, expr, variables, options);
|
|
224
318
|
}
|
|
225
319
|
|
|
@@ -230,7 +324,11 @@ function dataCalculatedField([data, fieldName, expr, variables = null], options)
|
|
|
230
324
|
// $arg expr: The filter expression
|
|
231
325
|
// $arg variables: Optional (default is null). A variables object the expression evaluation.
|
|
232
326
|
// $return: The filtered data array
|
|
233
|
-
function dataFilter([data, expr, variables = null], options) {
|
|
327
|
+
function dataFilter([data = null, expr = null, variables = null], options) {
|
|
328
|
+
if (valueType(data) !== 'array' || valueType(expr) !== 'string' || (variables !== null && valueType(variables) !== 'object')) {
|
|
329
|
+
return null;
|
|
330
|
+
}
|
|
331
|
+
|
|
234
332
|
return filterData(data, expr, variables, options);
|
|
235
333
|
}
|
|
236
334
|
|
|
@@ -246,7 +344,12 @@ function dataFilter([data, expr, variables = null], options) {
|
|
|
246
344
|
// $arg isLeftJoin: Optional (default is false). If true, perform a left join (always include left row).
|
|
247
345
|
// $arg variables: Optional (default is null). A variables object for join expression evaluation.
|
|
248
346
|
// $return: The joined data array
|
|
249
|
-
function dataJoin([leftData, rightData, joinExpr, rightExpr = null, isLeftJoin = false, variables = null], options) {
|
|
347
|
+
function dataJoin([leftData = null, rightData = null, joinExpr = null, rightExpr = null, isLeftJoin = false, variables = null], options) {
|
|
348
|
+
if (valueType(leftData) !== 'array' || valueType(rightData) !== 'array' || valueType(joinExpr) !== 'string' ||
|
|
349
|
+
(rightExpr !== null && valueType(rightExpr) !== 'string') || (variables !== null && valueType(variables) !== 'object')) {
|
|
350
|
+
return null;
|
|
351
|
+
}
|
|
352
|
+
|
|
250
353
|
return joinData(leftData, rightData, joinExpr, rightExpr, isLeftJoin, variables, options);
|
|
251
354
|
}
|
|
252
355
|
|
|
@@ -256,8 +359,20 @@ function dataJoin([leftData, rightData, joinExpr, rightExpr = null, isLeftJoin =
|
|
|
256
359
|
// $doc: Parse CSV text to a data array
|
|
257
360
|
// $arg text...: The CSV text
|
|
258
361
|
// $return: The data array
|
|
259
|
-
function dataParseCSV(
|
|
260
|
-
|
|
362
|
+
function dataParseCSV(args) {
|
|
363
|
+
// Split the input CSV parts into lines
|
|
364
|
+
const lines = [];
|
|
365
|
+
for (const arg of args) {
|
|
366
|
+
if (arg === null) {
|
|
367
|
+
continue;
|
|
368
|
+
}
|
|
369
|
+
if (valueType(arg) !== 'string') {
|
|
370
|
+
return null;
|
|
371
|
+
}
|
|
372
|
+
lines.push(arg);
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
const data = parseCSV(lines);
|
|
261
376
|
validateData(data, true);
|
|
262
377
|
return data;
|
|
263
378
|
}
|
|
@@ -269,7 +384,11 @@ function dataParseCSV(text) {
|
|
|
269
384
|
// $arg data: The data array
|
|
270
385
|
// $arg sorts: The sort field-name/descending-sort tuples
|
|
271
386
|
// $return: The sorted data array
|
|
272
|
-
function dataSort([data, sorts]) {
|
|
387
|
+
function dataSort([data = null, sorts = null]) {
|
|
388
|
+
if (valueType(data) !== 'array' || valueType(sorts) !== 'array') {
|
|
389
|
+
return null;
|
|
390
|
+
}
|
|
391
|
+
|
|
273
392
|
return sortData(data, sorts);
|
|
274
393
|
}
|
|
275
394
|
|
|
@@ -278,10 +397,16 @@ function dataSort([data, sorts]) {
|
|
|
278
397
|
// $group: Data
|
|
279
398
|
// $doc: Keep the top rows for each category
|
|
280
399
|
// $arg data: The data array
|
|
281
|
-
// $arg count: The number of rows to keep
|
|
400
|
+
// $arg count: The number of rows to keep (default is 1)
|
|
282
401
|
// $arg categoryFields: Optional (default is null). The category fields.
|
|
283
402
|
// $return: The top data array
|
|
284
|
-
function dataTop([data, count, categoryFields = null]) {
|
|
403
|
+
function dataTop([data = null, count = null, categoryFields = null]) {
|
|
404
|
+
if (valueType(data) !== 'array' ||
|
|
405
|
+
valueType(count) !== 'number' || Math.floor(count) !== count || count < 1 ||
|
|
406
|
+
(categoryFields !== null && valueType(categoryFields) !== 'array')) {
|
|
407
|
+
return null;
|
|
408
|
+
}
|
|
409
|
+
|
|
285
410
|
return topData(data, count, categoryFields);
|
|
286
411
|
}
|
|
287
412
|
|
|
@@ -291,7 +416,11 @@ function dataTop([data, count, categoryFields = null]) {
|
|
|
291
416
|
// $doc: Validate a data array
|
|
292
417
|
// $arg data: The data array
|
|
293
418
|
// $return: The validated data array
|
|
294
|
-
function dataValidate([data]) {
|
|
419
|
+
function dataValidate([data = null]) {
|
|
420
|
+
if (valueType(data) !== 'array') {
|
|
421
|
+
return null;
|
|
422
|
+
}
|
|
423
|
+
|
|
295
424
|
validateData(data);
|
|
296
425
|
return data;
|
|
297
426
|
}
|
|
@@ -306,10 +435,13 @@ function dataValidate([data]) {
|
|
|
306
435
|
// $group: Datetime
|
|
307
436
|
// $doc: Get the day of the month of a datetime
|
|
308
437
|
// $arg datetime: The datetime
|
|
309
|
-
// $arg utc: Optional (default is false). If true, return the UTC day of the month.
|
|
310
438
|
// $return: The day of the month
|
|
311
|
-
function datetimeDay([datetime
|
|
312
|
-
|
|
439
|
+
function datetimeDay([datetime = null]) {
|
|
440
|
+
if (valueType(datetime) !== 'datetime') {
|
|
441
|
+
return null;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
return datetime.getDate();
|
|
313
445
|
}
|
|
314
446
|
|
|
315
447
|
|
|
@@ -317,10 +449,13 @@ function datetimeDay([datetime, utc = false]) {
|
|
|
317
449
|
// $group: Datetime
|
|
318
450
|
// $doc: Get the hour of a datetime
|
|
319
451
|
// $arg datetime: The datetime
|
|
320
|
-
// $arg utc: Optional (default is false). If true, return the UTC hour.
|
|
321
452
|
// $return: The hour
|
|
322
|
-
function datetimeHour([datetime
|
|
323
|
-
|
|
453
|
+
function datetimeHour([datetime = null]) {
|
|
454
|
+
if (valueType(datetime) !== 'datetime') {
|
|
455
|
+
return null;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
return datetime.getHours();
|
|
324
459
|
}
|
|
325
460
|
|
|
326
461
|
|
|
@@ -330,51 +465,75 @@ function datetimeHour([datetime, utc = false]) {
|
|
|
330
465
|
// $arg datetime: The datetime
|
|
331
466
|
// $arg isDate: If true, format the datetime as an ISO date
|
|
332
467
|
// $return: The formatted datetime string
|
|
333
|
-
function datetimeISOFormat([datetime, isDate = false]) {
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
if (isDate) {
|
|
337
|
-
const year = datetime.getFullYear();
|
|
338
|
-
const month = datetime.getMonth() + 1;
|
|
339
|
-
const day = datetime.getDate();
|
|
340
|
-
result = `${year}-${month < 10 ? '0' : ''}${month}-${day < 10 ? '0' : ''}${day}`;
|
|
341
|
-
} else {
|
|
342
|
-
result = datetime.toISOString();
|
|
343
|
-
}
|
|
468
|
+
function datetimeISOFormat([datetime = null, isDate = false]) {
|
|
469
|
+
if (valueType(datetime) !== 'datetime') {
|
|
470
|
+
return null;
|
|
344
471
|
}
|
|
345
|
-
|
|
472
|
+
|
|
473
|
+
if (valueBoolean(isDate)) {
|
|
474
|
+
const year = datetime.getFullYear();
|
|
475
|
+
const month = datetime.getMonth() + 1;
|
|
476
|
+
const day = datetime.getDate();
|
|
477
|
+
return `${year}-${month < 10 ? '0' : ''}${month}-${day < 10 ? '0' : ''}${day}`;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
return valueString(datetime);
|
|
346
481
|
}
|
|
347
482
|
|
|
348
483
|
|
|
349
484
|
// $function: datetimeISOParse
|
|
350
485
|
// $group: Datetime
|
|
351
486
|
// $doc: Parse an ISO date/time string
|
|
352
|
-
// $arg
|
|
487
|
+
// $arg string: The ISO date/time string
|
|
353
488
|
// $return: The datetime, or null if parsing fails
|
|
354
|
-
function datetimeISOParse([
|
|
355
|
-
|
|
489
|
+
function datetimeISOParse([string]) {
|
|
490
|
+
if (valueType(string) !== 'string') {
|
|
491
|
+
return null;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
return valueParseDatetime(string);
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
|
|
498
|
+
// $function: datetimeMillisecond
|
|
499
|
+
// $group: Datetime
|
|
500
|
+
// $doc: Get the millisecond of a datetime
|
|
501
|
+
// $arg datetime: The datetime
|
|
502
|
+
// $return: The millisecond
|
|
503
|
+
function datetimeMillisecond([datetime = null]) {
|
|
504
|
+
if (valueType(datetime) !== 'datetime') {
|
|
505
|
+
return null;
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
return datetime.getMilliseconds();
|
|
356
509
|
}
|
|
357
510
|
|
|
358
511
|
|
|
359
512
|
// $function: datetimeMinute
|
|
360
513
|
// $group: Datetime
|
|
361
|
-
// $doc: Get the
|
|
514
|
+
// $doc: Get the minute of a datetime
|
|
362
515
|
// $arg datetime: The datetime
|
|
363
|
-
// $
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
516
|
+
// $return: The minute
|
|
517
|
+
function datetimeMinute([datetime = null]) {
|
|
518
|
+
if (valueType(datetime) !== 'datetime') {
|
|
519
|
+
return null;
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
return datetime.getMinutes();
|
|
367
523
|
}
|
|
368
524
|
|
|
369
525
|
|
|
370
526
|
// $function: datetimeMonth
|
|
371
527
|
// $group: Datetime
|
|
372
|
-
// $doc: Get the
|
|
528
|
+
// $doc: Get the month (1-12) of a datetime
|
|
373
529
|
// $arg datetime: The datetime
|
|
374
|
-
// $
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
530
|
+
// $return: The month
|
|
531
|
+
function datetimeMonth([datetime = null]) {
|
|
532
|
+
if (valueType(datetime) !== 'datetime') {
|
|
533
|
+
return null;
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
return datetime.getMonth() + 1;
|
|
378
537
|
}
|
|
379
538
|
|
|
380
539
|
|
|
@@ -384,29 +543,23 @@ function datetimeMonth([datetime, utc = false]) {
|
|
|
384
543
|
// $arg year: The full year
|
|
385
544
|
// $arg month: The month (1-12)
|
|
386
545
|
// $arg day: The day of the month
|
|
387
|
-
// $arg
|
|
388
|
-
// $arg
|
|
389
|
-
// $arg
|
|
390
|
-
// $arg
|
|
546
|
+
// $arg hour: Optional (default is 0). The hour (0-23).
|
|
547
|
+
// $arg minute: Optional (default is 0). The minute.
|
|
548
|
+
// $arg second: Optional (default is 0). The second.
|
|
549
|
+
// $arg millisecond: Optional (default is 0). The millisecond.
|
|
391
550
|
// $return: The new datetime
|
|
392
|
-
function datetimeNew([year, month, day,
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
551
|
+
function datetimeNew([year, month, day, hour = 0, minute = 0, second = 0, millisecond = 0]) {
|
|
552
|
+
if (valueType(year) !== 'number' || Math.floor(year) !== year ||
|
|
553
|
+
valueType(month) !== 'number' || Math.floor(month) !== month ||
|
|
554
|
+
valueType(day) !== 'number' || Math.floor(day) !== day || day < -10000 || day > 10000 ||
|
|
555
|
+
valueType(hour) !== 'number' || Math.floor(hour) !== hour ||
|
|
556
|
+
valueType(minute) !== 'number' || Math.floor(minute) !== minute ||
|
|
557
|
+
valueType(second) !== 'number' || Math.floor(second) !== second ||
|
|
558
|
+
valueType(millisecond) !== 'number' || Math.floor(millisecond) !== millisecond) {
|
|
559
|
+
return null;
|
|
560
|
+
}
|
|
396
561
|
|
|
397
|
-
|
|
398
|
-
// $group: Datetime
|
|
399
|
-
// $doc: Create a new UTC datetime
|
|
400
|
-
// $arg year: The full year
|
|
401
|
-
// $arg month: The month (1-12)
|
|
402
|
-
// $arg day: The day of the month
|
|
403
|
-
// $arg hours: Optional (default is 0). The hour (0-23)
|
|
404
|
-
// $arg minutes: Optional (default is 0). The number of minutes.
|
|
405
|
-
// $arg seconds: Optional (default is 0). The number of seconds.
|
|
406
|
-
// $arg milliseconds: Optional (default is 0). The number of milliseconds.
|
|
407
|
-
// $return: The new UTC datetime
|
|
408
|
-
function datetimeNewUTC([year, month, day, hours = 0, minutes = 0, seconds = 0, milliseconds = 0]) {
|
|
409
|
-
return new Date(Date.UTC(year, month - 1, day, hours, minutes, seconds, milliseconds));
|
|
562
|
+
return new Date(year, month - 1, day, hour, minute, second, millisecond);
|
|
410
563
|
}
|
|
411
564
|
|
|
412
565
|
|
|
@@ -421,12 +574,15 @@ function datetimeNow() {
|
|
|
421
574
|
|
|
422
575
|
// $function: datetimeSecond
|
|
423
576
|
// $group: Datetime
|
|
424
|
-
// $doc: Get the
|
|
577
|
+
// $doc: Get the second of a datetime
|
|
425
578
|
// $arg datetime: The datetime
|
|
426
|
-
// $
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
579
|
+
// $return: The second
|
|
580
|
+
function datetimeSecond([datetime = null]) {
|
|
581
|
+
if (valueType(datetime) !== 'datetime') {
|
|
582
|
+
return null;
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
return datetime.getSeconds();
|
|
430
586
|
}
|
|
431
587
|
|
|
432
588
|
|
|
@@ -444,10 +600,13 @@ function datetimeToday() {
|
|
|
444
600
|
// $group: Datetime
|
|
445
601
|
// $doc: Get the full year of a datetime
|
|
446
602
|
// $arg datetime: The datetime
|
|
447
|
-
// $arg utc: Optional (default is false). If true, return the UTC year.
|
|
448
603
|
// $return: The full year
|
|
449
|
-
function datetimeYear([datetime
|
|
450
|
-
|
|
604
|
+
function datetimeYear([datetime = null]) {
|
|
605
|
+
if (valueType(datetime) !== 'datetime') {
|
|
606
|
+
return null;
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
return datetime.getFullYear();
|
|
451
610
|
}
|
|
452
611
|
|
|
453
612
|
|
|
@@ -455,12 +614,17 @@ function datetimeYear([datetime, utc = false]) {
|
|
|
455
614
|
// JSON functions
|
|
456
615
|
//
|
|
457
616
|
|
|
617
|
+
|
|
458
618
|
// $function: jsonParse
|
|
459
619
|
// $group: JSON
|
|
460
620
|
// $doc: Convert a JSON string to an object
|
|
461
621
|
// $arg string: The JSON string
|
|
462
622
|
// $return: The object
|
|
463
|
-
function jsonParse([string]) {
|
|
623
|
+
function jsonParse([string = null]) {
|
|
624
|
+
if (valueType(string) !== 'string') {
|
|
625
|
+
return null;
|
|
626
|
+
}
|
|
627
|
+
|
|
464
628
|
return JSON.parse(string);
|
|
465
629
|
}
|
|
466
630
|
|
|
@@ -469,10 +633,14 @@ function jsonParse([string]) {
|
|
|
469
633
|
// $group: JSON
|
|
470
634
|
// $doc: Convert an object to a JSON string
|
|
471
635
|
// $arg value: The object
|
|
472
|
-
// $arg
|
|
636
|
+
// $arg indent: Optional (default is null). The indentation number.
|
|
473
637
|
// $return: The JSON string
|
|
474
|
-
function jsonStringify([value,
|
|
475
|
-
|
|
638
|
+
function jsonStringify([value = null, indent = null]) {
|
|
639
|
+
if (indent !== null && (valueType(indent) !== 'number' || Math.floor(indent) !== indent || indent < 1)) {
|
|
640
|
+
return null;
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
return valueJSON(value, indent);
|
|
476
644
|
}
|
|
477
645
|
|
|
478
646
|
|
|
@@ -485,7 +653,11 @@ function jsonStringify([value, space]) {
|
|
|
485
653
|
// $doc: Compute the absolute value of a number
|
|
486
654
|
// $arg x: The number
|
|
487
655
|
// $return: The absolute value of the number
|
|
488
|
-
function mathAbs([x]) {
|
|
656
|
+
function mathAbs([x = null]) {
|
|
657
|
+
if (valueType(x) !== 'number') {
|
|
658
|
+
return null;
|
|
659
|
+
}
|
|
660
|
+
|
|
489
661
|
return Math.abs(x);
|
|
490
662
|
}
|
|
491
663
|
|
|
@@ -495,7 +667,11 @@ function mathAbs([x]) {
|
|
|
495
667
|
// $doc: Compute the arccosine, in radians, of a number
|
|
496
668
|
// $arg x: The number
|
|
497
669
|
// $return: The arccosine, in radians, of the number
|
|
498
|
-
function mathAcos([x]) {
|
|
670
|
+
function mathAcos([x = null]) {
|
|
671
|
+
if (valueType(x) !== 'number') {
|
|
672
|
+
return null;
|
|
673
|
+
}
|
|
674
|
+
|
|
499
675
|
return Math.acos(x);
|
|
500
676
|
}
|
|
501
677
|
|
|
@@ -505,7 +681,11 @@ function mathAcos([x]) {
|
|
|
505
681
|
// $doc: Compute the arcsine, in radians, of a number
|
|
506
682
|
// $arg x: The number
|
|
507
683
|
// $return: The arcsine, in radians, of the number
|
|
508
|
-
function mathAsin([x]) {
|
|
684
|
+
function mathAsin([x = null]) {
|
|
685
|
+
if (valueType(x) !== 'number') {
|
|
686
|
+
return null;
|
|
687
|
+
}
|
|
688
|
+
|
|
509
689
|
return Math.asin(x);
|
|
510
690
|
}
|
|
511
691
|
|
|
@@ -515,7 +695,11 @@ function mathAsin([x]) {
|
|
|
515
695
|
// $doc: Compute the arctangent, in radians, of a number
|
|
516
696
|
// $arg x: The number
|
|
517
697
|
// $return: The arctangent, in radians, of the number
|
|
518
|
-
function mathAtan([x]) {
|
|
698
|
+
function mathAtan([x = null]) {
|
|
699
|
+
if (valueType(x) !== 'number') {
|
|
700
|
+
return null;
|
|
701
|
+
}
|
|
702
|
+
|
|
519
703
|
return Math.atan(x);
|
|
520
704
|
}
|
|
521
705
|
|
|
@@ -526,7 +710,11 @@ function mathAtan([x]) {
|
|
|
526
710
|
// $arg y: The Y-coordinate of the point
|
|
527
711
|
// $arg x: The X-coordinate of the point
|
|
528
712
|
// $return: The angle, in radians
|
|
529
|
-
function mathAtan2([y, x]) {
|
|
713
|
+
function mathAtan2([y = null, x = null]) {
|
|
714
|
+
if (valueType(y) !== 'number' || valueType(x) !== 'number') {
|
|
715
|
+
return null;
|
|
716
|
+
}
|
|
717
|
+
|
|
530
718
|
return Math.atan2(y, x);
|
|
531
719
|
}
|
|
532
720
|
|
|
@@ -536,7 +724,11 @@ function mathAtan2([y, x]) {
|
|
|
536
724
|
// $doc: Compute the ceiling of a number (round up to the next highest integer)
|
|
537
725
|
// $arg x: The number
|
|
538
726
|
// $return: The ceiling of the number
|
|
539
|
-
function mathCeil([x]) {
|
|
727
|
+
function mathCeil([x = null]) {
|
|
728
|
+
if (valueType(x) !== 'number') {
|
|
729
|
+
return null;
|
|
730
|
+
}
|
|
731
|
+
|
|
540
732
|
return Math.ceil(x);
|
|
541
733
|
}
|
|
542
734
|
|
|
@@ -546,7 +738,11 @@ function mathCeil([x]) {
|
|
|
546
738
|
// $doc: Compute the cosine of an angle, in radians
|
|
547
739
|
// $arg x: The angle, in radians
|
|
548
740
|
// $return: The cosine of the angle
|
|
549
|
-
function mathCos([x]) {
|
|
741
|
+
function mathCos([x = null]) {
|
|
742
|
+
if (valueType(x) !== 'number') {
|
|
743
|
+
return null;
|
|
744
|
+
}
|
|
745
|
+
|
|
550
746
|
return Math.cos(x);
|
|
551
747
|
}
|
|
552
748
|
|
|
@@ -556,7 +752,11 @@ function mathCos([x]) {
|
|
|
556
752
|
// $doc: Compute the floor of a number (round down to the next lowest integer)
|
|
557
753
|
// $arg x: The number
|
|
558
754
|
// $return: The floor of the number
|
|
559
|
-
function mathFloor([x]) {
|
|
755
|
+
function mathFloor([x = null]) {
|
|
756
|
+
if (valueType(x) !== 'number') {
|
|
757
|
+
return null;
|
|
758
|
+
}
|
|
759
|
+
|
|
560
760
|
return Math.floor(x);
|
|
561
761
|
}
|
|
562
762
|
|
|
@@ -566,7 +766,11 @@ function mathFloor([x]) {
|
|
|
566
766
|
// $doc: Compute the natural logarithm (base e) of a number
|
|
567
767
|
// $arg x: The number
|
|
568
768
|
// $return: The natural logarithm of the number
|
|
569
|
-
function mathLn([x]) {
|
|
769
|
+
function mathLn([x = null]) {
|
|
770
|
+
if (valueType(x) !== 'number' || x <= 0) {
|
|
771
|
+
return null;
|
|
772
|
+
}
|
|
773
|
+
|
|
570
774
|
return Math.log(x);
|
|
571
775
|
}
|
|
572
776
|
|
|
@@ -577,7 +781,11 @@ function mathLn([x]) {
|
|
|
577
781
|
// $arg x: The number
|
|
578
782
|
// $arg base: Optional (default is 10). The logarithm base.
|
|
579
783
|
// $return: The logarithm of the number
|
|
580
|
-
function mathLog([x, base = 10]) {
|
|
784
|
+
function mathLog([x = null, base = 10]) {
|
|
785
|
+
if (valueType(x) !== 'number' || x <= 0 || valueType(base) !== 'number' || base <= 0 || base === 1) {
|
|
786
|
+
return null;
|
|
787
|
+
}
|
|
788
|
+
|
|
581
789
|
return Math.log(x) / Math.log(base);
|
|
582
790
|
}
|
|
583
791
|
|
|
@@ -588,6 +796,10 @@ function mathLog([x, base = 10]) {
|
|
|
588
796
|
// $arg values...: The values
|
|
589
797
|
// $return: The maximum value
|
|
590
798
|
function mathMax(values) {
|
|
799
|
+
if (values.some((value) => valueType(value) !== 'number')) {
|
|
800
|
+
return null;
|
|
801
|
+
}
|
|
802
|
+
|
|
591
803
|
return Math.max(...values);
|
|
592
804
|
}
|
|
593
805
|
|
|
@@ -598,6 +810,10 @@ function mathMax(values) {
|
|
|
598
810
|
// $arg values...: The values
|
|
599
811
|
// $return: The minimum value
|
|
600
812
|
function mathMin(values) {
|
|
813
|
+
if (values.some((value) => valueType(value) !== 'number')) {
|
|
814
|
+
return null;
|
|
815
|
+
}
|
|
816
|
+
|
|
601
817
|
return Math.min(...values);
|
|
602
818
|
}
|
|
603
819
|
|
|
@@ -626,7 +842,11 @@ function mathRandom() {
|
|
|
626
842
|
// $arg x: The number
|
|
627
843
|
// $arg digits: Optional (default is 0). The number of decimal digits to round to.
|
|
628
844
|
// $return: The rounded number
|
|
629
|
-
function mathRound([x, digits = 0]) {
|
|
845
|
+
function mathRound([x = null, digits = 0]) {
|
|
846
|
+
if (valueType(x) !== 'number' || valueType(digits) !== 'number' || Math.floor(digits) !== digits || digits < 0) {
|
|
847
|
+
return null;
|
|
848
|
+
}
|
|
849
|
+
|
|
630
850
|
const multiplier = 10 ** digits;
|
|
631
851
|
return Math.round(x * multiplier) / multiplier;
|
|
632
852
|
}
|
|
@@ -637,7 +857,11 @@ function mathRound([x, digits = 0]) {
|
|
|
637
857
|
// $doc: Compute the sign of a number
|
|
638
858
|
// $arg x: The number
|
|
639
859
|
// $return: -1 for a negative number, 1 for a positive number, and 0 for zero
|
|
640
|
-
function mathSign([x]) {
|
|
860
|
+
function mathSign([x = null]) {
|
|
861
|
+
if (valueType(x) !== 'number') {
|
|
862
|
+
return null;
|
|
863
|
+
}
|
|
864
|
+
|
|
641
865
|
return Math.sign(x);
|
|
642
866
|
}
|
|
643
867
|
|
|
@@ -647,7 +871,11 @@ function mathSign([x]) {
|
|
|
647
871
|
// $doc: Compute the sine of an angle, in radians
|
|
648
872
|
// $arg x: The angle, in radians
|
|
649
873
|
// $return: The sine of the angle
|
|
650
|
-
function mathSin([x]) {
|
|
874
|
+
function mathSin([x = null]) {
|
|
875
|
+
if (valueType(x) !== 'number') {
|
|
876
|
+
return null;
|
|
877
|
+
}
|
|
878
|
+
|
|
651
879
|
return Math.sin(x);
|
|
652
880
|
}
|
|
653
881
|
|
|
@@ -657,7 +885,11 @@ function mathSin([x]) {
|
|
|
657
885
|
// $doc: Compute the square root of a number
|
|
658
886
|
// $arg x: The number
|
|
659
887
|
// $return: The square root of the number
|
|
660
|
-
function mathSqrt([x]) {
|
|
888
|
+
function mathSqrt([x = null]) {
|
|
889
|
+
if (valueType(x) !== 'number' || x < 0) {
|
|
890
|
+
return null;
|
|
891
|
+
}
|
|
892
|
+
|
|
661
893
|
return Math.sqrt(x);
|
|
662
894
|
}
|
|
663
895
|
|
|
@@ -667,7 +899,11 @@ function mathSqrt([x]) {
|
|
|
667
899
|
// $doc: Compute the tangent of an angle, in radians
|
|
668
900
|
// $arg x: The angle, in radians
|
|
669
901
|
// $return: The tangent of the angle
|
|
670
|
-
function mathTan([x]) {
|
|
902
|
+
function mathTan([x = null]) {
|
|
903
|
+
if (valueType(x) !== 'number') {
|
|
904
|
+
return null;
|
|
905
|
+
}
|
|
906
|
+
|
|
671
907
|
return Math.tan(x);
|
|
672
908
|
}
|
|
673
909
|
|
|
@@ -676,13 +912,18 @@ function mathTan([x]) {
|
|
|
676
912
|
// Number functions
|
|
677
913
|
//
|
|
678
914
|
|
|
915
|
+
|
|
679
916
|
// $function: numberParseFloat
|
|
680
917
|
// $group: Number
|
|
681
918
|
// $doc: Parse a string as a floating point number
|
|
682
919
|
// $arg string: The string
|
|
683
920
|
// $return: The number
|
|
684
|
-
function numberParseFloat([string]) {
|
|
685
|
-
|
|
921
|
+
function numberParseFloat([string = null]) {
|
|
922
|
+
if (valueType(string) !== 'string') {
|
|
923
|
+
return null;
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
return valueParseNumber(string);
|
|
686
927
|
}
|
|
687
928
|
|
|
688
929
|
|
|
@@ -692,8 +933,12 @@ function numberParseFloat([string]) {
|
|
|
692
933
|
// $arg string: The string
|
|
693
934
|
// $arg radix: Optional (default is 10). The number base.
|
|
694
935
|
// $return: The integer
|
|
695
|
-
function numberParseInt([string, radix = 10]) {
|
|
696
|
-
|
|
936
|
+
function numberParseInt([string = null, radix = 10]) {
|
|
937
|
+
if (valueType(string) !== 'string' || valueType(radix) !== 'number' || Math.floor(radix) !== radix || radix < 2 || radix > 36) {
|
|
938
|
+
return null;
|
|
939
|
+
}
|
|
940
|
+
|
|
941
|
+
return valueParseInteger(string, radix);
|
|
697
942
|
}
|
|
698
943
|
|
|
699
944
|
|
|
@@ -704,13 +949,14 @@ function numberParseInt([string, radix = 10]) {
|
|
|
704
949
|
// $arg digits: Optional (default is 2). The number of digits to appear after the decimal point.
|
|
705
950
|
// $arg trim: Optional (default is false). If true, trim trailing zeroes and decimal point.
|
|
706
951
|
// $return: The fixed-point notation string
|
|
707
|
-
function numberToFixed([x, digits = 2, trim = false]) {
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
952
|
+
function numberToFixed([x = null, digits = 2, trim = false]) {
|
|
953
|
+
if (valueType(x) !== 'number' || valueType(digits) !== 'number' || Math.floor(digits) !== digits || digits < 0) {
|
|
954
|
+
return null;
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
let result = x.toFixed(digits);
|
|
958
|
+
if (valueBoolean(trim)) {
|
|
959
|
+
result = result.replace(rNumberCleanup, '');
|
|
714
960
|
}
|
|
715
961
|
return result;
|
|
716
962
|
}
|
|
@@ -722,17 +968,19 @@ const rNumberCleanup = /\.0*$/;
|
|
|
722
968
|
// Object functions
|
|
723
969
|
//
|
|
724
970
|
|
|
971
|
+
|
|
725
972
|
// $function: objectAssign
|
|
726
973
|
// $group: Object
|
|
727
974
|
// $doc: Assign the keys/values of one object to another
|
|
728
975
|
// $arg object: The object to assign to
|
|
729
976
|
// $arg object2: The object to assign
|
|
730
977
|
// $return: The updated object
|
|
731
|
-
function objectAssign([object, object2]) {
|
|
732
|
-
if (object !==
|
|
733
|
-
|
|
734
|
-
Object.assign(object, object2);
|
|
978
|
+
function objectAssign([object = null, object2 = null]) {
|
|
979
|
+
if (valueType(object) !== 'object' || valueType(object2) !== 'object') {
|
|
980
|
+
return null;
|
|
735
981
|
}
|
|
982
|
+
|
|
983
|
+
Object.assign(object, object2);
|
|
736
984
|
return object;
|
|
737
985
|
}
|
|
738
986
|
|
|
@@ -742,8 +990,12 @@ function objectAssign([object, object2]) {
|
|
|
742
990
|
// $doc: Create a copy of an object
|
|
743
991
|
// $arg object: The object to copy
|
|
744
992
|
// $return: The object copy
|
|
745
|
-
function objectCopy([object]) {
|
|
746
|
-
|
|
993
|
+
function objectCopy([object = null]) {
|
|
994
|
+
if (valueType(object) !== 'object') {
|
|
995
|
+
return null;
|
|
996
|
+
}
|
|
997
|
+
|
|
998
|
+
return {...object};
|
|
747
999
|
}
|
|
748
1000
|
|
|
749
1001
|
|
|
@@ -752,10 +1004,13 @@ function objectCopy([object]) {
|
|
|
752
1004
|
// $doc: Delete an object key
|
|
753
1005
|
// $arg object: The object
|
|
754
1006
|
// $arg key: The key to delete
|
|
755
|
-
function objectDelete([object, key]) {
|
|
756
|
-
if (object !==
|
|
757
|
-
|
|
1007
|
+
function objectDelete([object = null, key = null]) {
|
|
1008
|
+
if (valueType(object) !== 'object' || valueType(key) !== 'string') {
|
|
1009
|
+
return null;
|
|
758
1010
|
}
|
|
1011
|
+
|
|
1012
|
+
delete object[key];
|
|
1013
|
+
return null;
|
|
759
1014
|
}
|
|
760
1015
|
|
|
761
1016
|
|
|
@@ -766,8 +1021,12 @@ function objectDelete([object, key]) {
|
|
|
766
1021
|
// $arg key: The key
|
|
767
1022
|
// $arg defaultValue: The default value (optional)
|
|
768
1023
|
// $return: The value or null if the key does not exist
|
|
769
|
-
function objectGet([object, key, defaultValue = null]) {
|
|
770
|
-
|
|
1024
|
+
function objectGet([object = null, key = null, defaultValue = null]) {
|
|
1025
|
+
if (valueType(object) !== 'object' || valueType(key) !== 'string') {
|
|
1026
|
+
return defaultValue;
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
return object[key] ?? defaultValue;
|
|
771
1030
|
}
|
|
772
1031
|
|
|
773
1032
|
|
|
@@ -777,8 +1036,12 @@ function objectGet([object, key, defaultValue = null]) {
|
|
|
777
1036
|
// $arg object: The object
|
|
778
1037
|
// $arg key: The key
|
|
779
1038
|
// $return: true if the object contains the key, false otherwise
|
|
780
|
-
function objectHas([object, key]) {
|
|
781
|
-
|
|
1039
|
+
function objectHas([object = null, key = null]) {
|
|
1040
|
+
if (valueType(object) !== 'object' || valueType(key) !== 'string') {
|
|
1041
|
+
return false;
|
|
1042
|
+
}
|
|
1043
|
+
|
|
1044
|
+
return key in object;
|
|
782
1045
|
}
|
|
783
1046
|
|
|
784
1047
|
|
|
@@ -786,9 +1049,13 @@ function objectHas([object, key]) {
|
|
|
786
1049
|
// $group: Object
|
|
787
1050
|
// $doc: Get an object's keys
|
|
788
1051
|
// $arg object: The object
|
|
789
|
-
// $return: The array of keys
|
|
790
|
-
function objectKeys([object]) {
|
|
791
|
-
|
|
1052
|
+
// $return: The array of keys
|
|
1053
|
+
function objectKeys([object = null]) {
|
|
1054
|
+
if (valueType(object) !== 'object') {
|
|
1055
|
+
return null;
|
|
1056
|
+
}
|
|
1057
|
+
|
|
1058
|
+
return Object.keys(object);
|
|
792
1059
|
}
|
|
793
1060
|
|
|
794
1061
|
|
|
@@ -797,10 +1064,15 @@ function objectKeys([object]) {
|
|
|
797
1064
|
// $doc: Create a new object
|
|
798
1065
|
// $arg keyValues...: The object's initial key and value pairs
|
|
799
1066
|
// $return: The new object
|
|
800
|
-
function objectNew(keyValues) {
|
|
1067
|
+
function objectNew(keyValues = null) {
|
|
801
1068
|
const object = {};
|
|
802
1069
|
for (let ix = 0; ix < keyValues.length; ix += 2) {
|
|
803
|
-
|
|
1070
|
+
const key = keyValues[ix];
|
|
1071
|
+
const value = ix + 1 < keyValues.length ? keyValues[ix + 1] : null;
|
|
1072
|
+
if (valueType(key) !== 'string') {
|
|
1073
|
+
return null;
|
|
1074
|
+
}
|
|
1075
|
+
object[key] = value;
|
|
804
1076
|
}
|
|
805
1077
|
return object;
|
|
806
1078
|
}
|
|
@@ -813,10 +1085,12 @@ function objectNew(keyValues) {
|
|
|
813
1085
|
// $arg key: The key
|
|
814
1086
|
// $arg value: The value to set
|
|
815
1087
|
// $return: The value to set
|
|
816
|
-
function objectSet([object, key, value]) {
|
|
817
|
-
if (object !==
|
|
818
|
-
|
|
1088
|
+
function objectSet([object = null, key = null, value = null]) {
|
|
1089
|
+
if (valueType(object) !== 'object' || valueType(key) !== 'string') {
|
|
1090
|
+
return null;
|
|
819
1091
|
}
|
|
1092
|
+
|
|
1093
|
+
object[key] = value;
|
|
820
1094
|
return value;
|
|
821
1095
|
}
|
|
822
1096
|
|
|
@@ -831,8 +1105,12 @@ function objectSet([object, key, value]) {
|
|
|
831
1105
|
// $doc: Escape a string for use in a regular expression
|
|
832
1106
|
// $arg string: The string to escape
|
|
833
1107
|
// $return: The escaped string
|
|
834
|
-
function regexEscape([string]) {
|
|
835
|
-
|
|
1108
|
+
function regexEscape([string = null]) {
|
|
1109
|
+
if (valueType(string) !== 'string') {
|
|
1110
|
+
return null;
|
|
1111
|
+
}
|
|
1112
|
+
|
|
1113
|
+
return string.replace(rRegexEscape, '\\$&');
|
|
836
1114
|
}
|
|
837
1115
|
|
|
838
1116
|
const rRegexEscape = /[.*+?^${}()|[\]\\]/g;
|
|
@@ -843,11 +1121,19 @@ const rRegexEscape = /[.*+?^${}()|[\]\\]/g;
|
|
|
843
1121
|
// $doc: Find the first match of a regular expression in a string
|
|
844
1122
|
// $arg regex: The regular expression
|
|
845
1123
|
// $arg string: The string
|
|
846
|
-
// $return: The [match object
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
1124
|
+
// $return: The [match object](model.html#var.vName='RegexMatch'), or null if no matches are found
|
|
1125
|
+
function regexMatch([regex = null, string = null]) {
|
|
1126
|
+
if (valueType(regex) !== 'regex' || valueType(string) !== 'string') {
|
|
1127
|
+
return null;
|
|
1128
|
+
}
|
|
1129
|
+
|
|
1130
|
+
// Match?
|
|
1131
|
+
const match = string.match(regex);
|
|
1132
|
+
if (match === null) {
|
|
1133
|
+
return null;
|
|
1134
|
+
}
|
|
1135
|
+
|
|
1136
|
+
return regexMatchGroups(match);
|
|
851
1137
|
}
|
|
852
1138
|
|
|
853
1139
|
|
|
@@ -856,23 +1142,82 @@ function regexMatch([regex, string]) {
|
|
|
856
1142
|
// $doc: Find all matches of regular expression in a string
|
|
857
1143
|
// $arg regex: The regular expression
|
|
858
1144
|
// $arg string: The string
|
|
859
|
-
// $return: The [match
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
1145
|
+
// $return: The array of [match objects](model.html#var.vName='RegexMatch')
|
|
1146
|
+
function regexMatchAll([regex = null, string = null]) {
|
|
1147
|
+
if (valueType(regex) !== 'regex' || valueType(string) !== 'string') {
|
|
1148
|
+
return null;
|
|
1149
|
+
}
|
|
1150
|
+
|
|
1151
|
+
// Re-compile the regex with the "g" flag, if necessary
|
|
1152
|
+
const regexGlobal = (regex.flags.indexOf('g') !== -1 ? regex : new RegExp(regex.source, `${regex.flags}g`));
|
|
1153
|
+
|
|
1154
|
+
return Array.from(string.matchAll(regexGlobal)).map((match) => regexMatchGroups(match));
|
|
864
1155
|
}
|
|
865
1156
|
|
|
866
1157
|
|
|
1158
|
+
// Helper function to create a match model from a metch object
|
|
1159
|
+
function regexMatchGroups(match) {
|
|
1160
|
+
const groups = {};
|
|
1161
|
+
for (let ixMatch = 0; ixMatch < match.length; ixMatch++) {
|
|
1162
|
+
groups[`${ixMatch}`] = match[ixMatch];
|
|
1163
|
+
}
|
|
1164
|
+
if (match.groups) {
|
|
1165
|
+
for (const groupName of Object.keys(match.groups)) {
|
|
1166
|
+
groups[groupName] = match.groups[groupName];
|
|
1167
|
+
}
|
|
1168
|
+
}
|
|
1169
|
+
return {
|
|
1170
|
+
'index': match.index,
|
|
1171
|
+
'input': match.input,
|
|
1172
|
+
'groups': groups
|
|
1173
|
+
};
|
|
1174
|
+
}
|
|
1175
|
+
|
|
1176
|
+
|
|
1177
|
+
// The regex match model
|
|
1178
|
+
export const regexMatchTypes = parseSchemaMarkdown(`\
|
|
1179
|
+
group "RegexMatch"
|
|
1180
|
+
|
|
1181
|
+
|
|
1182
|
+
# A regex match model
|
|
1183
|
+
struct RegexMatch
|
|
1184
|
+
|
|
1185
|
+
# The zero-based index of the match in the input string
|
|
1186
|
+
int(>= 0) index
|
|
1187
|
+
|
|
1188
|
+
# The input string
|
|
1189
|
+
string input
|
|
1190
|
+
|
|
1191
|
+
# The matched groups. The "0" key is the full match text. Ordered (non-named) groups use keys "1", "2", and so on.
|
|
1192
|
+
string{} groups
|
|
1193
|
+
`);
|
|
1194
|
+
|
|
1195
|
+
|
|
867
1196
|
// $function: regexNew
|
|
868
1197
|
// $group: Regex
|
|
869
1198
|
// $doc: Create a regular expression
|
|
870
|
-
//
|
|
871
|
-
// $arg
|
|
872
|
-
// $arg flags:
|
|
1199
|
+
// eslint-disable-next-line max-len
|
|
1200
|
+
// $arg pattern: The [regular expression pattern string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_expressions#writing_a_regular_expression_pattern)
|
|
1201
|
+
// $arg flags: The regular expression flags. The string may contain the following characters:
|
|
1202
|
+
// $arg flags: - **i** - case-insensitive search
|
|
1203
|
+
// $arg flags: - **m** - multi-line search - "^" and "$" matches next to newline characters
|
|
1204
|
+
// $arg flags: - **s** - "." matches newline characters
|
|
873
1205
|
// $return: The regular expression or null if the pattern is invalid
|
|
874
|
-
function regexNew([pattern, flags]) {
|
|
875
|
-
|
|
1206
|
+
function regexNew([pattern = null, flags = null]) {
|
|
1207
|
+
if (valueType(pattern) !== 'string' || (flags !== null && valueType(flags) !== 'string')) {
|
|
1208
|
+
return null;
|
|
1209
|
+
}
|
|
1210
|
+
|
|
1211
|
+
// Valid flags mask?
|
|
1212
|
+
if (flags !== null) {
|
|
1213
|
+
for (const flag of flags) {
|
|
1214
|
+
if (flag !== 'i' && flag !== 'm' && flag !== 's') {
|
|
1215
|
+
return null;
|
|
1216
|
+
}
|
|
1217
|
+
}
|
|
1218
|
+
}
|
|
1219
|
+
|
|
1220
|
+
return flags !== null ? new RegExp(pattern, flags) : new RegExp(pattern);
|
|
876
1221
|
}
|
|
877
1222
|
|
|
878
1223
|
|
|
@@ -883,8 +1228,8 @@ function regexNew([pattern, flags]) {
|
|
|
883
1228
|
// $arg string: The string
|
|
884
1229
|
// $arg substr: The replacement string
|
|
885
1230
|
// $return: The updated string
|
|
886
|
-
function regexReplace([regex, string, substr]) {
|
|
887
|
-
if (
|
|
1231
|
+
function regexReplace([regex = null, string = null, substr = null]) {
|
|
1232
|
+
if (valueType(regex) !== 'regex' || valueType(string) !== 'string' || valueType(substr) !== 'string') {
|
|
888
1233
|
return null;
|
|
889
1234
|
}
|
|
890
1235
|
|
|
@@ -901,29 +1246,20 @@ function regexReplace([regex, string, substr]) {
|
|
|
901
1246
|
// $arg regex: The regular expression
|
|
902
1247
|
// $arg string: The string
|
|
903
1248
|
// $return: The array of split parts
|
|
904
|
-
function regexSplit([regex, string]) {
|
|
905
|
-
if (
|
|
1249
|
+
function regexSplit([regex = null, string = null]) {
|
|
1250
|
+
if (valueType(regex) !== 'regex' || valueType(string) !== 'string') {
|
|
906
1251
|
return null;
|
|
907
1252
|
}
|
|
908
1253
|
|
|
909
1254
|
return string.split(regex);
|
|
910
1255
|
}
|
|
911
1256
|
|
|
912
|
-
// $function: regexTest
|
|
913
|
-
// $group: Regex
|
|
914
|
-
// $doc: Test if a regular expression matches a string
|
|
915
|
-
// $arg regex: The regular expression
|
|
916
|
-
// $arg string: The string
|
|
917
|
-
// $return: true if the regular expression matches, false otherwise
|
|
918
|
-
function regexTest([regex, string]) {
|
|
919
|
-
return regex instanceof RegExp ? regex.test(string) : null;
|
|
920
|
-
}
|
|
921
|
-
|
|
922
1257
|
|
|
923
1258
|
//
|
|
924
1259
|
// Schema functions
|
|
925
1260
|
//
|
|
926
1261
|
|
|
1262
|
+
|
|
927
1263
|
// $function: schemaParse
|
|
928
1264
|
// $group: Schema
|
|
929
1265
|
// $doc: Parse the [Schema Markdown](https://craigahobbs.github.io/schema-markdown-js/language/) text
|
|
@@ -943,7 +1279,12 @@ function schemaParse(lines) {
|
|
|
943
1279
|
// $arg types: Optional. The [type model](https://craigahobbs.github.io/schema-markdown-doc/doc/#var.vName='Types').
|
|
944
1280
|
// $arg filename: Optional (default is ""). The file name.
|
|
945
1281
|
// $return: The schema's [type model](https://craigahobbs.github.io/schema-markdown-doc/doc/#var.vName='Types')
|
|
946
|
-
function schemaParseEx([lines, types = {}, filename = '']) {
|
|
1282
|
+
function schemaParseEx([lines = null, types = {}, filename = '']) {
|
|
1283
|
+
if (!(valueType(lines) === 'array' || valueType(lines) === 'string') ||
|
|
1284
|
+
valueType(types) !== 'object' || valueType(filename) !== 'string') {
|
|
1285
|
+
return null;
|
|
1286
|
+
}
|
|
1287
|
+
|
|
947
1288
|
return parseSchemaMarkdown(lines, {types, filename});
|
|
948
1289
|
}
|
|
949
1290
|
|
|
@@ -964,7 +1305,12 @@ function schemaTypeModel() {
|
|
|
964
1305
|
// $arg typeName: The type name
|
|
965
1306
|
// $arg value: The object to validate
|
|
966
1307
|
// $return: The validated object or null if validation fails
|
|
967
|
-
function schemaValidate([types, typeName, value]) {
|
|
1308
|
+
function schemaValidate([types = null, typeName = null, value = null]) {
|
|
1309
|
+
if (valueType(types) !== 'object' || valueType(typeName) !== 'string') {
|
|
1310
|
+
return null;
|
|
1311
|
+
}
|
|
1312
|
+
|
|
1313
|
+
validateTypeModel(types);
|
|
968
1314
|
return validateType(types, typeName, value);
|
|
969
1315
|
}
|
|
970
1316
|
|
|
@@ -974,7 +1320,11 @@ function schemaValidate([types, typeName, value]) {
|
|
|
974
1320
|
// $doc: Validate a [Schema Markdown Type Model](https://craigahobbs.github.io/schema-markdown-doc/doc/#var.vName='Types')
|
|
975
1321
|
// $arg types: The [type model](https://craigahobbs.github.io/schema-markdown-doc/doc/#var.vName='Types') to validate
|
|
976
1322
|
// $return: The validated [type model](https://craigahobbs.github.io/schema-markdown-doc/doc/#var.vName='Types')
|
|
977
|
-
function schemaValidateTypeModel([types]) {
|
|
1323
|
+
function schemaValidateTypeModel([types = null]) {
|
|
1324
|
+
if (valueType(types) !== 'object') {
|
|
1325
|
+
return null;
|
|
1326
|
+
}
|
|
1327
|
+
|
|
978
1328
|
return validateTypeModel(types);
|
|
979
1329
|
}
|
|
980
1330
|
|
|
@@ -990,8 +1340,13 @@ function schemaValidateTypeModel([types]) {
|
|
|
990
1340
|
// $arg string: The string
|
|
991
1341
|
// $arg index: The character index
|
|
992
1342
|
// $return: The character code
|
|
993
|
-
function stringCharCodeAt([string, index]) {
|
|
994
|
-
|
|
1343
|
+
function stringCharCodeAt([string = null, index = null]) {
|
|
1344
|
+
if (valueType(string) !== 'string' ||
|
|
1345
|
+
valueType(index) !== 'number' || Math.floor(index) !== index || index < 0 || index >= string.length) {
|
|
1346
|
+
return null;
|
|
1347
|
+
}
|
|
1348
|
+
|
|
1349
|
+
return string.charCodeAt(index);
|
|
995
1350
|
}
|
|
996
1351
|
|
|
997
1352
|
|
|
@@ -999,10 +1354,14 @@ function stringCharCodeAt([string, index]) {
|
|
|
999
1354
|
// $group: String
|
|
1000
1355
|
// $doc: Determine if a string ends with a search string
|
|
1001
1356
|
// $arg string: The string
|
|
1002
|
-
// $arg
|
|
1357
|
+
// $arg search: The search string
|
|
1003
1358
|
// $return: true if the string ends with the search string, false otherwise
|
|
1004
|
-
function stringEndsWith([string,
|
|
1005
|
-
|
|
1359
|
+
function stringEndsWith([string = null, search = null]) {
|
|
1360
|
+
if (valueType(string) !== 'string' || valueType(search) !== 'string') {
|
|
1361
|
+
return null;
|
|
1362
|
+
}
|
|
1363
|
+
|
|
1364
|
+
return string.endsWith(search);
|
|
1006
1365
|
}
|
|
1007
1366
|
|
|
1008
1367
|
|
|
@@ -1011,7 +1370,11 @@ function stringEndsWith([string, searchString]) {
|
|
|
1011
1370
|
// $doc: Create a string of characters from character codes
|
|
1012
1371
|
// $arg charCodes...: The character codes
|
|
1013
1372
|
// $return: The string of characters
|
|
1014
|
-
function stringFromCharCode(charCodes) {
|
|
1373
|
+
function stringFromCharCode(charCodes = null) {
|
|
1374
|
+
if (charCodes.some((code) => valueType(code) !== 'number' || Math.floor(code) !== code || code < 0)) {
|
|
1375
|
+
return null;
|
|
1376
|
+
}
|
|
1377
|
+
|
|
1015
1378
|
return String.fromCharCode(...charCodes);
|
|
1016
1379
|
}
|
|
1017
1380
|
|
|
@@ -1020,11 +1383,16 @@ function stringFromCharCode(charCodes) {
|
|
|
1020
1383
|
// $group: String
|
|
1021
1384
|
// $doc: Find the first index of a search string in a string
|
|
1022
1385
|
// $arg string: The string
|
|
1023
|
-
// $arg
|
|
1386
|
+
// $arg search: The search string
|
|
1024
1387
|
// $arg index: Optional (default is 0). The index at which to start the search.
|
|
1025
1388
|
// $return: The first index of the search string; -1 if not found.
|
|
1026
|
-
function stringIndexOf([string,
|
|
1027
|
-
|
|
1389
|
+
function stringIndexOf([string = null, search = null, index = 0]) {
|
|
1390
|
+
if (valueType(string) !== 'string' || valueType(search) !== 'string' ||
|
|
1391
|
+
valueType(index) !== 'number' || Math.floor(index) !== index || index < 0 || index >= string.length) {
|
|
1392
|
+
return -1;
|
|
1393
|
+
}
|
|
1394
|
+
|
|
1395
|
+
return string.indexOf(search, index);
|
|
1028
1396
|
}
|
|
1029
1397
|
|
|
1030
1398
|
|
|
@@ -1032,11 +1400,20 @@ function stringIndexOf([string, searchString, index]) {
|
|
|
1032
1400
|
// $group: String
|
|
1033
1401
|
// $doc: Find the last index of a search string in a string
|
|
1034
1402
|
// $arg string: The string
|
|
1035
|
-
// $arg
|
|
1403
|
+
// $arg search: The search string
|
|
1036
1404
|
// $arg index: Optional (default is the end of the string). The index at which to start the search.
|
|
1037
1405
|
// $return: The last index of the search string; -1 if not found.
|
|
1038
|
-
function stringLastIndexOf([string,
|
|
1039
|
-
|
|
1406
|
+
function stringLastIndexOf([string = null, search = null, indexArg = null]) {
|
|
1407
|
+
let index = indexArg;
|
|
1408
|
+
if (index === null && valueType(string) === 'string') {
|
|
1409
|
+
index = string.length - 1;
|
|
1410
|
+
}
|
|
1411
|
+
if (valueType(string) !== 'string' || valueType(search) !== 'string' ||
|
|
1412
|
+
valueType(index) !== 'number' || Math.floor(index) !== index || index < 0 || index >= string.length) {
|
|
1413
|
+
return -1;
|
|
1414
|
+
}
|
|
1415
|
+
|
|
1416
|
+
return string.lastIndexOf(search, index);
|
|
1040
1417
|
}
|
|
1041
1418
|
|
|
1042
1419
|
|
|
@@ -1044,9 +1421,13 @@ function stringLastIndexOf([string, searchString, index]) {
|
|
|
1044
1421
|
// $group: String
|
|
1045
1422
|
// $doc: Get the length of a string
|
|
1046
1423
|
// $arg string: The string
|
|
1047
|
-
// $return: The string's length;
|
|
1048
|
-
function stringLength([string]) {
|
|
1049
|
-
|
|
1424
|
+
// $return: The string's length; zero if not a string
|
|
1425
|
+
function stringLength([string = null]) {
|
|
1426
|
+
if (valueType(string) !== 'string') {
|
|
1427
|
+
return 0;
|
|
1428
|
+
}
|
|
1429
|
+
|
|
1430
|
+
return string.length;
|
|
1050
1431
|
}
|
|
1051
1432
|
|
|
1052
1433
|
|
|
@@ -1055,8 +1436,12 @@ function stringLength([string]) {
|
|
|
1055
1436
|
// $doc: Convert a string to lower-case
|
|
1056
1437
|
// $arg string: The string
|
|
1057
1438
|
// $return: The lower-case string
|
|
1058
|
-
function stringLower([string]) {
|
|
1059
|
-
|
|
1439
|
+
function stringLower([string = null]) {
|
|
1440
|
+
if (valueType(string) !== 'string') {
|
|
1441
|
+
return null;
|
|
1442
|
+
}
|
|
1443
|
+
|
|
1444
|
+
return string.toLowerCase();
|
|
1060
1445
|
}
|
|
1061
1446
|
|
|
1062
1447
|
|
|
@@ -1065,8 +1450,8 @@ function stringLower([string]) {
|
|
|
1065
1450
|
// $doc: Create a new string from a value
|
|
1066
1451
|
// $arg value: The value
|
|
1067
1452
|
// $return: The new string
|
|
1068
|
-
function stringNew([value]) {
|
|
1069
|
-
return
|
|
1453
|
+
function stringNew([value = null]) {
|
|
1454
|
+
return valueString(value);
|
|
1070
1455
|
}
|
|
1071
1456
|
|
|
1072
1457
|
|
|
@@ -1076,8 +1461,12 @@ function stringNew([value]) {
|
|
|
1076
1461
|
// $arg string: The string to repeat
|
|
1077
1462
|
// $arg count: The number of times to repeat the string
|
|
1078
1463
|
// $return: The repeated string
|
|
1079
|
-
function stringRepeat([string, count]) {
|
|
1080
|
-
|
|
1464
|
+
function stringRepeat([string = null, count = null]) {
|
|
1465
|
+
if (valueType(string) !== 'string' || valueType(count) !== 'number' || Math.floor(count) !== count || count < 0) {
|
|
1466
|
+
return null;
|
|
1467
|
+
}
|
|
1468
|
+
|
|
1469
|
+
return string.repeat(count);
|
|
1081
1470
|
}
|
|
1082
1471
|
|
|
1083
1472
|
|
|
@@ -1088,14 +1477,11 @@ function stringRepeat([string, count]) {
|
|
|
1088
1477
|
// $arg substr: The string to replace
|
|
1089
1478
|
// $arg newSubstr: The replacement string
|
|
1090
1479
|
// $return: The updated string
|
|
1091
|
-
function stringReplace([string, substr, newSubstr]
|
|
1092
|
-
if (
|
|
1480
|
+
function stringReplace([string = null, substr = null, newSubstr = null]) {
|
|
1481
|
+
if (valueType(string) !== 'string' || valueType(substr) !== 'string' || valueType(newSubstr) !== 'string') {
|
|
1093
1482
|
return null;
|
|
1094
1483
|
}
|
|
1095
|
-
|
|
1096
|
-
const replacerFunction = (...args) => newSubstr(args, options);
|
|
1097
|
-
return string.replaceAll(substr, replacerFunction);
|
|
1098
|
-
}
|
|
1484
|
+
|
|
1099
1485
|
return string.replaceAll(substr, newSubstr);
|
|
1100
1486
|
}
|
|
1101
1487
|
|
|
@@ -1104,11 +1490,21 @@ function stringReplace([string, substr, newSubstr], options) {
|
|
|
1104
1490
|
// $group: String
|
|
1105
1491
|
// $doc: Copy a portion of a string
|
|
1106
1492
|
// $arg string: The string
|
|
1107
|
-
// $arg start:
|
|
1493
|
+
// $arg start: The start index of the slice
|
|
1108
1494
|
// $arg end: Optional (default is the end of the string). The end index of the slice.
|
|
1109
1495
|
// $return: The new string slice
|
|
1110
|
-
function stringSlice([string,
|
|
1111
|
-
|
|
1496
|
+
function stringSlice([string = null, begin = null, endArg = null]) {
|
|
1497
|
+
let end = endArg;
|
|
1498
|
+
if (end === null && valueType(string) === 'string') {
|
|
1499
|
+
end = string.length;
|
|
1500
|
+
}
|
|
1501
|
+
if (valueType(string) !== 'string' ||
|
|
1502
|
+
valueType(begin) !== 'number' || Math.floor(begin) !== begin || begin < 0 || begin > string.length ||
|
|
1503
|
+
valueType(end) !== 'number' || Math.floor(end) !== end || end < 0 || end > string.length) {
|
|
1504
|
+
return null;
|
|
1505
|
+
}
|
|
1506
|
+
|
|
1507
|
+
return string.slice(begin, end);
|
|
1112
1508
|
}
|
|
1113
1509
|
|
|
1114
1510
|
|
|
@@ -1116,11 +1512,14 @@ function stringSlice([string, beginIndex, endIndex]) {
|
|
|
1116
1512
|
// $group: String
|
|
1117
1513
|
// $doc: Split a string
|
|
1118
1514
|
// $arg string: The string to split
|
|
1119
|
-
// $arg separator: The separator string
|
|
1120
|
-
// $arg limit: The maximum number of strings to split into
|
|
1515
|
+
// $arg separator: The separator string
|
|
1121
1516
|
// $return: The array of split-out strings
|
|
1122
|
-
function stringSplit([string, separator
|
|
1123
|
-
|
|
1517
|
+
function stringSplit([string = null, separator = null]) {
|
|
1518
|
+
if (valueType(string) !== 'string' || valueType(separator) !== 'string') {
|
|
1519
|
+
return null;
|
|
1520
|
+
}
|
|
1521
|
+
|
|
1522
|
+
return string.split(separator);
|
|
1124
1523
|
}
|
|
1125
1524
|
|
|
1126
1525
|
|
|
@@ -1128,10 +1527,14 @@ function stringSplit([string, separator, limit]) {
|
|
|
1128
1527
|
// $group: String
|
|
1129
1528
|
// $doc: Determine if a string starts with a search string
|
|
1130
1529
|
// $arg string: The string
|
|
1131
|
-
// $arg
|
|
1530
|
+
// $arg search: The search string
|
|
1132
1531
|
// $return: true if the string starts with the search string, false otherwise
|
|
1133
|
-
function stringStartsWith([string,
|
|
1134
|
-
|
|
1532
|
+
function stringStartsWith([string = null, search = null]) {
|
|
1533
|
+
if (valueType(string) !== 'string' || valueType(search) !== 'string') {
|
|
1534
|
+
return null;
|
|
1535
|
+
}
|
|
1536
|
+
|
|
1537
|
+
return string.startsWith(search);
|
|
1135
1538
|
}
|
|
1136
1539
|
|
|
1137
1540
|
|
|
@@ -1140,8 +1543,12 @@ function stringStartsWith([string, searchString]) {
|
|
|
1140
1543
|
// $doc: Trim the whitespace from the beginning and end of a string
|
|
1141
1544
|
// $arg string: The string
|
|
1142
1545
|
// $return: The trimmed string
|
|
1143
|
-
function stringTrim([string]) {
|
|
1144
|
-
|
|
1546
|
+
function stringTrim([string = null]) {
|
|
1547
|
+
if (valueType(string) !== 'string') {
|
|
1548
|
+
return null;
|
|
1549
|
+
}
|
|
1550
|
+
|
|
1551
|
+
return string.trim();
|
|
1145
1552
|
}
|
|
1146
1553
|
|
|
1147
1554
|
|
|
@@ -1150,8 +1557,12 @@ function stringTrim([string]) {
|
|
|
1150
1557
|
// $doc: Convert a string to upper-case
|
|
1151
1558
|
// $arg string: The string
|
|
1152
1559
|
// $return: The upper-case string
|
|
1153
|
-
function stringUpper([string]) {
|
|
1154
|
-
|
|
1560
|
+
function stringUpper([string = null]) {
|
|
1561
|
+
if (valueType(string) !== 'string') {
|
|
1562
|
+
return null;
|
|
1563
|
+
}
|
|
1564
|
+
|
|
1565
|
+
return string.toUpperCase();
|
|
1155
1566
|
}
|
|
1156
1567
|
|
|
1157
1568
|
|
|
@@ -1160,51 +1571,128 @@ function stringUpper([string]) {
|
|
|
1160
1571
|
//
|
|
1161
1572
|
|
|
1162
1573
|
|
|
1574
|
+
// $function: systemBoolean
|
|
1575
|
+
// $group: System
|
|
1576
|
+
// $doc: Interpret a value as a boolean
|
|
1577
|
+
// $arg value: The value
|
|
1578
|
+
// $return: true or false
|
|
1579
|
+
function systemBoolean([value = null]) {
|
|
1580
|
+
return valueBoolean(value);
|
|
1581
|
+
}
|
|
1582
|
+
|
|
1583
|
+
|
|
1584
|
+
// $function: systemCompare
|
|
1585
|
+
// $group: System
|
|
1586
|
+
// $doc: Compare two values
|
|
1587
|
+
// $arg left: The left value
|
|
1588
|
+
// $arg right: The right value
|
|
1589
|
+
// $return: -1 if the left value is less than the right value, 0 if equal, and 1 if greater than
|
|
1590
|
+
function systemCompare([left = null, right = null]) {
|
|
1591
|
+
return valueCompare(left, right);
|
|
1592
|
+
}
|
|
1593
|
+
|
|
1594
|
+
|
|
1163
1595
|
// $function: systemFetch
|
|
1164
1596
|
// $group: System
|
|
1165
|
-
// $doc: Retrieve a
|
|
1166
|
-
// $arg url: The resource URL or array of
|
|
1167
|
-
// $arg
|
|
1168
|
-
// $
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
const
|
|
1172
|
-
const
|
|
1173
|
-
const
|
|
1597
|
+
// $doc: Retrieve a URL resource
|
|
1598
|
+
// $arg url: The resource URL, [request model](model.html#var.vName='SystemFetchRequest'), or array of URL and
|
|
1599
|
+
// $arg url: [request model](model.html#var.vName='SystemFetchRequest')
|
|
1600
|
+
// $return: The response string or array of strings; null if an error occurred
|
|
1601
|
+
async function systemFetch([url = null], options) {
|
|
1602
|
+
// Options
|
|
1603
|
+
const fetchFn = options !== null ? (options.fetchFn ?? null) : null;
|
|
1604
|
+
const logFn = options !== null && options.debug ? (options.logFn ?? null) : null;
|
|
1605
|
+
const urlFn = options !== null ? (options.urlFn ?? null) : null;
|
|
1606
|
+
|
|
1607
|
+
// Validate the URL argument
|
|
1608
|
+
const requests = [];
|
|
1609
|
+
let isResponseArray = false;
|
|
1610
|
+
if (valueType(url) === 'string') {
|
|
1611
|
+
requests.push({'url': url});
|
|
1612
|
+
} else if (valueType(url) === 'object') {
|
|
1613
|
+
requests.push(validateType(systemFetchTypes, 'SystemFetchRequest', url));
|
|
1614
|
+
} else if (valueType(url) === 'array') {
|
|
1615
|
+
isResponseArray = true;
|
|
1616
|
+
for (const urlItem of url) {
|
|
1617
|
+
if (valueType(urlItem) === 'string') {
|
|
1618
|
+
requests.push({'url': urlItem});
|
|
1619
|
+
} else {
|
|
1620
|
+
requests.push(validateType(systemFetchTypes, 'SystemFetchRequest', urlItem));
|
|
1621
|
+
}
|
|
1622
|
+
}
|
|
1623
|
+
} else {
|
|
1624
|
+
return null;
|
|
1625
|
+
}
|
|
1626
|
+
|
|
1627
|
+
// Fetch in parallel
|
|
1628
|
+
const fetchResponses = await Promise.all(requests.map((request) => {
|
|
1174
1629
|
try {
|
|
1175
|
-
|
|
1630
|
+
const fetchURL = urlFn !== null ? urlFn(request.url) : request.url;
|
|
1631
|
+
const fetchOptions = {};
|
|
1632
|
+
if ((request.body ?? null) !== null) {
|
|
1633
|
+
fetchOptions.body = request.body;
|
|
1634
|
+
}
|
|
1635
|
+
if ((request.headers ?? null) !== null) {
|
|
1636
|
+
fetchOptions.headers = request.headers;
|
|
1637
|
+
}
|
|
1638
|
+
return fetchFn !== null ? fetchFn(fetchURL, fetchOptions) : null;
|
|
1176
1639
|
} catch {
|
|
1177
1640
|
return null;
|
|
1178
1641
|
}
|
|
1179
1642
|
}));
|
|
1180
|
-
const
|
|
1643
|
+
const responses = await Promise.all(fetchResponses.map(async (fetchResponse, ixResponse) => {
|
|
1644
|
+
let response;
|
|
1181
1645
|
try {
|
|
1182
|
-
|
|
1646
|
+
response = fetchResponse !== null && fetchResponse.ok ? await fetchResponse.text() : null;
|
|
1183
1647
|
} catch {
|
|
1184
|
-
|
|
1648
|
+
response = null;
|
|
1185
1649
|
}
|
|
1186
|
-
}));
|
|
1187
1650
|
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
options.logFn(`BareScript: Function "systemFetch" failed for ${isText ? 'text' : 'JSON'} resource "${errorURL}"`);
|
|
1651
|
+
// Log failure
|
|
1652
|
+
if (response === null && logFn !== null) {
|
|
1653
|
+
const errorURL = requests[ixResponse].url;
|
|
1654
|
+
logFn(`BareScript: Function "systemFetch" failed for resource "${errorURL}"`);
|
|
1193
1655
|
}
|
|
1194
|
-
}
|
|
1195
1656
|
|
|
1196
|
-
|
|
1657
|
+
return response;
|
|
1658
|
+
}));
|
|
1659
|
+
|
|
1660
|
+
return isResponseArray ? responses : responses[0];
|
|
1197
1661
|
}
|
|
1198
1662
|
|
|
1199
1663
|
|
|
1664
|
+
// The aggregation model
|
|
1665
|
+
export const systemFetchTypes = parseSchemaMarkdown(`\
|
|
1666
|
+
group "SystemFetch"
|
|
1667
|
+
|
|
1668
|
+
|
|
1669
|
+
# A fetch request model
|
|
1670
|
+
struct SystemFetchRequest
|
|
1671
|
+
|
|
1672
|
+
# The resource URL
|
|
1673
|
+
string url
|
|
1674
|
+
|
|
1675
|
+
# The request body
|
|
1676
|
+
optional string body
|
|
1677
|
+
|
|
1678
|
+
# The request headers
|
|
1679
|
+
optional string{} headers
|
|
1680
|
+
`);
|
|
1681
|
+
|
|
1682
|
+
|
|
1200
1683
|
// $function: systemGlobalGet
|
|
1201
1684
|
// $group: System
|
|
1202
1685
|
// $doc: Get a global variable value
|
|
1203
1686
|
// $arg name: The global variable name
|
|
1687
|
+
// $arg defaultValue: The default value (optional)
|
|
1204
1688
|
// $return: The global variable's value or null if it does not exist
|
|
1205
|
-
function systemGlobalGet([name], options) {
|
|
1689
|
+
function systemGlobalGet([name = null, defaultValue = null], options) {
|
|
1690
|
+
if (valueType(name) !== 'string') {
|
|
1691
|
+
return defaultValue;
|
|
1692
|
+
}
|
|
1693
|
+
|
|
1206
1694
|
const globals = (options !== null ? (options.globals ?? null) : null);
|
|
1207
|
-
return
|
|
1695
|
+
return globals !== null ? (globals[name] ?? defaultValue) : defaultValue;
|
|
1208
1696
|
}
|
|
1209
1697
|
|
|
1210
1698
|
|
|
@@ -1214,24 +1702,37 @@ function systemGlobalGet([name], options) {
|
|
|
1214
1702
|
// $arg name: The global variable name
|
|
1215
1703
|
// $arg value: The global variable's value
|
|
1216
1704
|
// $return: The global variable's value
|
|
1217
|
-
function systemGlobalSet([name, value], options) {
|
|
1218
|
-
if (
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1705
|
+
function systemGlobalSet([name = null, value = null], options) {
|
|
1706
|
+
if (valueType(name) !== 'string') {
|
|
1707
|
+
return null;
|
|
1708
|
+
}
|
|
1709
|
+
|
|
1710
|
+
const globals = (options !== null ? (options.globals ?? null) : null);
|
|
1711
|
+
if (globals !== null) {
|
|
1712
|
+
globals[name] = value;
|
|
1223
1713
|
}
|
|
1224
1714
|
return value;
|
|
1225
1715
|
}
|
|
1226
1716
|
|
|
1227
1717
|
|
|
1718
|
+
// $function: systemIs
|
|
1719
|
+
// $group: System
|
|
1720
|
+
// $doc: Test if one value is the same object as another
|
|
1721
|
+
// $arg value1: The first value
|
|
1722
|
+
// $arg value2: The second value
|
|
1723
|
+
// $return: true if values are the same object, false otherwise
|
|
1724
|
+
function systemIs([value1 = null, value2 = null]) {
|
|
1725
|
+
return valueIs(value1, value2);
|
|
1726
|
+
}
|
|
1727
|
+
|
|
1728
|
+
|
|
1228
1729
|
// $function: systemLog
|
|
1229
1730
|
// $group: System
|
|
1230
1731
|
// $doc: Log a message to the console
|
|
1231
|
-
// $arg
|
|
1232
|
-
function systemLog([
|
|
1732
|
+
// $arg message: The log message
|
|
1733
|
+
function systemLog([message = null], options) {
|
|
1233
1734
|
if (options !== null && 'logFn' in options) {
|
|
1234
|
-
options.logFn(
|
|
1735
|
+
options.logFn(valueString(message));
|
|
1235
1736
|
}
|
|
1236
1737
|
}
|
|
1237
1738
|
|
|
@@ -1239,10 +1740,10 @@ function systemLog([string], options) {
|
|
|
1239
1740
|
// $function: systemLogDebug
|
|
1240
1741
|
// $group: System
|
|
1241
1742
|
// $doc: Log a message to the console, if in debug mode
|
|
1242
|
-
// $arg
|
|
1243
|
-
function systemLogDebug([
|
|
1743
|
+
// $arg message: The log message
|
|
1744
|
+
function systemLogDebug([message = null], options) {
|
|
1244
1745
|
if (options !== null && 'logFn' in options && options.debug) {
|
|
1245
|
-
options.logFn(
|
|
1746
|
+
options.logFn(valueString(message));
|
|
1246
1747
|
}
|
|
1247
1748
|
}
|
|
1248
1749
|
|
|
@@ -1254,7 +1755,11 @@ function systemLogDebug([string], options) {
|
|
|
1254
1755
|
// $arg func: The function
|
|
1255
1756
|
// $arg args...: The function arguments
|
|
1256
1757
|
// $return: The new function called with "args"
|
|
1257
|
-
function systemPartial([func, ...args]) {
|
|
1758
|
+
function systemPartial([func = null, ...args]) {
|
|
1759
|
+
if (valueType(func) !== 'function' || args.length < 1) {
|
|
1760
|
+
return null;
|
|
1761
|
+
}
|
|
1762
|
+
|
|
1258
1763
|
return (argsExtra, options) => func([...args, ...argsExtra], options);
|
|
1259
1764
|
}
|
|
1260
1765
|
|
|
@@ -1265,20 +1770,8 @@ function systemPartial([func, ...args]) {
|
|
|
1265
1770
|
// $arg value: The value
|
|
1266
1771
|
// $return: The type string of the value.
|
|
1267
1772
|
// $return: Valid values are: 'array', 'boolean', 'datetime', 'function', 'null', 'number', 'object', 'regex', 'string'.
|
|
1268
|
-
function systemType([value]) {
|
|
1269
|
-
|
|
1270
|
-
if (type === 'object') {
|
|
1271
|
-
if (value === null) {
|
|
1272
|
-
return 'null';
|
|
1273
|
-
} else if (Array.isArray(value)) {
|
|
1274
|
-
return 'array';
|
|
1275
|
-
} else if (value instanceof Date) {
|
|
1276
|
-
return 'datetime';
|
|
1277
|
-
} else if (value instanceof RegExp) {
|
|
1278
|
-
return 'regex';
|
|
1279
|
-
}
|
|
1280
|
-
}
|
|
1281
|
-
return type;
|
|
1773
|
+
function systemType([value = null]) {
|
|
1774
|
+
return valueType(value);
|
|
1282
1775
|
}
|
|
1283
1776
|
|
|
1284
1777
|
|
|
@@ -1293,9 +1786,13 @@ function systemType([value]) {
|
|
|
1293
1786
|
// $arg url: The URL string
|
|
1294
1787
|
// $arg extra: Optional (default is true). If true, encode extra characters for wider compatibility.
|
|
1295
1788
|
// $return: The encoded URL string
|
|
1296
|
-
function urlEncode([url, extra = true]) {
|
|
1789
|
+
function urlEncode([url = null, extra = true]) {
|
|
1790
|
+
if (valueType(url) !== 'string') {
|
|
1791
|
+
return null;
|
|
1792
|
+
}
|
|
1793
|
+
|
|
1297
1794
|
let urlEncoded = encodeURI(url);
|
|
1298
|
-
if (extra) {
|
|
1795
|
+
if (valueBoolean(extra)) {
|
|
1299
1796
|
// Replace ')' with '%29' for Markdown links
|
|
1300
1797
|
urlEncoded = urlEncoded.replaceAll(')', '%29');
|
|
1301
1798
|
}
|
|
@@ -1309,13 +1806,17 @@ function urlEncode([url, extra = true]) {
|
|
|
1309
1806
|
// $arg url: The URL component string
|
|
1310
1807
|
// $arg extra: Optional (default is true). If true, encode extra characters for wider compatibility.
|
|
1311
1808
|
// $return: The encoded URL component string
|
|
1312
|
-
function urlEncodeComponent([
|
|
1313
|
-
|
|
1314
|
-
|
|
1809
|
+
function urlEncodeComponent([url = null, extra = true]) {
|
|
1810
|
+
if (valueType(url) !== 'string') {
|
|
1811
|
+
return null;
|
|
1812
|
+
}
|
|
1813
|
+
|
|
1814
|
+
let urlEncoded = encodeURIComponent(url);
|
|
1815
|
+
if (valueBoolean(extra)) {
|
|
1315
1816
|
// Replace ')' with '%29' for Markdown links
|
|
1316
|
-
|
|
1817
|
+
urlEncoded = urlEncoded.replaceAll(')', '%29');
|
|
1317
1818
|
}
|
|
1318
|
-
return
|
|
1819
|
+
return urlEncoded;
|
|
1319
1820
|
}
|
|
1320
1821
|
|
|
1321
1822
|
|
|
@@ -1348,10 +1849,10 @@ export const scriptFunctions = {
|
|
|
1348
1849
|
datetimeHour,
|
|
1349
1850
|
datetimeISOFormat,
|
|
1350
1851
|
datetimeISOParse,
|
|
1852
|
+
datetimeMillisecond,
|
|
1351
1853
|
datetimeMinute,
|
|
1352
1854
|
datetimeMonth,
|
|
1353
1855
|
datetimeNew,
|
|
1354
|
-
datetimeNewUTC,
|
|
1355
1856
|
datetimeNow,
|
|
1356
1857
|
datetimeSecond,
|
|
1357
1858
|
datetimeToday,
|
|
@@ -1394,7 +1895,6 @@ export const scriptFunctions = {
|
|
|
1394
1895
|
regexNew,
|
|
1395
1896
|
regexReplace,
|
|
1396
1897
|
regexSplit,
|
|
1397
|
-
regexTest,
|
|
1398
1898
|
schemaParse,
|
|
1399
1899
|
schemaParseEx,
|
|
1400
1900
|
schemaTypeModel,
|
|
@@ -1415,9 +1915,12 @@ export const scriptFunctions = {
|
|
|
1415
1915
|
stringStartsWith,
|
|
1416
1916
|
stringTrim,
|
|
1417
1917
|
stringUpper,
|
|
1918
|
+
systemBoolean,
|
|
1919
|
+
systemCompare,
|
|
1418
1920
|
systemFetch,
|
|
1419
1921
|
systemGlobalGet,
|
|
1420
1922
|
systemGlobalSet,
|
|
1923
|
+
systemIs,
|
|
1421
1924
|
systemLog,
|
|
1422
1925
|
systemLogDebug,
|
|
1423
1926
|
systemPartial,
|