bare-script 2.0.2
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/LICENSE +21 -0
- package/README.md +132 -0
- package/bin/bareScriptDoc.js +15 -0
- package/lib/library.js +978 -0
- package/lib/libraryDoc.js +136 -0
- package/lib/model.js +477 -0
- package/lib/parser.js +725 -0
- package/lib/runtime.js +316 -0
- package/lib/runtimeAsync.js +379 -0
- package/package.json +36 -0
package/lib/library.js
ADDED
|
@@ -0,0 +1,978 @@
|
|
|
1
|
+
// Licensed under the MIT License
|
|
2
|
+
// https://github.com/craigahobbs/bare-script/blob/main/LICENSE
|
|
3
|
+
|
|
4
|
+
import {validateType, validateTypeModel} from 'schema-markdown/lib/schema.js';
|
|
5
|
+
import {jsonStringifySortKeys} from 'schema-markdown/lib/encode.js';
|
|
6
|
+
import {parseSchemaMarkdown} from 'schema-markdown/lib/parser.js';
|
|
7
|
+
import {typeModel} from 'schema-markdown/lib/typeModel.js';
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
/* eslint-disable id-length */
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
// The default maximum statements for executeScript
|
|
14
|
+
export const defaultMaxStatements = 1e9;
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
// The built-in script functions
|
|
18
|
+
export const scriptFunctions = {
|
|
19
|
+
//
|
|
20
|
+
// Array functions
|
|
21
|
+
//
|
|
22
|
+
|
|
23
|
+
// $function: arrayCopy
|
|
24
|
+
// $group: Array
|
|
25
|
+
// $doc: Create a copy of an array
|
|
26
|
+
// $arg array: The array to copy
|
|
27
|
+
// $return: The array copy
|
|
28
|
+
'arrayCopy': ([array]) => (Array.isArray(array) ? [...array] : null),
|
|
29
|
+
|
|
30
|
+
// $function: arrayExtend
|
|
31
|
+
// $group: Array
|
|
32
|
+
// $doc: Extend one array with another
|
|
33
|
+
// $arg array: The array to extend
|
|
34
|
+
// $arg array2: The array to extend with
|
|
35
|
+
// $return: The extended array
|
|
36
|
+
'arrayExtend': ([array, array2]) => {
|
|
37
|
+
if (!Array.isArray(array)) {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
array.push(...array2);
|
|
41
|
+
return array;
|
|
42
|
+
},
|
|
43
|
+
|
|
44
|
+
// $function: arrayGet
|
|
45
|
+
// $group: Array
|
|
46
|
+
// $doc: Get an array element
|
|
47
|
+
// $arg array: The array
|
|
48
|
+
// $arg index: The array element's index
|
|
49
|
+
// $return: The array element
|
|
50
|
+
'arrayGet': ([array, index]) => (Array.isArray(array) ? array[index] ?? null : null),
|
|
51
|
+
|
|
52
|
+
// $function: arrayIndexOf
|
|
53
|
+
// $group: Array
|
|
54
|
+
// $doc: Find the index of a value in an array
|
|
55
|
+
// $arg array: The array
|
|
56
|
+
// $arg value: The value to find in the array
|
|
57
|
+
// $arg index: Optional (default is 0). The index at which to start the search.
|
|
58
|
+
// $return: The first index of the value in the array; -1 if not found.
|
|
59
|
+
'arrayIndexOf': ([array, value, index = 0]) => (Array.isArray(array) ? array.indexOf(value, index) : null),
|
|
60
|
+
|
|
61
|
+
// $function: arrayJoin
|
|
62
|
+
// $group: Array
|
|
63
|
+
// $doc: Join an array with a separator string
|
|
64
|
+
// $arg array: The array
|
|
65
|
+
// $arg separator: The separator string
|
|
66
|
+
// $return: The joined string
|
|
67
|
+
'arrayJoin': ([array, separator]) => (Array.isArray(array) ? array.join(separator) : null),
|
|
68
|
+
|
|
69
|
+
// $function: arrayLastIndexOf
|
|
70
|
+
// $group: Array
|
|
71
|
+
// $doc: Find the last index of a value in an array
|
|
72
|
+
// $arg array: The array
|
|
73
|
+
// $arg value: The value to find in the array
|
|
74
|
+
// $arg index: Optional (default is the end of the array). The index at which to start the search.
|
|
75
|
+
// $return: The last index of the value in the array; -1 if not found.
|
|
76
|
+
'arrayLastIndexOf': ([array, value, index = null]) => (
|
|
77
|
+
Array.isArray(array) ? (index === null ? array.lastIndexOf(value) : array.lastIndexOf(value, index)) : null
|
|
78
|
+
),
|
|
79
|
+
|
|
80
|
+
// $function: arrayLength
|
|
81
|
+
// $group: Array
|
|
82
|
+
// $doc: Get the length of an array
|
|
83
|
+
// $arg array: The array
|
|
84
|
+
// $return: The array's length
|
|
85
|
+
'arrayLength': ([array]) => (Array.isArray(array) ? array.length : null),
|
|
86
|
+
|
|
87
|
+
// $function: arrayNew
|
|
88
|
+
// $group: Array
|
|
89
|
+
// $doc: Create a new array
|
|
90
|
+
// $arg args: The new array's values
|
|
91
|
+
// $return: The new array
|
|
92
|
+
'arrayNew': (args) => args,
|
|
93
|
+
|
|
94
|
+
// $function: arrayNewSize
|
|
95
|
+
// $group: Array
|
|
96
|
+
// $doc: Create a new array of a specific size
|
|
97
|
+
// $arg size: Optional (default is 0). The new array's size.
|
|
98
|
+
// $arg value: Optional (default is 0). The value with which to fill the new array.
|
|
99
|
+
// $return: The new array
|
|
100
|
+
'arrayNewSize': ([size = 0, value = 0]) => new Array(size).fill(value),
|
|
101
|
+
|
|
102
|
+
// $function: arrayPop
|
|
103
|
+
// $group: Array
|
|
104
|
+
// $doc: Remove the last element of the array and return it
|
|
105
|
+
// $arg array: The array
|
|
106
|
+
// $return: The last element of the array; null if the array is empty.
|
|
107
|
+
'arrayPop': ([array]) => (Array.isArray(array) ? array.pop() ?? null : null),
|
|
108
|
+
|
|
109
|
+
// $function: arrayPush
|
|
110
|
+
// $group: Array
|
|
111
|
+
// $doc: Add one or more values to the end of the array
|
|
112
|
+
// $arg array: The array
|
|
113
|
+
// $arg values: The values to add to the end of the array
|
|
114
|
+
// $return: The new length of the array
|
|
115
|
+
'arrayPush': ([array, ...values]) => (Array.isArray(array) ? array.push(...values) : null),
|
|
116
|
+
|
|
117
|
+
// $function: arraySet
|
|
118
|
+
// $group: Array
|
|
119
|
+
// $doc: Set an array element value
|
|
120
|
+
// $arg array: The array
|
|
121
|
+
// $arg index: The index of the element to set
|
|
122
|
+
// $arg value: The value to set
|
|
123
|
+
// $return: The value
|
|
124
|
+
'arraySet': ([array, index, value]) => {
|
|
125
|
+
if (Array.isArray(array)) {
|
|
126
|
+
array[index] = value;
|
|
127
|
+
return value;
|
|
128
|
+
}
|
|
129
|
+
return null;
|
|
130
|
+
},
|
|
131
|
+
|
|
132
|
+
// $function: arraySlice
|
|
133
|
+
// $group: Array
|
|
134
|
+
// $doc: Copy a portion of an array
|
|
135
|
+
// $arg array: The array
|
|
136
|
+
// $arg start: Optional (default is 0). The start index of the slice.
|
|
137
|
+
// $arg end: Optional (default is the end of the array). The end index of the slice.
|
|
138
|
+
// $return: The new array slice
|
|
139
|
+
'arraySlice': ([array, start, end]) => (Array.isArray(array) ? array.slice(start, end) : null),
|
|
140
|
+
|
|
141
|
+
// $function: arraySort
|
|
142
|
+
// $group: Array
|
|
143
|
+
// $doc: Sort an array
|
|
144
|
+
// $arg array: The array
|
|
145
|
+
// $arg compareFn: Optional (default is null). The comparison function.
|
|
146
|
+
// $return: The sorted array
|
|
147
|
+
'arraySort': ([array, compareFn = null], options) => (
|
|
148
|
+
Array.isArray(array) ? (compareFn === null ? array.sort() : array.sort((...args) => compareFn(args, options))) : null
|
|
149
|
+
),
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
//
|
|
153
|
+
// Console functions
|
|
154
|
+
//
|
|
155
|
+
|
|
156
|
+
// $function: consoleLog
|
|
157
|
+
// $group: Console
|
|
158
|
+
// $doc: Log a message to the console
|
|
159
|
+
// $arg string: The message
|
|
160
|
+
'consoleLog': ([string], options) => {
|
|
161
|
+
if (options !== null && 'logFn' in options) {
|
|
162
|
+
options.logFn(string);
|
|
163
|
+
}
|
|
164
|
+
},
|
|
165
|
+
|
|
166
|
+
// $function: consoleLogDebug
|
|
167
|
+
// $group: Console
|
|
168
|
+
// $doc: Log a debug message
|
|
169
|
+
// $arg string: The message
|
|
170
|
+
'consoleLogDebug': ([string], options) => {
|
|
171
|
+
if (options !== null && 'logFn' in options && options.debug) {
|
|
172
|
+
options.logFn(string);
|
|
173
|
+
}
|
|
174
|
+
},
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
//
|
|
178
|
+
// Datetime functions
|
|
179
|
+
//
|
|
180
|
+
|
|
181
|
+
// $function: datetimeDay
|
|
182
|
+
// $group: Datetime
|
|
183
|
+
// $doc: Get the day of the month of a datetime
|
|
184
|
+
// $arg datetime: The datetime
|
|
185
|
+
// $return: The day of the month
|
|
186
|
+
'datetimeDay': ([datetime]) => (datetime instanceof Date ? datetime.getDate() : null),
|
|
187
|
+
|
|
188
|
+
// $function: datetimeHour
|
|
189
|
+
// $group: Datetime
|
|
190
|
+
// $doc: Get the hour of a datetime
|
|
191
|
+
// $arg datetime: The datetime
|
|
192
|
+
// $return: The hour
|
|
193
|
+
'datetimeHour': ([datetime]) => (datetime instanceof Date ? datetime.getHours() : null),
|
|
194
|
+
|
|
195
|
+
// $function: datetimeISOFormat
|
|
196
|
+
// $group: Datetime
|
|
197
|
+
// $doc: Format the datetime as an ISO date/time string
|
|
198
|
+
// $arg datetime: The datetime
|
|
199
|
+
// $arg isDate: If true, format the datetime as an ISO date
|
|
200
|
+
// $return: The formatted datetime string
|
|
201
|
+
'datetimeISOFormat': ([datetime, isDate = false]) => {
|
|
202
|
+
let result = null;
|
|
203
|
+
if (datetime instanceof Date) {
|
|
204
|
+
result = datetime.toISOString();
|
|
205
|
+
if (isDate) {
|
|
206
|
+
result = result.slice(0, result.indexOf('T'));
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
return result;
|
|
210
|
+
},
|
|
211
|
+
|
|
212
|
+
// $function: datetimeMinute
|
|
213
|
+
// $group: Datetime
|
|
214
|
+
// $doc: Get the number of minutes of a datetime
|
|
215
|
+
// $arg datetime: The datetime
|
|
216
|
+
// $return: The number of minutes
|
|
217
|
+
'datetimeMinute': ([datetime]) => (datetime instanceof Date ? datetime.getMinutes() : null),
|
|
218
|
+
|
|
219
|
+
// $function: datetimeMonth
|
|
220
|
+
// $group: Datetime
|
|
221
|
+
// $doc: Get the number of the month (1-12) of a datetime
|
|
222
|
+
// $arg datetime: The datetime
|
|
223
|
+
// $return: The number of the month
|
|
224
|
+
'datetimeMonth': ([datetime]) => (datetime instanceof Date ? datetime.getMonth() + 1 : null),
|
|
225
|
+
|
|
226
|
+
// $function: datetimeNew
|
|
227
|
+
// $group: Datetime
|
|
228
|
+
// $doc: Create a new datetime
|
|
229
|
+
// $arg year: The full year
|
|
230
|
+
// $arg month: The month (1-12)
|
|
231
|
+
// $arg day: The day of the month
|
|
232
|
+
// $arg hours: Optional (default is 0). The hour (0-23)
|
|
233
|
+
// $arg minutes: Optional (default is 0). The number of minutes.
|
|
234
|
+
// $arg seconds: Optional (default is 0). The number of seconds.
|
|
235
|
+
// $arg milliseconds: Optional (default is 0). The number of milliseconds.
|
|
236
|
+
// $return: The new datetime
|
|
237
|
+
'datetimeNew': ([year, month, day, hours = 0, minutes = 0, seconds = 0, milliseconds = 0]) => (
|
|
238
|
+
new Date(year, month - 1, day, hours, minutes, seconds, milliseconds)
|
|
239
|
+
),
|
|
240
|
+
|
|
241
|
+
// $function: datetimeNewUTC
|
|
242
|
+
// $group: Datetime
|
|
243
|
+
// $doc: Create a new UTC datetime
|
|
244
|
+
// $arg year: The full year
|
|
245
|
+
// $arg month: The month (1-12)
|
|
246
|
+
// $arg day: The day of the month
|
|
247
|
+
// $arg hours: Optional (default is 0). The hour (0-23)
|
|
248
|
+
// $arg minutes: Optional (default is 0). The number of minutes.
|
|
249
|
+
// $arg seconds: Optional (default is 0). The number of seconds.
|
|
250
|
+
// $arg milliseconds: Optional (default is 0). The number of milliseconds.
|
|
251
|
+
// $return: The new UTC datetime
|
|
252
|
+
'datetimeNewUTC': ([year, month, day, hours = 0, minutes = 0, seconds = 0, milliseconds = 0]) => (
|
|
253
|
+
new Date(Date.UTC(year, month - 1, day, hours, minutes, seconds, milliseconds))
|
|
254
|
+
),
|
|
255
|
+
|
|
256
|
+
// $function: datetimeNow
|
|
257
|
+
// $group: Datetime
|
|
258
|
+
// $doc: Get the current datetime
|
|
259
|
+
// $return: The current datetime
|
|
260
|
+
'datetimeNow': () => new Date(),
|
|
261
|
+
|
|
262
|
+
// $function: datetimeSecond
|
|
263
|
+
// $group: Datetime
|
|
264
|
+
// $doc: Get the number of seconds of a datetime
|
|
265
|
+
// $arg datetime: The datetime
|
|
266
|
+
// $return: The number of seconds
|
|
267
|
+
'datetimeSecond': ([datetime]) => (datetime instanceof Date ? datetime.getSeconds() : null),
|
|
268
|
+
|
|
269
|
+
// $function: datetimeToday
|
|
270
|
+
// $group: Datetime
|
|
271
|
+
// $doc: Get today's datetime
|
|
272
|
+
// $return: Today's datetime
|
|
273
|
+
'datetimeToday': () => {
|
|
274
|
+
const now = new Date();
|
|
275
|
+
return new Date(now.getFullYear(), now.getMonth(), now.getDate());
|
|
276
|
+
},
|
|
277
|
+
|
|
278
|
+
// $function: datetimeYear
|
|
279
|
+
// $group: Datetime
|
|
280
|
+
// $doc: Get the full year of a datetime
|
|
281
|
+
// $arg datetime: The datetime
|
|
282
|
+
// $return: The full year
|
|
283
|
+
'datetimeYear': ([datetime]) => (datetime instanceof Date ? datetime.getFullYear() : null),
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
//
|
|
287
|
+
// HTTP functions
|
|
288
|
+
//
|
|
289
|
+
|
|
290
|
+
// $function: httpFetch
|
|
291
|
+
// $group: HTTP
|
|
292
|
+
// $doc: Retrieve a remote JSON or text resource
|
|
293
|
+
// $arg url: The resource URL or array of URLs
|
|
294
|
+
// $arg options: Optional (default is null). The [fetch options](https://developer.mozilla.org/en-US/docs/Web/API/fetch#parameters).
|
|
295
|
+
// $arg isText: Optional (default is false). If true, retrieve the resource as text.
|
|
296
|
+
// $return: The resource object/string or array of objects/strings; null if an error occurred.
|
|
297
|
+
'httpFetch': async ([url, fetchOptions = null, isText = false], options) => {
|
|
298
|
+
const isArray = Array.isArray(url);
|
|
299
|
+
const urls = (isArray ? url : [url]).map((mURL) => (options !== null && 'urlFn' in options ? options.urlFn(mURL) : mURL));
|
|
300
|
+
const responses = await Promise.all(urls.map(async (fURL) => {
|
|
301
|
+
try {
|
|
302
|
+
return 'fetchFn' in options ? await (fetchOptions ? options.fetchFn(fURL, fetchOptions) : options.fetchFn(fURL)) : null;
|
|
303
|
+
} catch {
|
|
304
|
+
return null;
|
|
305
|
+
}
|
|
306
|
+
}));
|
|
307
|
+
const values = await Promise.all(responses.map(async (response) => {
|
|
308
|
+
try {
|
|
309
|
+
return response !== null && response.ok ? await (isText ? response.text() : response.json()) : null;
|
|
310
|
+
} catch {
|
|
311
|
+
return null;
|
|
312
|
+
}
|
|
313
|
+
}));
|
|
314
|
+
|
|
315
|
+
// Log failures
|
|
316
|
+
for (const [ixValue, value] of values.entries()) {
|
|
317
|
+
if (value === null && options !== null && 'logFn' in options && options.debug) {
|
|
318
|
+
const errorURL = urls[ixValue];
|
|
319
|
+
options.logFn(`BareScript: Function "httpFetch" failed for ${isText ? 'text' : 'JSON'} resource "${errorURL}"`);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
return isArray ? values : values[0];
|
|
324
|
+
},
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
//
|
|
328
|
+
// JSON functions
|
|
329
|
+
//
|
|
330
|
+
|
|
331
|
+
// $function: jsonParse
|
|
332
|
+
// $group: JSON
|
|
333
|
+
// $doc: Convert a JSON string to an object
|
|
334
|
+
// $arg string: The JSON string
|
|
335
|
+
// $return: The object
|
|
336
|
+
'jsonParse': ([string]) => JSON.parse(string),
|
|
337
|
+
|
|
338
|
+
// $function: jsonStringify
|
|
339
|
+
// $group: JSON
|
|
340
|
+
// $doc: Convert an object to a JSON string
|
|
341
|
+
// $arg value: The object
|
|
342
|
+
// $arg space: Optional (default is null). The indentation string or number.
|
|
343
|
+
// $return: The JSON string
|
|
344
|
+
'jsonStringify': ([value, space]) => jsonStringifySortKeys(value, space),
|
|
345
|
+
|
|
346
|
+
|
|
347
|
+
//
|
|
348
|
+
// Math functions
|
|
349
|
+
//
|
|
350
|
+
|
|
351
|
+
// $function: mathAbs
|
|
352
|
+
// $group: Math
|
|
353
|
+
// $doc: Compute the absolute value of a number
|
|
354
|
+
// $arg x: The number
|
|
355
|
+
// $return: The absolute value of the number
|
|
356
|
+
'mathAbs': ([x]) => Math.abs(x),
|
|
357
|
+
|
|
358
|
+
// $function: mathAcos
|
|
359
|
+
// $group: Math
|
|
360
|
+
// $doc: Compute the arccosine, in radians, of a number
|
|
361
|
+
// $arg x: The number
|
|
362
|
+
// $return: The arccosine, in radians, of the number
|
|
363
|
+
'mathAcos': ([x]) => Math.acos(x),
|
|
364
|
+
|
|
365
|
+
// $function: mathAsin
|
|
366
|
+
// $group: Math
|
|
367
|
+
// $doc: Compute the arcsine, in radians, of a number
|
|
368
|
+
// $arg x: The number
|
|
369
|
+
// $return: The arcsine, in radians, of the number
|
|
370
|
+
'mathAsin': ([x]) => Math.asin(x),
|
|
371
|
+
|
|
372
|
+
// $function: mathAtan
|
|
373
|
+
// $group: Math
|
|
374
|
+
// $doc: Compute the arctangent, in radians, of a number
|
|
375
|
+
// $arg x: The number
|
|
376
|
+
// $return: The arctangent, in radians, of the number
|
|
377
|
+
'mathAtan': ([x]) => Math.atan(x),
|
|
378
|
+
|
|
379
|
+
// $function: mathAtan2
|
|
380
|
+
// $group: Math
|
|
381
|
+
// $doc: Compute the angle, in radians, between (0, 0) and a point
|
|
382
|
+
// $arg y: The Y-coordinate of the point
|
|
383
|
+
// $arg x: The X-coordinate of the point
|
|
384
|
+
// $return: The angle, in radians
|
|
385
|
+
'mathAtan2': ([y, x]) => Math.atan2(y, x),
|
|
386
|
+
|
|
387
|
+
// $function: mathCeil
|
|
388
|
+
// $group: Math
|
|
389
|
+
// $doc: Compute the ceiling of a number (round up to the next highest integer)
|
|
390
|
+
// $arg x: The number
|
|
391
|
+
// $return: The ceiling of the number
|
|
392
|
+
'mathCeil': ([x]) => Math.ceil(x),
|
|
393
|
+
|
|
394
|
+
// $function: mathCos
|
|
395
|
+
// $group: Math
|
|
396
|
+
// $doc: Compute the cosine of an angle, in radians
|
|
397
|
+
// $arg x: The angle, in radians
|
|
398
|
+
// $return: The cosine of the angle
|
|
399
|
+
'mathCos': ([x]) => Math.cos(x),
|
|
400
|
+
|
|
401
|
+
// $function: mathFloor
|
|
402
|
+
// $group: Math
|
|
403
|
+
// $doc: Compute the floor of a number (round down to the next lowest integer)
|
|
404
|
+
// $arg x: The number
|
|
405
|
+
// $return: The floor of the number
|
|
406
|
+
'mathFloor': ([x]) => Math.floor(x),
|
|
407
|
+
|
|
408
|
+
// $function: mathLn
|
|
409
|
+
// $group: Math
|
|
410
|
+
// $doc: Compute the natural logarithm (base e) of a number
|
|
411
|
+
// $arg x: The number
|
|
412
|
+
// $return: The natural logarithm of the number
|
|
413
|
+
'mathLn': ([x]) => Math.log(x),
|
|
414
|
+
|
|
415
|
+
// $function: mathLog
|
|
416
|
+
// $group: Math
|
|
417
|
+
// $doc: Compute the logarithm (base 10) of a number
|
|
418
|
+
// $arg x: The number
|
|
419
|
+
// $arg base: Optional (default is 10). The logarithm base.
|
|
420
|
+
// $return: The logarithm of the number
|
|
421
|
+
'mathLog': ([x, base = 10]) => Math.log(x) / Math.log(base),
|
|
422
|
+
|
|
423
|
+
// $function: mathMax
|
|
424
|
+
// $group: Math
|
|
425
|
+
// $doc: Compute the maximum value of all arguments
|
|
426
|
+
// $arg values: All arguments
|
|
427
|
+
// $return: The maximum value
|
|
428
|
+
'mathMax': (values) => Math.max(...values),
|
|
429
|
+
|
|
430
|
+
// $function: mathMin
|
|
431
|
+
// $group: Math
|
|
432
|
+
// $doc: Compute the minimum value of all arguments
|
|
433
|
+
// $arg values: All arguments
|
|
434
|
+
// $return: The minimum value
|
|
435
|
+
'mathMin': (values) => Math.min(...values),
|
|
436
|
+
|
|
437
|
+
// $function: mathPi
|
|
438
|
+
// $group: Math
|
|
439
|
+
// $doc: Return the number pi
|
|
440
|
+
// $return: The number pi
|
|
441
|
+
'mathPi': () => Math.PI,
|
|
442
|
+
|
|
443
|
+
// $function: mathRandom
|
|
444
|
+
// $group: Math
|
|
445
|
+
// $doc: Compute a random number between 0 and 1, inclusive
|
|
446
|
+
// $return: A random number
|
|
447
|
+
'mathRandom': () => Math.random(),
|
|
448
|
+
|
|
449
|
+
// $function: mathRound
|
|
450
|
+
// $group: Math
|
|
451
|
+
// $doc: Round a number to a certain number of decimal places
|
|
452
|
+
// $arg x: The number
|
|
453
|
+
// $arg digits: Optional (default is 0). The number of decimal digits to round to.
|
|
454
|
+
// $return: The rounded number
|
|
455
|
+
'mathRound': ([x, digits = 0]) => {
|
|
456
|
+
const multiplier = 10 ** digits;
|
|
457
|
+
return Math.round(x * multiplier) / multiplier;
|
|
458
|
+
},
|
|
459
|
+
|
|
460
|
+
// $function: mathSign
|
|
461
|
+
// $group: Math
|
|
462
|
+
// $doc: Compute the sign of a number
|
|
463
|
+
// $arg x: The number
|
|
464
|
+
// $return: -1 for a negative number, 1 for a positive number, and 0 for zero
|
|
465
|
+
'mathSign': ([x]) => Math.sign(x),
|
|
466
|
+
|
|
467
|
+
// $function: mathSin
|
|
468
|
+
// $group: Math
|
|
469
|
+
// $doc: Compute the sine of an angle, in radians
|
|
470
|
+
// $arg x: The angle, in radians
|
|
471
|
+
// $return: The sine of the angle
|
|
472
|
+
'mathSin': ([x]) => Math.sin(x),
|
|
473
|
+
|
|
474
|
+
// $function: mathSqrt
|
|
475
|
+
// $group: Math
|
|
476
|
+
// $doc: Compute the square root of a number
|
|
477
|
+
// $arg x: The number
|
|
478
|
+
// $return: The square root of the number
|
|
479
|
+
'mathSqrt': ([x]) => Math.sqrt(x),
|
|
480
|
+
|
|
481
|
+
// $function: mathTan
|
|
482
|
+
// $group: Math
|
|
483
|
+
// $doc: Compute the tangent of an angle, in radians
|
|
484
|
+
// $arg x: The angle, in radians
|
|
485
|
+
// $return: The tangent of the angle
|
|
486
|
+
'mathTan': ([x]) => Math.tan(x),
|
|
487
|
+
|
|
488
|
+
|
|
489
|
+
//
|
|
490
|
+
// Number functions
|
|
491
|
+
//
|
|
492
|
+
|
|
493
|
+
// $function: numberParseFloat
|
|
494
|
+
// $group: Number
|
|
495
|
+
// $doc: Parse a string as a floating point number
|
|
496
|
+
// $arg string: The string
|
|
497
|
+
// $return: The number
|
|
498
|
+
'numberParseFloat': ([string]) => Number.parseFloat(string),
|
|
499
|
+
|
|
500
|
+
// $function: numberParseInt
|
|
501
|
+
// $group: Number
|
|
502
|
+
// $doc: Parse a string as an integer
|
|
503
|
+
// $arg string: The string
|
|
504
|
+
// $arg radix: Optional (default is 10). The number base.
|
|
505
|
+
// $return: The integer
|
|
506
|
+
'numberParseInt': ([string, radix = 10]) => Number.parseInt(string, radix),
|
|
507
|
+
|
|
508
|
+
// $function: numberToFixed
|
|
509
|
+
// $group: Number
|
|
510
|
+
// $doc: Format a number using fixed-point notation
|
|
511
|
+
// $arg x: The number
|
|
512
|
+
// $arg digits: Optional (default is 2). The number of digits to appear after the decimal point.
|
|
513
|
+
// $arg trim: Optional (default is false). If true, trim trailing zeroes and decimal point.
|
|
514
|
+
// $return: The fixed-point notation string
|
|
515
|
+
'numberToFixed': ([x, digits = 2, trim = false]) => {
|
|
516
|
+
let result = null;
|
|
517
|
+
if (typeof x === 'number') {
|
|
518
|
+
result = x.toFixed(digits);
|
|
519
|
+
if (trim) {
|
|
520
|
+
result = result.replace(rNumberCleanup, '');
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
return result;
|
|
524
|
+
},
|
|
525
|
+
|
|
526
|
+
|
|
527
|
+
//
|
|
528
|
+
// Object functions
|
|
529
|
+
//
|
|
530
|
+
|
|
531
|
+
// $function: objectAssign
|
|
532
|
+
// $group: Object
|
|
533
|
+
// $doc: Assign the keys/values of one object to another
|
|
534
|
+
// $arg object: The object to assign to
|
|
535
|
+
// $arg object2: The object to assign
|
|
536
|
+
// $return: The updated object
|
|
537
|
+
'objectAssign': ([object, object2]) => {
|
|
538
|
+
if (object !== null && typeof object === 'object' && !Array.isArray(object) &&
|
|
539
|
+
object2 !== null && typeof object2 === 'object' && !Array.isArray(object2)) {
|
|
540
|
+
return Object.assign(object, object2);
|
|
541
|
+
}
|
|
542
|
+
return null;
|
|
543
|
+
},
|
|
544
|
+
|
|
545
|
+
// $function: objectCopy
|
|
546
|
+
// $group: Object
|
|
547
|
+
// $doc: Create a copy of an object
|
|
548
|
+
// $arg object: The object to copy
|
|
549
|
+
// $return: The object copy
|
|
550
|
+
'objectCopy': ([object]) => (object !== null && typeof object === 'object' && !Array.isArray(object) ? {...object} : null),
|
|
551
|
+
|
|
552
|
+
// $function: objectDelete
|
|
553
|
+
// $group: Object
|
|
554
|
+
// $doc: Delete an object key
|
|
555
|
+
// $arg object: The object
|
|
556
|
+
// $arg key: The key to delete
|
|
557
|
+
'objectDelete': ([object, key]) => {
|
|
558
|
+
if (object !== null && typeof object === 'object' && !Array.isArray(object)) {
|
|
559
|
+
delete object[key];
|
|
560
|
+
}
|
|
561
|
+
},
|
|
562
|
+
|
|
563
|
+
// $function: objectGet
|
|
564
|
+
// $group: Object
|
|
565
|
+
// $doc: Get an object key's value
|
|
566
|
+
// $arg object: The object
|
|
567
|
+
// $arg key: The key
|
|
568
|
+
// $arg defaultValue: The default value (optional)
|
|
569
|
+
// $return: The value or null if the key does not exist
|
|
570
|
+
'objectGet': ([object, key, defaultValue = null]) => (
|
|
571
|
+
object !== null && typeof object === 'object' ? (Object.hasOwn(object, key) ? object[key] : defaultValue) : null
|
|
572
|
+
),
|
|
573
|
+
|
|
574
|
+
// $function: objectHas
|
|
575
|
+
// $group: Object
|
|
576
|
+
// $doc: Test if an object contains a key
|
|
577
|
+
// $arg object: The object
|
|
578
|
+
// $arg key: The key
|
|
579
|
+
// $return: true if the object contains the key, false otherwise
|
|
580
|
+
'objectHas': ([object, key]) => (object !== null && typeof object === 'object' && Object.hasOwn(object, key)),
|
|
581
|
+
|
|
582
|
+
// $function: objectKeys
|
|
583
|
+
// $group: Object
|
|
584
|
+
// $doc: Get an object's keys
|
|
585
|
+
// $arg object: The object
|
|
586
|
+
// $return: The array of keys
|
|
587
|
+
'objectKeys': ([object]) => (object !== null && typeof object === 'object' && !Array.isArray(object) ? Object.keys(object) : null),
|
|
588
|
+
|
|
589
|
+
// $function: objectNew
|
|
590
|
+
// $group: Object
|
|
591
|
+
// $doc: Create a new object
|
|
592
|
+
// $arg keyValues: The object's initial key and value arguments
|
|
593
|
+
// $return: The new object
|
|
594
|
+
'objectNew': (keyValues) => {
|
|
595
|
+
const object = {};
|
|
596
|
+
for (let ix = 0; ix < keyValues.length; ix += 2) {
|
|
597
|
+
object[keyValues[ix]] = (ix + 1 < keyValues.length ? keyValues[ix + 1] : null);
|
|
598
|
+
}
|
|
599
|
+
return object;
|
|
600
|
+
},
|
|
601
|
+
|
|
602
|
+
// $function: objectSet
|
|
603
|
+
// $group: Object
|
|
604
|
+
// $doc: Set an object key's value
|
|
605
|
+
// $arg object: The object
|
|
606
|
+
// $arg key: The key
|
|
607
|
+
// $arg value: The value to set
|
|
608
|
+
// $return: The value to set
|
|
609
|
+
'objectSet': ([object, key, value]) => {
|
|
610
|
+
if (object !== null && typeof object === 'object' && !Array.isArray(object)) {
|
|
611
|
+
object[key] = value;
|
|
612
|
+
return value;
|
|
613
|
+
}
|
|
614
|
+
return null;
|
|
615
|
+
},
|
|
616
|
+
|
|
617
|
+
|
|
618
|
+
//
|
|
619
|
+
// Regular expression functions
|
|
620
|
+
//
|
|
621
|
+
|
|
622
|
+
// $function: regexEscape
|
|
623
|
+
// $group: Regex
|
|
624
|
+
// $doc: Escape a string for use in a regular expression
|
|
625
|
+
// $arg string: The string to escape
|
|
626
|
+
// $return: The escaped string
|
|
627
|
+
'regexEscape': ([string]) => (typeof string === 'string' ? string.replace(reRegexEscape, '\\$&') : null),
|
|
628
|
+
|
|
629
|
+
// $function: regexMatch
|
|
630
|
+
// $group: Regex
|
|
631
|
+
// $doc: Find the first match of a regular expression in a string
|
|
632
|
+
// $arg regex: The regular expression
|
|
633
|
+
// $arg string: The string
|
|
634
|
+
// $return: The [match object
|
|
635
|
+
// $return: ](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/match#return_value)
|
|
636
|
+
// $return: or null if no matches are found
|
|
637
|
+
'regexMatch': ([regex, string]) => (typeof string === 'string' ? string.match(regex) : null),
|
|
638
|
+
|
|
639
|
+
// $function: regexMatchAll
|
|
640
|
+
// $group: Regex
|
|
641
|
+
// $doc: Find all matches of regular expression in a string
|
|
642
|
+
// $arg regex: The regular expression
|
|
643
|
+
// $arg string: The string
|
|
644
|
+
// $return: The [match object
|
|
645
|
+
// $return: ](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/match#return_value)
|
|
646
|
+
// $return: array or null if no matches are found
|
|
647
|
+
'regexMatchAll': ([regex, string]) => (typeof string === 'string' ? Array.from(string.matchAll(regex)) : null),
|
|
648
|
+
|
|
649
|
+
// $function: regexNew
|
|
650
|
+
// $group: Regex
|
|
651
|
+
// $doc: Create a regular expression
|
|
652
|
+
// $arg pattern: The regular expression pattern string
|
|
653
|
+
// $arg flags: The [regular expression flags
|
|
654
|
+
// $arg flags: ](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#advanced_searching_with_flags)
|
|
655
|
+
// $return: The regular expression or null if the pattern is invalid
|
|
656
|
+
'regexNew': ([pattern, flags]) => new RegExp(pattern, flags),
|
|
657
|
+
|
|
658
|
+
// $function: regexTest
|
|
659
|
+
// $group: Regex
|
|
660
|
+
// $doc: Test if a regular expression matches a string
|
|
661
|
+
// $arg regex: The regular expression
|
|
662
|
+
// $arg string: The string
|
|
663
|
+
// $return: true if the regular expression matches, false otherwise
|
|
664
|
+
'regexTest': ([regex, string]) => (regex instanceof RegExp ? regex.test(string) : null),
|
|
665
|
+
|
|
666
|
+
|
|
667
|
+
//
|
|
668
|
+
// Runtime functions
|
|
669
|
+
//
|
|
670
|
+
|
|
671
|
+
// $function: runtimeGetGlobal
|
|
672
|
+
// $group: Runtime
|
|
673
|
+
// $doc: Get a global variable value
|
|
674
|
+
// $arg name: The global variable name
|
|
675
|
+
// $return: The global variable's value or null if it does not exist
|
|
676
|
+
'runtimeGetGlobal': ([name], options) => {
|
|
677
|
+
const globals = (options !== null ? (options.globals ?? null) : null);
|
|
678
|
+
return (globals !== null ? (globals[name] ?? null) : null);
|
|
679
|
+
},
|
|
680
|
+
|
|
681
|
+
// $function: runtimeSetGlobal
|
|
682
|
+
// $group: Runtime
|
|
683
|
+
// $doc: Set a global variable value
|
|
684
|
+
// $arg name: The global variable name
|
|
685
|
+
// $arg value: The global variable's value
|
|
686
|
+
// $return: The global variable's value
|
|
687
|
+
'runtimeSetGlobal': ([name, value], options) => {
|
|
688
|
+
if (options !== null) {
|
|
689
|
+
const globals = options.globals ?? null;
|
|
690
|
+
if (globals !== null) {
|
|
691
|
+
globals[name] = value;
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
return value;
|
|
695
|
+
},
|
|
696
|
+
|
|
697
|
+
|
|
698
|
+
//
|
|
699
|
+
// Schema functions
|
|
700
|
+
//
|
|
701
|
+
|
|
702
|
+
// $function: schemaParse
|
|
703
|
+
// $group: Schema
|
|
704
|
+
// $doc: Parse the [Schema Markdown](https://craigahobbs.github.io/schema-markdown-js/language/) text
|
|
705
|
+
// $arg lines: The [Schema Markdown](https://craigahobbs.github.io/schema-markdown-js/language/)
|
|
706
|
+
// $arg lines: text lines (may contain nested arrays of un-split lines)
|
|
707
|
+
// $return: The schema's [type model](https://craigahobbs.github.io/schema-markdown-doc/doc/#var.vName='Types')
|
|
708
|
+
'schemaParse': (lines) => parseSchemaMarkdown(lines),
|
|
709
|
+
|
|
710
|
+
// $function: schemaParseEx
|
|
711
|
+
// $group: Schema
|
|
712
|
+
// $doc: Parse the [Schema Markdown](https://craigahobbs.github.io/schema-markdown-js/language/) text with options
|
|
713
|
+
// $arg lines: The array of [Schema Markdown](https://craigahobbs.github.io/schema-markdown-js/language/)
|
|
714
|
+
// $arg lines: text lines (may contain nested arrays of un-split lines)
|
|
715
|
+
// $arg types: Optional. The [type model](https://craigahobbs.github.io/schema-markdown-doc/doc/#var.vName='Types').
|
|
716
|
+
// $arg filename: Optional (default is ""). The file name.
|
|
717
|
+
// $return: The schema's [type model](https://craigahobbs.github.io/schema-markdown-doc/doc/#var.vName='Types')
|
|
718
|
+
'schemaParseEx': ([lines, types = {}, filename = '']) => parseSchemaMarkdown(lines, {types, filename}),
|
|
719
|
+
|
|
720
|
+
// $function: schemaTypeModel
|
|
721
|
+
// $group: Schema
|
|
722
|
+
// $doc: Get the [Schema Markdown Type Model](https://craigahobbs.github.io/schema-markdown-doc/doc/#var.vName='Types')
|
|
723
|
+
// $return: The [Schema Markdown Type Model](https://craigahobbs.github.io/schema-markdown-doc/doc/#var.vName='Types')
|
|
724
|
+
'schemaTypeModel': () => typeModel,
|
|
725
|
+
|
|
726
|
+
// $function: schemaValidate
|
|
727
|
+
// $group: Schema
|
|
728
|
+
// $doc: Validate an object to a schema type
|
|
729
|
+
// $arg types: The [type model](https://craigahobbs.github.io/schema-markdown-doc/doc/#var.vName='Types')
|
|
730
|
+
// $arg typeName: The type name
|
|
731
|
+
// $arg value: The object to validate
|
|
732
|
+
// $return: The validated object or null if validation fails
|
|
733
|
+
'schemaValidate': ([types, typeName, value]) => validateType(types, typeName, value),
|
|
734
|
+
|
|
735
|
+
// $function: schemaValidateTypeModel
|
|
736
|
+
// $group: Schema
|
|
737
|
+
// $doc: Validate a [Schema Markdown Type Model](https://craigahobbs.github.io/schema-markdown-doc/doc/#var.vName='Types')
|
|
738
|
+
// $arg types: The [type model](https://craigahobbs.github.io/schema-markdown-doc/doc/#var.vName='Types') to validate
|
|
739
|
+
// $return: The validated [type model](https://craigahobbs.github.io/schema-markdown-doc/doc/#var.vName='Types')
|
|
740
|
+
'schemaValidateTypeModel': ([types]) => validateTypeModel(types),
|
|
741
|
+
|
|
742
|
+
|
|
743
|
+
//
|
|
744
|
+
// String functions
|
|
745
|
+
//
|
|
746
|
+
|
|
747
|
+
// $function: stringCharCodeAt
|
|
748
|
+
// $group: String
|
|
749
|
+
// $doc: Get a string index's character code
|
|
750
|
+
// $arg string: The string
|
|
751
|
+
// $arg index: The character index
|
|
752
|
+
// $return: The character code
|
|
753
|
+
'stringCharCodeAt': ([string, index]) => (typeof string === 'string' ? string.charCodeAt(index) : null),
|
|
754
|
+
|
|
755
|
+
// $function: stringEndsWith
|
|
756
|
+
// $group: String
|
|
757
|
+
// $doc: Determine if a string ends with a search string
|
|
758
|
+
// $arg string: The string
|
|
759
|
+
// $arg searchString: The search string
|
|
760
|
+
// $return: true if the string ends with the search string, false otherwise
|
|
761
|
+
'stringEndsWith': ([string, searchString]) => (typeof string === 'string' ? string.endsWith(searchString) : null),
|
|
762
|
+
|
|
763
|
+
// $function: stringFromCharCode
|
|
764
|
+
// $group: String
|
|
765
|
+
// $doc: Create a string from the character code arguments
|
|
766
|
+
// $arg charCodes: The character codes
|
|
767
|
+
// $return: The new string
|
|
768
|
+
'stringFromCharCode': (charCodes) => String.fromCharCode(...charCodes),
|
|
769
|
+
|
|
770
|
+
// $function: stringIndexOf
|
|
771
|
+
// $group: String
|
|
772
|
+
// $doc: Find the first index of a search string in a string
|
|
773
|
+
// $arg string: The string
|
|
774
|
+
// $arg searchString: The search string
|
|
775
|
+
// $arg index: Optional (default is 0). The index at which to start the search.
|
|
776
|
+
// $return: The first index of the search string; -1 if not found.
|
|
777
|
+
'stringIndexOf': ([string, searchString, index]) => (typeof string === 'string' ? string.indexOf(searchString, index) : null),
|
|
778
|
+
|
|
779
|
+
// $function: stringLastIndexOf
|
|
780
|
+
// $group: String
|
|
781
|
+
// $doc: Find the last index of a search string in a string
|
|
782
|
+
// $arg string: The string
|
|
783
|
+
// $arg searchString: The search string
|
|
784
|
+
// $arg index: Optional (default is the end of the string). The index at which to start the search.
|
|
785
|
+
// $return: The last index of the search string; -1 if not found.
|
|
786
|
+
'stringLastIndexOf': ([string, searchString, index]) => (
|
|
787
|
+
typeof string === 'string' ? string.lastIndexOf(searchString, index) : null
|
|
788
|
+
),
|
|
789
|
+
|
|
790
|
+
// $function: stringLength
|
|
791
|
+
// $group: String
|
|
792
|
+
// $doc: Get the length of a string
|
|
793
|
+
// $arg string: The string
|
|
794
|
+
// $return: The string's length
|
|
795
|
+
'stringLength': ([string]) => (typeof string === 'string' ? string.length : null),
|
|
796
|
+
|
|
797
|
+
// $function: stringLower
|
|
798
|
+
// $group: String
|
|
799
|
+
// $doc: Convert a string to lower-case
|
|
800
|
+
// $arg string: The string
|
|
801
|
+
// $return: The lower-case string
|
|
802
|
+
'stringLower': ([string]) => (typeof string === 'string' ? string.toLowerCase() : null),
|
|
803
|
+
|
|
804
|
+
// $function: stringNew
|
|
805
|
+
// $group: String
|
|
806
|
+
// $doc: Create a new string from a value
|
|
807
|
+
// $arg value: The value
|
|
808
|
+
// $return: The new string
|
|
809
|
+
'stringNew': ([value]) => `${value}`,
|
|
810
|
+
|
|
811
|
+
// $function: stringRepeat
|
|
812
|
+
// $group: String
|
|
813
|
+
// $doc: Repeat a string
|
|
814
|
+
// $arg string: The string to repeat
|
|
815
|
+
// $arg count: The number of times to repeat the string
|
|
816
|
+
// $return: The repeated string
|
|
817
|
+
'stringRepeat': ([string, count]) => (typeof string === 'string' ? string.repeat(count) : null),
|
|
818
|
+
|
|
819
|
+
// $function: stringReplace
|
|
820
|
+
// $group: String
|
|
821
|
+
// $doc: Replace all instances of a string with another string
|
|
822
|
+
// $arg string: The string to update
|
|
823
|
+
// $arg substr: The string to replace
|
|
824
|
+
// $arg newSubstr: The replacement string
|
|
825
|
+
// $return: The updated string
|
|
826
|
+
'stringReplace': ([string, substr, newSubstr], options) => {
|
|
827
|
+
if (typeof string !== 'string') {
|
|
828
|
+
return null;
|
|
829
|
+
}
|
|
830
|
+
if (typeof newSubstr === 'function') {
|
|
831
|
+
const replacerFunction = (...args) => newSubstr(args, options);
|
|
832
|
+
return string.replaceAll(substr, replacerFunction);
|
|
833
|
+
}
|
|
834
|
+
return string.replaceAll(substr, newSubstr);
|
|
835
|
+
},
|
|
836
|
+
|
|
837
|
+
// $function: stringSlice
|
|
838
|
+
// $group: String
|
|
839
|
+
// $doc: Copy a portion of a string
|
|
840
|
+
// $arg string: The string
|
|
841
|
+
// $arg start: Optional (default is 0). The start index of the slice.
|
|
842
|
+
// $arg end: Optional (default is the end of the string). The end index of the slice.
|
|
843
|
+
// $return: The new string slice
|
|
844
|
+
'stringSlice': ([string, beginIndex, endIndex]) => (typeof string === 'string' ? string.slice(beginIndex, endIndex) : null),
|
|
845
|
+
|
|
846
|
+
// $function: stringSplit
|
|
847
|
+
// $group: String
|
|
848
|
+
// $doc: Split a string
|
|
849
|
+
// $arg string: The string to split
|
|
850
|
+
// $arg separator: The separator string or regular expression
|
|
851
|
+
// $arg limit: The maximum number of strings to split into
|
|
852
|
+
// $return: The array of split-out strings
|
|
853
|
+
'stringSplit': ([string, separator, limit]) => (typeof string === 'string' ? string.split(separator, limit) : null),
|
|
854
|
+
|
|
855
|
+
// $function: stringStartsWith
|
|
856
|
+
// $group: String
|
|
857
|
+
// $doc: Determine if a string starts with a search string
|
|
858
|
+
// $arg string: The string
|
|
859
|
+
// $arg searchString: The search string
|
|
860
|
+
// $return: true if the string starts with the search string, false otherwise
|
|
861
|
+
'stringStartsWith': ([string, searchString]) => (typeof string === 'string' ? string.startsWith(searchString) : null),
|
|
862
|
+
|
|
863
|
+
// $function: stringTrim
|
|
864
|
+
// $group: String
|
|
865
|
+
// $doc: Trim the whitespace from the beginning and end of a string
|
|
866
|
+
// $arg string: The string
|
|
867
|
+
// $return: The trimmed string
|
|
868
|
+
'stringTrim': ([string]) => (typeof string === 'string' ? string.trim() : null),
|
|
869
|
+
|
|
870
|
+
// $function: stringUpper
|
|
871
|
+
// $group: String
|
|
872
|
+
// $doc: Convert a string to upper-case
|
|
873
|
+
// $arg string: The string
|
|
874
|
+
// $return: The upper-case string
|
|
875
|
+
'stringUpper': ([string]) => (typeof string === 'string' ? string.toUpperCase() : null),
|
|
876
|
+
|
|
877
|
+
|
|
878
|
+
//
|
|
879
|
+
// URL functions
|
|
880
|
+
//
|
|
881
|
+
|
|
882
|
+
// $function: urlEncode
|
|
883
|
+
// $group: URL
|
|
884
|
+
// $doc: Encode a URL
|
|
885
|
+
// $arg url: The URL string
|
|
886
|
+
// $arg extra: Optional (default is true). If true, encode extra characters for wider compatibility.
|
|
887
|
+
// $return: The encoded URL string
|
|
888
|
+
'urlEncode': ([url, extra = true]) => {
|
|
889
|
+
let urlEncoded = encodeURI(url);
|
|
890
|
+
if (extra) {
|
|
891
|
+
// Replace ')' with '%29' for Markdown links
|
|
892
|
+
urlEncoded = urlEncoded.replaceAll(')', '%29');
|
|
893
|
+
}
|
|
894
|
+
return urlEncoded;
|
|
895
|
+
},
|
|
896
|
+
|
|
897
|
+
// $function: urlEncodeComponent
|
|
898
|
+
// $group: URL
|
|
899
|
+
// $doc: Encode a URL component
|
|
900
|
+
// $arg url: The URL component string
|
|
901
|
+
// $arg extra: Optional (default is true). If true, encode extra characters for wider compatibility.
|
|
902
|
+
// $return: The encoded URL component string
|
|
903
|
+
'urlEncodeComponent': ([urlComponent, extra = true]) => {
|
|
904
|
+
let urlComponentEncoded = encodeURIComponent(urlComponent);
|
|
905
|
+
if (extra) {
|
|
906
|
+
// Replace ')' with '%29' for Markdown links
|
|
907
|
+
urlComponentEncoded = urlComponentEncoded.replaceAll(')', '%29');
|
|
908
|
+
}
|
|
909
|
+
return urlComponentEncoded;
|
|
910
|
+
}
|
|
911
|
+
};
|
|
912
|
+
|
|
913
|
+
|
|
914
|
+
// Regex escape regular expression
|
|
915
|
+
const reRegexEscape = /[.*+?^${}()|[\]\\]/g;
|
|
916
|
+
|
|
917
|
+
|
|
918
|
+
// Fixed-number trim regular expression
|
|
919
|
+
const rNumberCleanup = /\.0*$/;
|
|
920
|
+
|
|
921
|
+
|
|
922
|
+
// The built-in expression function name script function name map
|
|
923
|
+
export const expressionFunctionMap = {
|
|
924
|
+
'abs': 'mathAbs',
|
|
925
|
+
'acos': 'mathAcos',
|
|
926
|
+
'asin': 'mathAsin',
|
|
927
|
+
'atan': 'mathAtan',
|
|
928
|
+
'atan2': 'mathAtan2',
|
|
929
|
+
'ceil': 'mathCeil',
|
|
930
|
+
'charCodeAt': 'stringCharCodeAt',
|
|
931
|
+
'cos': 'mathCos',
|
|
932
|
+
'date': 'datetimeNew',
|
|
933
|
+
'day': 'datetimeDay',
|
|
934
|
+
'endsWith': 'stringEndsWith',
|
|
935
|
+
'if': 'if',
|
|
936
|
+
'indexOf': 'stringIndexOf',
|
|
937
|
+
'fixed': 'numberToFixed',
|
|
938
|
+
'floor': 'mathFloor',
|
|
939
|
+
'fromCharCode': 'stringFromCharCode',
|
|
940
|
+
'hour': 'datetimeHour',
|
|
941
|
+
'lastIndexOf': 'stringLastIndexOf',
|
|
942
|
+
'len': 'stringLength',
|
|
943
|
+
'lower': 'stringLower',
|
|
944
|
+
'ln': 'mathLn',
|
|
945
|
+
'log': 'mathLog',
|
|
946
|
+
'max': 'mathMax',
|
|
947
|
+
'min': 'mathMin',
|
|
948
|
+
'minute': 'datetimeMinute',
|
|
949
|
+
'month': 'datetimeMonth',
|
|
950
|
+
'now': 'datetimeNow',
|
|
951
|
+
'parseInt': 'numberParseInt',
|
|
952
|
+
'parseFloat': 'numberParseFloat',
|
|
953
|
+
'pi': 'mathPi',
|
|
954
|
+
'rand': 'mathRandom',
|
|
955
|
+
'replace': 'stringReplace',
|
|
956
|
+
'rept': 'stringRepeat',
|
|
957
|
+
'round': 'mathRound',
|
|
958
|
+
'second': 'datetimeSecond',
|
|
959
|
+
'sign': 'mathSign',
|
|
960
|
+
'sin': 'mathSin',
|
|
961
|
+
'slice': 'stringSlice',
|
|
962
|
+
'sqrt': 'mathSqrt',
|
|
963
|
+
'startsWith': 'stringStartsWith',
|
|
964
|
+
'text': 'stringNew',
|
|
965
|
+
'tan': 'mathTan',
|
|
966
|
+
'today': 'datetimeToday',
|
|
967
|
+
'trim': 'stringTrim',
|
|
968
|
+
'upper': 'stringUpper',
|
|
969
|
+
'urlEncode': 'urlEncode',
|
|
970
|
+
'urlEncodeComponent': 'urlEncodeComponent',
|
|
971
|
+
'year': 'datetimeYear'
|
|
972
|
+
};
|
|
973
|
+
|
|
974
|
+
|
|
975
|
+
// The built-in expression functions
|
|
976
|
+
export const expressionFunctions = Object.fromEntries(Object.entries(expressionFunctionMap).map(
|
|
977
|
+
([exprFnName, scriptFnName]) => [exprFnName, scriptFunctions[scriptFnName] ?? null]
|
|
978
|
+
).filter(([, exprFn]) => exprFn !== null));
|