bare-script 0.9.0__py3-none-any.whl
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.
- bare_script/__init__.py +33 -0
- bare_script/__main__.py +12 -0
- bare_script/bare.py +109 -0
- bare_script/baredoc.py +137 -0
- bare_script/library.py +1912 -0
- bare_script/model.py +257 -0
- bare_script/options.py +108 -0
- bare_script/parser.py +680 -0
- bare_script/runtime.py +345 -0
- bare_script/value.py +199 -0
- bare_script-0.9.0.dist-info/LICENSE +21 -0
- bare_script-0.9.0.dist-info/METADATA +189 -0
- bare_script-0.9.0.dist-info/RECORD +16 -0
- bare_script-0.9.0.dist-info/WHEEL +5 -0
- bare_script-0.9.0.dist-info/entry_points.txt +3 -0
- bare_script-0.9.0.dist-info/top_level.txt +1 -0
bare_script/library.py
ADDED
|
@@ -0,0 +1,1912 @@
|
|
|
1
|
+
# Licensed under the MIT License
|
|
2
|
+
# https://github.com/craigahobbs/bare-script-py/blob/main/LICENSE
|
|
3
|
+
|
|
4
|
+
"""
|
|
5
|
+
The BareScript library
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import calendar
|
|
9
|
+
import datetime
|
|
10
|
+
import functools
|
|
11
|
+
import json
|
|
12
|
+
import math
|
|
13
|
+
import random
|
|
14
|
+
import re
|
|
15
|
+
import urllib
|
|
16
|
+
|
|
17
|
+
from schema_markdown import TYPE_MODEL, parse_schema_markdown, validate_type, validate_type_model
|
|
18
|
+
|
|
19
|
+
from .value import R_NUMBER_CLEANUP, REGEX_TYPE, round_number, value_boolean, value_compare, value_is, value_json, value_string, value_type
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
# The default maximum statements for executeScript
|
|
23
|
+
DEFAULT_MAX_STATEMENTS = 1e9
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def default_args(args, defaults, last_arg_array=False):
|
|
27
|
+
"""
|
|
28
|
+
Helper function to fill-in default arguments
|
|
29
|
+
"""
|
|
30
|
+
len_args = len(args)
|
|
31
|
+
yield from ((args[ix] if ix < len_args else default) for ix, default in enumerate(defaults))
|
|
32
|
+
if last_arg_array:
|
|
33
|
+
yield args[len(defaults):]
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
#
|
|
37
|
+
# Array functions
|
|
38
|
+
#
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
# $function: arrayCopy
|
|
42
|
+
# $group: Array
|
|
43
|
+
# $doc: Create a copy of an array
|
|
44
|
+
# $arg array: The array to copy
|
|
45
|
+
# $return: The array copy
|
|
46
|
+
def _array_copy(args, unused_options):
|
|
47
|
+
array, = default_args(args, (None,))
|
|
48
|
+
if not isinstance(array, list):
|
|
49
|
+
return None
|
|
50
|
+
|
|
51
|
+
return list(array)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
# $function: arrayExtend
|
|
55
|
+
# $group: Array
|
|
56
|
+
# $doc: Extend one array with another
|
|
57
|
+
# $arg array: The array to extend
|
|
58
|
+
# $arg array2: The array to extend with
|
|
59
|
+
# $return: The extended array
|
|
60
|
+
def _array_extend(args, unused_options):
|
|
61
|
+
array, array2 = default_args(args, (None, None))
|
|
62
|
+
if not isinstance(array, list) or not isinstance(array2, list):
|
|
63
|
+
return None
|
|
64
|
+
|
|
65
|
+
array.extend(array2)
|
|
66
|
+
return array
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
# $function: arrayGet
|
|
70
|
+
# $group: Array
|
|
71
|
+
# $doc: Get an array element
|
|
72
|
+
# $arg array: The array
|
|
73
|
+
# $arg index: The array element's index
|
|
74
|
+
# $return: The array element
|
|
75
|
+
def _array_get(args, unused_options):
|
|
76
|
+
array, index = default_args(args, (None, None))
|
|
77
|
+
if not isinstance(array, list) or not isinstance(index, (int, float)) or int(index) != index or index < 0 or index >= len(array):
|
|
78
|
+
return None
|
|
79
|
+
|
|
80
|
+
return array[int(index)]
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
# $function: arrayIndexOf
|
|
84
|
+
# $group: Array
|
|
85
|
+
# $doc: Find the index of a value in an array
|
|
86
|
+
# $arg array: The array
|
|
87
|
+
# $arg value: The value to find in the array, or a match function, f(value) -> bool
|
|
88
|
+
# $arg index: Optional (default is 0). The index at which to start the search.
|
|
89
|
+
# $return: The first index of the value in the array; -1 if not found.
|
|
90
|
+
def _array_index_of(args, options):
|
|
91
|
+
array, value, index = default_args(args, (None, None, 0))
|
|
92
|
+
if not isinstance(array, list) or not isinstance(index, (int, float)) or int(index) != index or index < 0 or index >= len(array):
|
|
93
|
+
return -1
|
|
94
|
+
|
|
95
|
+
if callable(value):
|
|
96
|
+
for ix in range(int(index), len(array)):
|
|
97
|
+
if value([array[ix]], options):
|
|
98
|
+
return ix
|
|
99
|
+
else:
|
|
100
|
+
for ix in range(int(index), len(array)):
|
|
101
|
+
if value_compare(array[ix], value) == 0:
|
|
102
|
+
return ix
|
|
103
|
+
|
|
104
|
+
return -1
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
# $function: arrayJoin
|
|
108
|
+
# $group: Array
|
|
109
|
+
# $doc: Join an array with a separator string
|
|
110
|
+
# $arg array: The array
|
|
111
|
+
# $arg separator: The separator string
|
|
112
|
+
# $return: The joined string
|
|
113
|
+
def _array_join(args, unused_options):
|
|
114
|
+
array, separator = default_args(args, (None, None))
|
|
115
|
+
if not isinstance(array, list) or not isinstance(separator, str):
|
|
116
|
+
return None
|
|
117
|
+
|
|
118
|
+
return separator.join(value_string(value) for value in array)
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
# $function: arrayLastIndexOf
|
|
122
|
+
# $group: Array
|
|
123
|
+
# $doc: Find the last index of a value in an array
|
|
124
|
+
# $arg array: The array
|
|
125
|
+
# $arg value: The value to find in the array, or a match function, f(value) -> bool
|
|
126
|
+
# $arg index: Optional (default is the end of the array). The index at which to start the search.
|
|
127
|
+
# $return: The last index of the value in the array; -1 if not found.
|
|
128
|
+
def _array_last_index_of(args, options):
|
|
129
|
+
array, value, index = default_args(args, (None, None, None))
|
|
130
|
+
if isinstance(array, list) and index is None:
|
|
131
|
+
index = len(array) - 1
|
|
132
|
+
if not isinstance(array, list) or not isinstance(index, (int, float)) or int(index) != index or index < 0 or index >= len(array):
|
|
133
|
+
return -1
|
|
134
|
+
|
|
135
|
+
if callable(value):
|
|
136
|
+
for ix in range(int(index), -1, -1):
|
|
137
|
+
if value([array[ix]], options):
|
|
138
|
+
return ix
|
|
139
|
+
else:
|
|
140
|
+
for ix in range(int(index), -1, -1):
|
|
141
|
+
if value_compare(array[ix], value) == 0:
|
|
142
|
+
return ix
|
|
143
|
+
|
|
144
|
+
return -1
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
# $function: arrayLength
|
|
148
|
+
# $group: Array
|
|
149
|
+
# $doc: Get the length of an array
|
|
150
|
+
# $arg array: The array
|
|
151
|
+
# $return: The array's length; zero if not an array
|
|
152
|
+
def _array_length(args, unused_options):
|
|
153
|
+
array, = default_args(args, (None,))
|
|
154
|
+
if not isinstance(array, list):
|
|
155
|
+
return 0
|
|
156
|
+
|
|
157
|
+
return len(array)
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
# $function: arrayNew
|
|
161
|
+
# $group: Array
|
|
162
|
+
# $doc: Create a new array
|
|
163
|
+
# $arg values...: The new array's values
|
|
164
|
+
# $return: The new array
|
|
165
|
+
def _array_new(args, unused_options):
|
|
166
|
+
return args
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
# $function: arrayNewSize
|
|
170
|
+
# $group: Array
|
|
171
|
+
# $doc: Create a new array of a specific size
|
|
172
|
+
# $arg size: Optional (default is 0). The new array's size.
|
|
173
|
+
# $arg value: Optional (default is 0). The value with which to fill the new array.
|
|
174
|
+
# $return: The new array
|
|
175
|
+
def _array_new_size(args, unused_options):
|
|
176
|
+
size, value = default_args(args, (0, 0))
|
|
177
|
+
if not isinstance(size, (int, float)) or int(size) != size or size < 0:
|
|
178
|
+
return None
|
|
179
|
+
|
|
180
|
+
return list(value for _ in range(int(size)))
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
# $function: arrayPop
|
|
184
|
+
# $group: Array
|
|
185
|
+
# $doc: Remove the last element of the array and return it
|
|
186
|
+
# $arg array: The array
|
|
187
|
+
# $return: The last element of the array; null if the array is empty.
|
|
188
|
+
def _array_pop(args, unused_options):
|
|
189
|
+
array, = default_args(args, (None,))
|
|
190
|
+
if not isinstance(array, list) or len(array) == 0:
|
|
191
|
+
return None
|
|
192
|
+
|
|
193
|
+
return array.pop()
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
# $function: arrayPush
|
|
197
|
+
# $group: Array
|
|
198
|
+
# $doc: Add one or more values to the end of the array
|
|
199
|
+
# $arg array: The array
|
|
200
|
+
# $arg values...: The values to add to the end of the array
|
|
201
|
+
# $return: The array
|
|
202
|
+
def _array_push(args, unused_options):
|
|
203
|
+
array, values = default_args(args, (None,), True)
|
|
204
|
+
if not isinstance(array, list):
|
|
205
|
+
return None
|
|
206
|
+
|
|
207
|
+
array.extend(values)
|
|
208
|
+
return array
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
# $function: arraySet
|
|
212
|
+
# $group: Array
|
|
213
|
+
# $doc: Set an array element value
|
|
214
|
+
# $arg array: The array
|
|
215
|
+
# $arg index: The index of the element to set
|
|
216
|
+
# $arg value: The value to set
|
|
217
|
+
# $return: The value
|
|
218
|
+
def _array_set(args, unused_options):
|
|
219
|
+
array, index, value = default_args(args, (None, None, None))
|
|
220
|
+
if not isinstance(array, list) or index < 0 or index >= len(array):
|
|
221
|
+
return None
|
|
222
|
+
|
|
223
|
+
array[index] = value
|
|
224
|
+
return value
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
# $function: arrayShift
|
|
228
|
+
# $group: Array
|
|
229
|
+
# $doc: Remove the first element of the array and return it
|
|
230
|
+
# $arg array: The array
|
|
231
|
+
# $return: The first element of the array; null if the array is empty.
|
|
232
|
+
def _array_shift(args, unused_options):
|
|
233
|
+
array, = default_args(args, (None,))
|
|
234
|
+
if not isinstance(array, list) or len(array) == 0:
|
|
235
|
+
return None
|
|
236
|
+
|
|
237
|
+
result = array[0]
|
|
238
|
+
del array[0]
|
|
239
|
+
return result
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
# $function: arraySlice
|
|
243
|
+
# $group: Array
|
|
244
|
+
# $doc: Copy a portion of an array
|
|
245
|
+
# $arg array: The array
|
|
246
|
+
# $arg start: Optional (default is 0). The start index of the slice.
|
|
247
|
+
# $arg end: Optional (default is the end of the array). The end index of the slice.
|
|
248
|
+
# $return: The new array slice
|
|
249
|
+
def _array_slice(args, unused_options):
|
|
250
|
+
array, start, end = default_args(args, (None, 0, None))
|
|
251
|
+
if isinstance(array, list) and end is None:
|
|
252
|
+
end = len(array)
|
|
253
|
+
if not isinstance(array, list) or not isinstance(start, (int, float)) or int(start) != start or start < 0 or start >= len(array) or \
|
|
254
|
+
not isinstance(end, (int, float)) or int(end) != end or end < 0 or end > len(array):
|
|
255
|
+
return None
|
|
256
|
+
|
|
257
|
+
return array[int(start):int(end)]
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
# $function: arraySort
|
|
261
|
+
# $group: Array
|
|
262
|
+
# $doc: Sort an array
|
|
263
|
+
# $arg array: The array
|
|
264
|
+
# $arg compareFn: Optional (default is null). The comparison function.
|
|
265
|
+
# $return: The sorted array
|
|
266
|
+
def _array_sort(args, options):
|
|
267
|
+
array, compare_fn = default_args(args, (None, None))
|
|
268
|
+
if not isinstance(array, list) or (compare_fn is not None and not callable(compare_fn)):
|
|
269
|
+
return None
|
|
270
|
+
|
|
271
|
+
if compare_fn is None:
|
|
272
|
+
array.sort(key=functools.cmp_to_key(value_compare))
|
|
273
|
+
else:
|
|
274
|
+
array.sort(key=functools.cmp_to_key(lambda v1, v2: compare_fn([v1, v2], options)))
|
|
275
|
+
return array
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
#
|
|
279
|
+
# Data functions
|
|
280
|
+
#
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
# $function: dataAggregate
|
|
284
|
+
# $group: Data
|
|
285
|
+
# $doc: Aggregate a data array
|
|
286
|
+
# $arg data: The data array
|
|
287
|
+
# $arg aggregation: The [aggregation model](https://craigahobbs.github.io/bare-script-py/library/model.html#var.vName='Aggregation')
|
|
288
|
+
# $return: The aggregated data array
|
|
289
|
+
def _data_aggregate(unused_args, unused_options):
|
|
290
|
+
return None
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
# $function: dataCalculatedField
|
|
294
|
+
# $group: Data
|
|
295
|
+
# $doc: Add a calculated field to a data array
|
|
296
|
+
# $arg data: The data array
|
|
297
|
+
# $arg fieldName: The calculated field name
|
|
298
|
+
# $arg expr: The calculated field expression
|
|
299
|
+
# $arg variables: Optional (default is null). A variables object the expression evaluation.
|
|
300
|
+
# $return: The updated data array
|
|
301
|
+
def _data_calculated_field(unused_args, unused_options):
|
|
302
|
+
return None
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
# $function: dataFilter
|
|
306
|
+
# $group: Data
|
|
307
|
+
# $doc: Filter a data array
|
|
308
|
+
# $arg data: The data array
|
|
309
|
+
# $arg expr: The filter expression
|
|
310
|
+
# $arg variables: Optional (default is null). A variables object the expression evaluation.
|
|
311
|
+
# $return: The filtered data array
|
|
312
|
+
def _data_filter(unused_args, unused_options):
|
|
313
|
+
return None
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
# $function: dataJoin
|
|
317
|
+
# $group: Data
|
|
318
|
+
# $doc: Join two data arrays
|
|
319
|
+
# $arg leftData: The left data array
|
|
320
|
+
# $arg rightData: The right data array
|
|
321
|
+
# $arg joinExpr: The [join expression](https://craigahobbs.github.io/bare-script/language/#expressions)
|
|
322
|
+
# $arg rightExpr: Optional (default is null).
|
|
323
|
+
# $arg rightExpr: The right [join expression](https://craigahobbs.github.io/bare-script/language/#expressions)
|
|
324
|
+
# $arg isLeftJoin: Optional (default is false). If true, perform a left join (always include left row).
|
|
325
|
+
# $arg variables: Optional (default is null). A variables object for join expression evaluation.
|
|
326
|
+
# $return: The joined data array
|
|
327
|
+
def _data_join(unused_args, unused_options):
|
|
328
|
+
return None
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
# $function: dataParseCSV
|
|
332
|
+
# $group: Data
|
|
333
|
+
# $doc: Parse CSV text to a data array
|
|
334
|
+
# $arg text...: The CSV text
|
|
335
|
+
# $return: The data array
|
|
336
|
+
def _data_parse_csv(unused_args, unused_options):
|
|
337
|
+
return None
|
|
338
|
+
|
|
339
|
+
|
|
340
|
+
# $function: dataSort
|
|
341
|
+
# $group: Data
|
|
342
|
+
# $doc: Sort a data array
|
|
343
|
+
# $arg data: The data array
|
|
344
|
+
# $arg sorts: The sort field-name/descending-sort tuples
|
|
345
|
+
# $return: The sorted data array
|
|
346
|
+
def _data_sort(unused_args, unused_options):
|
|
347
|
+
return None
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
# $function: dataTop
|
|
351
|
+
# $group: Data
|
|
352
|
+
# $doc: Keep the top rows for each category
|
|
353
|
+
# $arg data: The data array
|
|
354
|
+
# $arg count: The number of rows to keep
|
|
355
|
+
# $arg categoryFields: Optional (default is null). The category fields.
|
|
356
|
+
# $return: The top data array
|
|
357
|
+
def _data_top(unused_args, unused_options):
|
|
358
|
+
return None
|
|
359
|
+
|
|
360
|
+
|
|
361
|
+
# $function: dataValidate
|
|
362
|
+
# $group: Data
|
|
363
|
+
# $doc: Validate a data array
|
|
364
|
+
# $arg data: The data array
|
|
365
|
+
# $return: The validated data array
|
|
366
|
+
def _data_validate(unused_args, unused_options):
|
|
367
|
+
return None
|
|
368
|
+
|
|
369
|
+
|
|
370
|
+
#
|
|
371
|
+
# Datetime functions
|
|
372
|
+
#
|
|
373
|
+
|
|
374
|
+
|
|
375
|
+
# $function: datetimeDay
|
|
376
|
+
# $group: Datetime
|
|
377
|
+
# $doc: Get the day of the month of a datetime
|
|
378
|
+
# $arg datetime: The datetime
|
|
379
|
+
# $return: The day of the month
|
|
380
|
+
def _datetime_day(args, unused_options):
|
|
381
|
+
datetime_, = default_args(args, (None,))
|
|
382
|
+
if not isinstance(datetime_, datetime.datetime):
|
|
383
|
+
return None
|
|
384
|
+
|
|
385
|
+
return datetime_.day
|
|
386
|
+
|
|
387
|
+
|
|
388
|
+
# $function: datetimeHour
|
|
389
|
+
# $group: Datetime
|
|
390
|
+
# $doc: Get the hour of a datetime
|
|
391
|
+
# $arg datetime: The datetime
|
|
392
|
+
# $return: The hour
|
|
393
|
+
def _datetime_hour(args, unused_options):
|
|
394
|
+
datetime_, = default_args(args, (None,))
|
|
395
|
+
if not isinstance(datetime_, datetime.datetime):
|
|
396
|
+
return None
|
|
397
|
+
|
|
398
|
+
return datetime_.hour
|
|
399
|
+
|
|
400
|
+
|
|
401
|
+
# $function: datetimeISOFormat
|
|
402
|
+
# $group: Datetime
|
|
403
|
+
# $doc: Format the datetime as an ISO date/time string
|
|
404
|
+
# $arg datetime: The datetime
|
|
405
|
+
# $arg isDate: If true, format the datetime as an ISO date
|
|
406
|
+
# $return: The formatted datetime string
|
|
407
|
+
def _datetime_iso_format(args, unused_options):
|
|
408
|
+
datetime_, is_date = default_args(args, (None, False))
|
|
409
|
+
if not isinstance(datetime_, datetime.datetime):
|
|
410
|
+
return None
|
|
411
|
+
|
|
412
|
+
if value_boolean(is_date):
|
|
413
|
+
return datetime.date(datetime_.year, datetime_.month, datetime_.day).isoformat()
|
|
414
|
+
return datetime_.astimezone(datetime.timezone.utc).isoformat()
|
|
415
|
+
|
|
416
|
+
|
|
417
|
+
# $function: datetimeISOParse
|
|
418
|
+
# $group: Datetime
|
|
419
|
+
# $doc: Parse an ISO date/time string
|
|
420
|
+
# $arg str: The ISO date/time string
|
|
421
|
+
# $return: The datetime, or null if parsing fails
|
|
422
|
+
def _datetime_iso_parse(args, unused_options):
|
|
423
|
+
string, = default_args(args, (None,))
|
|
424
|
+
if not isinstance(string, str):
|
|
425
|
+
return None
|
|
426
|
+
|
|
427
|
+
try:
|
|
428
|
+
return datetime.datetime.fromisoformat(_R_ZULU.sub('+00:00', string))
|
|
429
|
+
except ValueError:
|
|
430
|
+
return None
|
|
431
|
+
|
|
432
|
+
_R_ZULU = re.compile(r'Z$')
|
|
433
|
+
|
|
434
|
+
|
|
435
|
+
# $function: datetimeMillisecond
|
|
436
|
+
# $group: Datetime
|
|
437
|
+
# $doc: Get the millisecond of a datetime
|
|
438
|
+
# $arg datetime: The datetime
|
|
439
|
+
# $return: The millisecond
|
|
440
|
+
def _datetime_millisecond(args, unused_options):
|
|
441
|
+
datetime_, = default_args(args, (None,))
|
|
442
|
+
if not isinstance(datetime_, datetime.datetime):
|
|
443
|
+
return None
|
|
444
|
+
|
|
445
|
+
return int(round_number(datetime_.microsecond / 1000, 0))
|
|
446
|
+
|
|
447
|
+
|
|
448
|
+
# $function: datetimeMinute
|
|
449
|
+
# $group: Datetime
|
|
450
|
+
# $doc: Get the minute of a datetime
|
|
451
|
+
# $arg datetime: The datetime
|
|
452
|
+
# $return: The minute
|
|
453
|
+
def _datetime_minute(args, unused_options):
|
|
454
|
+
datetime_, = default_args(args, (None,))
|
|
455
|
+
if not isinstance(datetime_, datetime.datetime):
|
|
456
|
+
return None
|
|
457
|
+
|
|
458
|
+
return datetime_.minute
|
|
459
|
+
|
|
460
|
+
|
|
461
|
+
# $function: datetimeMonth
|
|
462
|
+
# $group: Datetime
|
|
463
|
+
# $doc: Get the month (1-12) of a datetime
|
|
464
|
+
# $arg datetime: The datetime
|
|
465
|
+
# $return: The month
|
|
466
|
+
def _datetime_month(args, unused_options):
|
|
467
|
+
datetime_, = default_args(args, (None,))
|
|
468
|
+
if not isinstance(datetime_, datetime.datetime):
|
|
469
|
+
return None
|
|
470
|
+
|
|
471
|
+
return datetime_.month
|
|
472
|
+
|
|
473
|
+
|
|
474
|
+
# $function: datetimeNew
|
|
475
|
+
# $group: Datetime
|
|
476
|
+
# $doc: Create a new datetime
|
|
477
|
+
# $arg year: The full year
|
|
478
|
+
# $arg month: The month (1-12)
|
|
479
|
+
# $arg day: The day of the month
|
|
480
|
+
# $arg hour: Optional (default is 0). The hour (0-23).
|
|
481
|
+
# $arg minute: Optional (default is 0). The minute.
|
|
482
|
+
# $arg second: Optional (default is 0). The second.
|
|
483
|
+
# $arg millisecond: Optional (default is 0). The millisecond.
|
|
484
|
+
# $return: The new datetime
|
|
485
|
+
def _datetime_new(args, unused_options):
|
|
486
|
+
year, month, day, hour, minute, second, millisecond = default_args(args, (None, None, None, 0, 0, 0, 0))
|
|
487
|
+
return _datetime_new_helper(year, month, day, hour, minute, second, millisecond, None)
|
|
488
|
+
|
|
489
|
+
|
|
490
|
+
# $function: datetimeNewUTC
|
|
491
|
+
# $group: Datetime
|
|
492
|
+
# $doc: Create a new UTC datetime
|
|
493
|
+
# $arg year: The full year
|
|
494
|
+
# $arg month: The month (1-12)
|
|
495
|
+
# $arg day: The day of the month
|
|
496
|
+
# $arg hour: Optional (default is 0). The hour (0-23).
|
|
497
|
+
# $arg minute: Optional (default is 0). The minute.
|
|
498
|
+
# $arg second: Optional (default is 0). The second.
|
|
499
|
+
# $arg millisecond: Optional (default is 0). The millisecond.
|
|
500
|
+
# $return: The new UTC datetime
|
|
501
|
+
def _datetime_new_utc(args, unused_options):
|
|
502
|
+
year, month, day, hour, minute, second, millisecond = default_args(args, (None, None, None, 0, 0, 0, 0))
|
|
503
|
+
return _datetime_new_helper(year, month, day, hour, minute, second, millisecond, tzinfo=datetime.timezone.utc)
|
|
504
|
+
|
|
505
|
+
|
|
506
|
+
# datetimeNew helper function
|
|
507
|
+
def _datetime_new_helper(year, month, day, hour, minute, second, millisecond, tzinfo):
|
|
508
|
+
if not isinstance(year, (int, float)) or int(year) != year or \
|
|
509
|
+
not isinstance(month, (int, float)) or int(month) != month or \
|
|
510
|
+
not isinstance(day, (int, float)) or int(day) != day or day < -10000 or day > 10000 or \
|
|
511
|
+
not isinstance(hour, (int, float)) or int(hour) != hour or \
|
|
512
|
+
not isinstance(minute, (int, float)) or int(minute) != minute or \
|
|
513
|
+
not isinstance(second, (int, float)) or int(second) != second or \
|
|
514
|
+
not isinstance(millisecond, (int, float)) or int(millisecond) != millisecond:
|
|
515
|
+
return None
|
|
516
|
+
|
|
517
|
+
# Adjust millisecond
|
|
518
|
+
if millisecond < 0 or millisecond >= 1000:
|
|
519
|
+
extra_seconds = millisecond // 1000
|
|
520
|
+
millisecond -= extra_seconds * 1000
|
|
521
|
+
second += extra_seconds
|
|
522
|
+
|
|
523
|
+
# Adjust seconds
|
|
524
|
+
if second < 0 or second >= 60:
|
|
525
|
+
extra_minutes = second // 60
|
|
526
|
+
second -= extra_minutes * 60
|
|
527
|
+
minute += extra_minutes
|
|
528
|
+
|
|
529
|
+
# Adjust minutes
|
|
530
|
+
if minute < 0 or minute >= 60:
|
|
531
|
+
extra_hours = minute // 60
|
|
532
|
+
minute -= extra_hours * 60
|
|
533
|
+
hour += extra_hours
|
|
534
|
+
|
|
535
|
+
# Adjust hours
|
|
536
|
+
if hour < 0 or hour >= 24:
|
|
537
|
+
extra_days = hour // 24
|
|
538
|
+
hour -= extra_days * 24
|
|
539
|
+
day += extra_days
|
|
540
|
+
|
|
541
|
+
# Adjust month
|
|
542
|
+
if month < 1 or month > 12:
|
|
543
|
+
extra_years = (month - 1) // 12
|
|
544
|
+
month -= extra_years * 12
|
|
545
|
+
year += extra_years
|
|
546
|
+
|
|
547
|
+
# Adjust day
|
|
548
|
+
if day < 1:
|
|
549
|
+
while day < 1:
|
|
550
|
+
year = year if month != 1 else year - 1
|
|
551
|
+
month = month - 1 if month != 1 else 12
|
|
552
|
+
_, month_days = calendar.monthrange(year, month)
|
|
553
|
+
day += month_days
|
|
554
|
+
elif day > 28:
|
|
555
|
+
_, month_days = calendar.monthrange(year, month)
|
|
556
|
+
while day > month_days:
|
|
557
|
+
day -= month_days
|
|
558
|
+
year = year if month != 12 else year + 1
|
|
559
|
+
month = month + 1 if month != 12 else 1
|
|
560
|
+
_, month_days = calendar.monthrange(year, month)
|
|
561
|
+
|
|
562
|
+
# Return the datetime
|
|
563
|
+
result = datetime.datetime(int(year), int(month), int(day), int(hour), int(minute), int(second), int(millisecond) * 1000, tzinfo)
|
|
564
|
+
return result if tzinfo is not None else result.astimezone()
|
|
565
|
+
|
|
566
|
+
|
|
567
|
+
# $function: datetimeNow
|
|
568
|
+
# $group: Datetime
|
|
569
|
+
# $doc: Get the current datetime
|
|
570
|
+
# $return: The current datetime
|
|
571
|
+
def _datetime_now(unused_args, unused_options):
|
|
572
|
+
return datetime.datetime.now()
|
|
573
|
+
|
|
574
|
+
|
|
575
|
+
# $function: datetimeSecond
|
|
576
|
+
# $group: Datetime
|
|
577
|
+
# $doc: Get the second of a datetime
|
|
578
|
+
# $arg datetime: The datetime
|
|
579
|
+
# $return: The second
|
|
580
|
+
def _datetime_second(args, unused_options):
|
|
581
|
+
datetime_, = default_args(args, (None,))
|
|
582
|
+
if not isinstance(datetime_, datetime.datetime):
|
|
583
|
+
return None
|
|
584
|
+
|
|
585
|
+
return datetime_.second
|
|
586
|
+
|
|
587
|
+
|
|
588
|
+
# $function: datetimeToday
|
|
589
|
+
# $group: Datetime
|
|
590
|
+
# $doc: Get today's datetime
|
|
591
|
+
# $return: Today's datetime
|
|
592
|
+
def _datetime_today(unused_args, unused_options):
|
|
593
|
+
today = datetime.date.today()
|
|
594
|
+
return datetime.datetime(today.year, today.month, today.day)
|
|
595
|
+
|
|
596
|
+
|
|
597
|
+
# $function: datetimeYear
|
|
598
|
+
# $group: Datetime
|
|
599
|
+
# $doc: Get the full year of a datetime
|
|
600
|
+
# $arg datetime: The datetime
|
|
601
|
+
# $return: The full year
|
|
602
|
+
def _datetime_year(args, unused_options):
|
|
603
|
+
datetime_, = default_args(args, (None,))
|
|
604
|
+
if not isinstance(datetime_, datetime.datetime):
|
|
605
|
+
return None
|
|
606
|
+
|
|
607
|
+
return datetime_.year
|
|
608
|
+
|
|
609
|
+
|
|
610
|
+
#
|
|
611
|
+
# JSON functions
|
|
612
|
+
#
|
|
613
|
+
|
|
614
|
+
|
|
615
|
+
# $function: jsonParse
|
|
616
|
+
# $group: JSON
|
|
617
|
+
# $doc: Convert a JSON string to an object
|
|
618
|
+
# $arg string: The JSON string
|
|
619
|
+
# $return: The object
|
|
620
|
+
def _json_parse(args, unused_options):
|
|
621
|
+
string, = default_args(args, (None,))
|
|
622
|
+
if not isinstance(string, str):
|
|
623
|
+
return None
|
|
624
|
+
|
|
625
|
+
return json.loads(string)
|
|
626
|
+
|
|
627
|
+
|
|
628
|
+
# $function: jsonStringify
|
|
629
|
+
# $group: JSON
|
|
630
|
+
# $doc: Convert an object to a JSON string
|
|
631
|
+
# $arg value: The object
|
|
632
|
+
# $arg indent: Optional (default is null). The indentation number.
|
|
633
|
+
# $return: The JSON string
|
|
634
|
+
def _json_stringify(args, unused_options):
|
|
635
|
+
value, indent = default_args(args, (None, None))
|
|
636
|
+
if indent is not None and (not isinstance(indent, (int, float)) or int(indent) != indent or indent < 1):
|
|
637
|
+
return None
|
|
638
|
+
|
|
639
|
+
return value_json(value, int(indent) if indent is not None else None)
|
|
640
|
+
|
|
641
|
+
|
|
642
|
+
#
|
|
643
|
+
# Math functions
|
|
644
|
+
#
|
|
645
|
+
|
|
646
|
+
|
|
647
|
+
# $function: mathAbs
|
|
648
|
+
# $group: Math
|
|
649
|
+
# $doc: Compute the absolute value of a number
|
|
650
|
+
# $arg x: The number
|
|
651
|
+
# $return: The absolute value of the number
|
|
652
|
+
def _math_abs(args, unused_options):
|
|
653
|
+
x, = default_args(args, (None,))
|
|
654
|
+
if not isinstance(x, (int, float)):
|
|
655
|
+
return None
|
|
656
|
+
|
|
657
|
+
return abs(x)
|
|
658
|
+
|
|
659
|
+
|
|
660
|
+
# $function: mathAcos
|
|
661
|
+
# $group: Math
|
|
662
|
+
# $doc: Compute the arccosine, in radians, of a number
|
|
663
|
+
# $arg x: The number
|
|
664
|
+
# $return: The arccosine, in radians, of the number
|
|
665
|
+
def _math_acos(args, unused_options):
|
|
666
|
+
x, = default_args(args, (None,))
|
|
667
|
+
if not isinstance(x, (int, float)):
|
|
668
|
+
return None
|
|
669
|
+
|
|
670
|
+
return math.acos(x)
|
|
671
|
+
|
|
672
|
+
|
|
673
|
+
# $function: mathAsin
|
|
674
|
+
# $group: Math
|
|
675
|
+
# $doc: Compute the arcsine, in radians, of a number
|
|
676
|
+
# $arg x: The number
|
|
677
|
+
# $return: The arcsine, in radians, of the number
|
|
678
|
+
def _math_asin(args, unused_options):
|
|
679
|
+
x, = default_args(args, (None,))
|
|
680
|
+
if not isinstance(x, (int, float)):
|
|
681
|
+
return None
|
|
682
|
+
|
|
683
|
+
return math.asin(x)
|
|
684
|
+
|
|
685
|
+
|
|
686
|
+
# $function: mathAtan
|
|
687
|
+
# $group: Math
|
|
688
|
+
# $doc: Compute the arctangent, in radians, of a number
|
|
689
|
+
# $arg x: The number
|
|
690
|
+
# $return: The arctangent, in radians, of the number
|
|
691
|
+
def _math_atan(args, unused_options):
|
|
692
|
+
x, = default_args(args, (None,))
|
|
693
|
+
if not isinstance(x, (int, float)):
|
|
694
|
+
return None
|
|
695
|
+
|
|
696
|
+
return math.atan(x)
|
|
697
|
+
|
|
698
|
+
|
|
699
|
+
# $function: mathAtan2
|
|
700
|
+
# $group: Math
|
|
701
|
+
# $doc: Compute the angle, in radians, between (0, 0) and a point
|
|
702
|
+
# $arg y: The Y-coordinate of the point
|
|
703
|
+
# $arg x: The X-coordinate of the point
|
|
704
|
+
# $return: The angle, in radians
|
|
705
|
+
def _math_atan2(args, unused_options):
|
|
706
|
+
y, x = default_args(args, (None, None))
|
|
707
|
+
if not isinstance(y, (int, float)) or not isinstance(x, (int, float)):
|
|
708
|
+
return None
|
|
709
|
+
|
|
710
|
+
return math.atan2(y, x)
|
|
711
|
+
|
|
712
|
+
|
|
713
|
+
# $function: mathCeil
|
|
714
|
+
# $group: Math
|
|
715
|
+
# $doc: Compute the ceiling of a number (round up to the next highest integer)
|
|
716
|
+
# $arg x: The number
|
|
717
|
+
# $return: The ceiling of the number
|
|
718
|
+
def _math_ceil(args, unused_options):
|
|
719
|
+
x, = default_args(args, (None,))
|
|
720
|
+
if not isinstance(x, (int, float)):
|
|
721
|
+
return None
|
|
722
|
+
|
|
723
|
+
return math.ceil(x)
|
|
724
|
+
|
|
725
|
+
|
|
726
|
+
# $function: mathCos
|
|
727
|
+
# $group: Math
|
|
728
|
+
# $doc: Compute the cosine of an angle, in radians
|
|
729
|
+
# $arg x: The angle, in radians
|
|
730
|
+
# $return: The cosine of the angle
|
|
731
|
+
def _math_cos(args, unused_options):
|
|
732
|
+
x, = default_args(args, (None,))
|
|
733
|
+
if not isinstance(x, (int, float)):
|
|
734
|
+
return None
|
|
735
|
+
|
|
736
|
+
return math.cos(x)
|
|
737
|
+
|
|
738
|
+
|
|
739
|
+
# $function: mathFloor
|
|
740
|
+
# $group: Math
|
|
741
|
+
# $doc: Compute the floor of a number (round down to the next lowest integer)
|
|
742
|
+
# $arg x: The number
|
|
743
|
+
# $return: The floor of the number
|
|
744
|
+
def _math_floor(args, unused_options):
|
|
745
|
+
x, = default_args(args, (None,))
|
|
746
|
+
if not isinstance(x, (int, float)):
|
|
747
|
+
return None
|
|
748
|
+
|
|
749
|
+
return math.floor(x)
|
|
750
|
+
|
|
751
|
+
|
|
752
|
+
# $function: mathLn
|
|
753
|
+
# $group: Math
|
|
754
|
+
# $doc: Compute the natural logarithm (base e) of a number
|
|
755
|
+
# $arg x: The number
|
|
756
|
+
# $return: The natural logarithm of the number
|
|
757
|
+
def _math_ln(args, unused_options):
|
|
758
|
+
x, = default_args(args, (None,))
|
|
759
|
+
if not isinstance(x, (int, float)) or x <= 0:
|
|
760
|
+
return None
|
|
761
|
+
|
|
762
|
+
return math.log(x)
|
|
763
|
+
|
|
764
|
+
|
|
765
|
+
# $function: mathLog
|
|
766
|
+
# $group: Math
|
|
767
|
+
# $doc: Compute the logarithm (base 10) of a number
|
|
768
|
+
# $arg x: The number
|
|
769
|
+
# $arg base: Optional (default is 10). The logarithm base.
|
|
770
|
+
# $return: The logarithm of the number
|
|
771
|
+
def _math_log(args, unused_options):
|
|
772
|
+
x, base = default_args(args, (None, 10))
|
|
773
|
+
if not isinstance(x, (int, float)) or x <= 0 or not isinstance(base, (int, float)) or base <= 0 or base == 1:
|
|
774
|
+
return None
|
|
775
|
+
|
|
776
|
+
return math.log(x, base)
|
|
777
|
+
|
|
778
|
+
|
|
779
|
+
# $function: mathMax
|
|
780
|
+
# $group: Math
|
|
781
|
+
# $doc: Compute the maximum value
|
|
782
|
+
# $arg values...: The values
|
|
783
|
+
# $return: The maximum value
|
|
784
|
+
def _math_max(args, unused_options):
|
|
785
|
+
for x in args:
|
|
786
|
+
if not isinstance(x, (int, float)):
|
|
787
|
+
return None
|
|
788
|
+
|
|
789
|
+
return max(*args)
|
|
790
|
+
|
|
791
|
+
|
|
792
|
+
# $function: mathMin
|
|
793
|
+
# $group: Math
|
|
794
|
+
# $doc: Compute the minimum value
|
|
795
|
+
# $arg values...: The values
|
|
796
|
+
# $return: The minimum value
|
|
797
|
+
def _math_min(args, unused_options):
|
|
798
|
+
for x in args:
|
|
799
|
+
if not isinstance(x, (int, float)):
|
|
800
|
+
return None
|
|
801
|
+
|
|
802
|
+
return min(*args)
|
|
803
|
+
|
|
804
|
+
|
|
805
|
+
# $function: mathPi
|
|
806
|
+
# $group: Math
|
|
807
|
+
# $doc: Return the number pi
|
|
808
|
+
# $return: The number pi
|
|
809
|
+
def _math_pi(unused_args, unused_options):
|
|
810
|
+
return math.pi
|
|
811
|
+
|
|
812
|
+
|
|
813
|
+
# $function: mathRandom
|
|
814
|
+
# $group: Math
|
|
815
|
+
# $doc: Compute a random number between 0 and 1, inclusive
|
|
816
|
+
# $return: A random number
|
|
817
|
+
def _math_random(unused_args, unused_options):
|
|
818
|
+
return random.random()
|
|
819
|
+
|
|
820
|
+
|
|
821
|
+
# $function: mathRound
|
|
822
|
+
# $group: Math
|
|
823
|
+
# $doc: Round a number to a certain number of decimal places
|
|
824
|
+
# $arg x: The number
|
|
825
|
+
# $arg digits: Optional (default is 0). The number of decimal digits to round to.
|
|
826
|
+
# $return: The rounded number
|
|
827
|
+
def _math_round(args, unused_options):
|
|
828
|
+
x, digits = default_args(args, (None, 0))
|
|
829
|
+
if not isinstance(x, (int, float)) or not isinstance(digits, (int, float)) or int(digits) != digits or digits < 0:
|
|
830
|
+
return None
|
|
831
|
+
|
|
832
|
+
return round_number(x, digits)
|
|
833
|
+
|
|
834
|
+
|
|
835
|
+
# $function: mathSign
|
|
836
|
+
# $group: Math
|
|
837
|
+
# $doc: Compute the sign of a number
|
|
838
|
+
# $arg x: The number
|
|
839
|
+
# $return: -1 for a negative number, 1 for a positive number, and 0 for zero
|
|
840
|
+
def _math_sign(args, unused_options):
|
|
841
|
+
x, = default_args(args, (None,))
|
|
842
|
+
if not isinstance(x, (int, float)):
|
|
843
|
+
return None
|
|
844
|
+
|
|
845
|
+
return -1 if x < 0 else (0 if x == 0 else 1)
|
|
846
|
+
|
|
847
|
+
|
|
848
|
+
# $function: mathSin
|
|
849
|
+
# $group: Math
|
|
850
|
+
# $doc: Compute the sine of an angle, in radians
|
|
851
|
+
# $arg x: The angle, in radians
|
|
852
|
+
# $return: The sine of the angle
|
|
853
|
+
def _math_sin(args, unused_options):
|
|
854
|
+
x, = default_args(args, (None,))
|
|
855
|
+
if not isinstance(x, (int, float)):
|
|
856
|
+
return None
|
|
857
|
+
|
|
858
|
+
return math.sin(x)
|
|
859
|
+
|
|
860
|
+
|
|
861
|
+
# $function: mathSqrt
|
|
862
|
+
# $group: Math
|
|
863
|
+
# $doc: Compute the square root of a number
|
|
864
|
+
# $arg x: The number
|
|
865
|
+
# $return: The square root of the number
|
|
866
|
+
def _math_sqrt(args, unused_options):
|
|
867
|
+
x, = default_args(args, (None,))
|
|
868
|
+
if not isinstance(x, (int, float)) or x < 0:
|
|
869
|
+
return None
|
|
870
|
+
|
|
871
|
+
return math.sqrt(x)
|
|
872
|
+
|
|
873
|
+
|
|
874
|
+
# $function: mathTan
|
|
875
|
+
# $group: Math
|
|
876
|
+
# $doc: Compute the tangent of an angle, in radians
|
|
877
|
+
# $arg x: The angle, in radians
|
|
878
|
+
# $return: The tangent of the angle
|
|
879
|
+
def _math_tan(args, unused_options):
|
|
880
|
+
x, = default_args(args, (None,))
|
|
881
|
+
if not isinstance(x, (int, float)):
|
|
882
|
+
return None
|
|
883
|
+
|
|
884
|
+
return math.tan(x)
|
|
885
|
+
|
|
886
|
+
|
|
887
|
+
#
|
|
888
|
+
# Number functions
|
|
889
|
+
#
|
|
890
|
+
|
|
891
|
+
|
|
892
|
+
# $function: numberParseFloat
|
|
893
|
+
# $group: Number
|
|
894
|
+
# $doc: Parse a string as a floating point number
|
|
895
|
+
# $arg string: The string
|
|
896
|
+
# $return: The number
|
|
897
|
+
def _number_parse_float(args, unused_options):
|
|
898
|
+
string, = default_args(args, (None,))
|
|
899
|
+
if not isinstance(string, str):
|
|
900
|
+
return None
|
|
901
|
+
|
|
902
|
+
try:
|
|
903
|
+
return float(string)
|
|
904
|
+
except ValueError:
|
|
905
|
+
return None
|
|
906
|
+
|
|
907
|
+
|
|
908
|
+
# $function: numberParseInt
|
|
909
|
+
# $group: Number
|
|
910
|
+
# $doc: Parse a string as an integer
|
|
911
|
+
# $arg string: The string
|
|
912
|
+
# $arg radix: Optional (default is 10). The number base.
|
|
913
|
+
# $return: The integer
|
|
914
|
+
def _number_parse_int(args, unused_options):
|
|
915
|
+
string, radix = default_args(args, (None, 10))
|
|
916
|
+
if not isinstance(string, str) or not isinstance(radix, (int, float)) or int(radix) != radix or radix < 2 or radix > 36:
|
|
917
|
+
return None
|
|
918
|
+
|
|
919
|
+
try:
|
|
920
|
+
return int(string, int(radix))
|
|
921
|
+
except ValueError:
|
|
922
|
+
return None
|
|
923
|
+
|
|
924
|
+
|
|
925
|
+
# $function: numberToFixed
|
|
926
|
+
# $group: Number
|
|
927
|
+
# $doc: Format a number using fixed-point notation
|
|
928
|
+
# $arg x: The number
|
|
929
|
+
# $arg digits: Optional (default is 2). The number of digits to appear after the decimal point.
|
|
930
|
+
# $arg trim: Optional (default is false). If true, trim trailing zeroes and decimal point.
|
|
931
|
+
# $return: The fixed-point notation string
|
|
932
|
+
def _number_to_fixed(args, unused_options):
|
|
933
|
+
x, digits, trim = default_args(args, (None, 2, False))
|
|
934
|
+
if not isinstance(x, (int, float)) or not isinstance(digits, (int, float)) or int(digits) != digits or digits < 0:
|
|
935
|
+
return None
|
|
936
|
+
|
|
937
|
+
result = f'{round_number(x, digits):.{int(digits)}f}'
|
|
938
|
+
if value_boolean(trim):
|
|
939
|
+
return R_NUMBER_CLEANUP.sub('', result)
|
|
940
|
+
return result
|
|
941
|
+
|
|
942
|
+
|
|
943
|
+
#
|
|
944
|
+
# Object functions
|
|
945
|
+
#
|
|
946
|
+
|
|
947
|
+
|
|
948
|
+
# $function: objectAssign
|
|
949
|
+
# $group: Object
|
|
950
|
+
# $doc: Assign the keys/values of one object to another
|
|
951
|
+
# $arg object: The object to assign to
|
|
952
|
+
# $arg object2: The object to assign
|
|
953
|
+
# $return: The updated object
|
|
954
|
+
def _object_assign(args, unused_options):
|
|
955
|
+
object_, object2 = default_args(args, (None, None))
|
|
956
|
+
if not isinstance(object_, dict) or not isinstance(object2, dict):
|
|
957
|
+
return None
|
|
958
|
+
|
|
959
|
+
object_.update(object2)
|
|
960
|
+
return object_
|
|
961
|
+
|
|
962
|
+
|
|
963
|
+
# $function: objectCopy
|
|
964
|
+
# $group: Object
|
|
965
|
+
# $doc: Create a copy of an object
|
|
966
|
+
# $arg object: The object to copy
|
|
967
|
+
# $return: The object copy
|
|
968
|
+
def _object_copy(args, unused_options):
|
|
969
|
+
object_, = default_args(args, (None,))
|
|
970
|
+
if not isinstance(object_, dict):
|
|
971
|
+
return None
|
|
972
|
+
|
|
973
|
+
return dict(object_)
|
|
974
|
+
|
|
975
|
+
|
|
976
|
+
# $function: objectDelete
|
|
977
|
+
# $group: Object
|
|
978
|
+
# $doc: Delete an object key
|
|
979
|
+
# $arg object: The object
|
|
980
|
+
# $arg key: The key to delete
|
|
981
|
+
def _object_delete(args, unused_options):
|
|
982
|
+
object_, key = default_args(args, (None, None))
|
|
983
|
+
if not isinstance(object_, dict) or not isinstance(key, str):
|
|
984
|
+
return None
|
|
985
|
+
|
|
986
|
+
if key in object_:
|
|
987
|
+
del object_[key]
|
|
988
|
+
return None
|
|
989
|
+
|
|
990
|
+
|
|
991
|
+
# $function: objectGet
|
|
992
|
+
# $group: Object
|
|
993
|
+
# $doc: Get an object key's value
|
|
994
|
+
# $arg object: The object
|
|
995
|
+
# $arg key: The key
|
|
996
|
+
# $arg defaultValue: The default value (optional)
|
|
997
|
+
# $return: The value or null if the key does not exist
|
|
998
|
+
def _object_get(args, unused_options):
|
|
999
|
+
object_, key, default_value = default_args(args, (None, None, None))
|
|
1000
|
+
if not isinstance(object_, dict) or not isinstance(key, str):
|
|
1001
|
+
return default_value
|
|
1002
|
+
|
|
1003
|
+
return object_.get(key, default_value)
|
|
1004
|
+
|
|
1005
|
+
|
|
1006
|
+
# $function: objectHas
|
|
1007
|
+
# $group: Object
|
|
1008
|
+
# $doc: Test if an object contains a key
|
|
1009
|
+
# $arg object: The object
|
|
1010
|
+
# $arg key: The key
|
|
1011
|
+
# $return: true if the object contains the key, false otherwise
|
|
1012
|
+
def _object_has(args, unused_options):
|
|
1013
|
+
object_, key = default_args(args, (None, None))
|
|
1014
|
+
if not isinstance(object_, dict) or not isinstance(key, str):
|
|
1015
|
+
return False
|
|
1016
|
+
|
|
1017
|
+
return key in object_
|
|
1018
|
+
|
|
1019
|
+
|
|
1020
|
+
# $function: objectKeys
|
|
1021
|
+
# $group: Object
|
|
1022
|
+
# $doc: Get an object's keys
|
|
1023
|
+
# $arg object: The object
|
|
1024
|
+
# $return: The array of keys
|
|
1025
|
+
def _object_keys(args, unused_options):
|
|
1026
|
+
object_, = default_args(args, (None,))
|
|
1027
|
+
if not isinstance(object_, dict):
|
|
1028
|
+
return None
|
|
1029
|
+
|
|
1030
|
+
return list(object_.keys())
|
|
1031
|
+
|
|
1032
|
+
|
|
1033
|
+
# $function: objectNew
|
|
1034
|
+
# $group: Object
|
|
1035
|
+
# $doc: Create a new object
|
|
1036
|
+
# $arg keyValues...: The object's initial key and value pairs
|
|
1037
|
+
# $return: The new object
|
|
1038
|
+
def _object_new(args, unused_options):
|
|
1039
|
+
args_length = len(args)
|
|
1040
|
+
object_ = {}
|
|
1041
|
+
ix = 0
|
|
1042
|
+
while ix < args_length:
|
|
1043
|
+
object_[args[ix]] = (args[ix + 1] if ix + 1 < len(args) else None)
|
|
1044
|
+
ix += 2
|
|
1045
|
+
return object_
|
|
1046
|
+
|
|
1047
|
+
|
|
1048
|
+
# $function: objectSet
|
|
1049
|
+
# $group: Object
|
|
1050
|
+
# $doc: Set an object key's value
|
|
1051
|
+
# $arg object: The object
|
|
1052
|
+
# $arg key: The key
|
|
1053
|
+
# $arg value: The value to set
|
|
1054
|
+
# $return: The value to set
|
|
1055
|
+
def _object_set(args, unused_options):
|
|
1056
|
+
object_, key, value = default_args(args, (None, None, None))
|
|
1057
|
+
if not isinstance(object_, dict) or not isinstance(key, str):
|
|
1058
|
+
return None
|
|
1059
|
+
|
|
1060
|
+
object_[key] = value
|
|
1061
|
+
return value
|
|
1062
|
+
|
|
1063
|
+
|
|
1064
|
+
#
|
|
1065
|
+
# Regex functions
|
|
1066
|
+
#
|
|
1067
|
+
|
|
1068
|
+
|
|
1069
|
+
# $function: regexEscape
|
|
1070
|
+
# $group: Regex
|
|
1071
|
+
# $doc: Escape a string for use in a regular expression
|
|
1072
|
+
# $arg string: The string to escape
|
|
1073
|
+
# $return: The escaped string
|
|
1074
|
+
def _regex_escape(args, unused_options):
|
|
1075
|
+
string, = default_args(args, (None,))
|
|
1076
|
+
if not isinstance(string, str):
|
|
1077
|
+
return None
|
|
1078
|
+
|
|
1079
|
+
return re.escape(string)
|
|
1080
|
+
|
|
1081
|
+
|
|
1082
|
+
# $function: regexMatch
|
|
1083
|
+
# $group: Regex
|
|
1084
|
+
# $doc: Find the first match of a regular expression in a string
|
|
1085
|
+
# $arg regex: The regular expression
|
|
1086
|
+
# $arg string: The string
|
|
1087
|
+
# $return: The [match object](model.html#var.vName='RegexMatch'), or null if no matches are found
|
|
1088
|
+
def _regex_match(args, unused_options):
|
|
1089
|
+
regex, string = default_args(args, (None, None))
|
|
1090
|
+
if not isinstance(regex, REGEX_TYPE) or not isinstance(string, str):
|
|
1091
|
+
return None
|
|
1092
|
+
|
|
1093
|
+
# Match?
|
|
1094
|
+
match = regex.search(string)
|
|
1095
|
+
if match is None:
|
|
1096
|
+
return None
|
|
1097
|
+
|
|
1098
|
+
return {
|
|
1099
|
+
'index': match.start(),
|
|
1100
|
+
'input': match.string,
|
|
1101
|
+
'match': match.group(0),
|
|
1102
|
+
'groups': match.groupdict(),
|
|
1103
|
+
'groupArray': list(match.groups())
|
|
1104
|
+
}
|
|
1105
|
+
|
|
1106
|
+
|
|
1107
|
+
# The regex match model
|
|
1108
|
+
REGEX_MATCH_TYPES = parse_schema_markdown('''\
|
|
1109
|
+
group "RegexMatch"
|
|
1110
|
+
|
|
1111
|
+
|
|
1112
|
+
# A regex match model
|
|
1113
|
+
struct RegexMatch
|
|
1114
|
+
|
|
1115
|
+
# The zero-based index of the match in the input string
|
|
1116
|
+
int(>= 0) index
|
|
1117
|
+
|
|
1118
|
+
# The input string
|
|
1119
|
+
string input
|
|
1120
|
+
|
|
1121
|
+
# The match string
|
|
1122
|
+
string match
|
|
1123
|
+
|
|
1124
|
+
# The named groups
|
|
1125
|
+
string{} groups
|
|
1126
|
+
|
|
1127
|
+
# The ordered groups
|
|
1128
|
+
string[] groupArray
|
|
1129
|
+
''')
|
|
1130
|
+
|
|
1131
|
+
|
|
1132
|
+
# $function: regexMatchAll
|
|
1133
|
+
# $group: Regex
|
|
1134
|
+
# $doc: Find all matches of regular expression in a string
|
|
1135
|
+
# $arg regex: The regular expression
|
|
1136
|
+
# $arg string: The string
|
|
1137
|
+
# $return: The array of [match objects](model.html#var.vName='RegexMatch')
|
|
1138
|
+
def _regex_match_all(args, unused_options):
|
|
1139
|
+
regex, string = default_args(args, (None, None))
|
|
1140
|
+
if not isinstance(regex, REGEX_TYPE) or not isinstance(string, str):
|
|
1141
|
+
return None
|
|
1142
|
+
|
|
1143
|
+
return [
|
|
1144
|
+
{
|
|
1145
|
+
'index': match.start(),
|
|
1146
|
+
'input': match.string,
|
|
1147
|
+
'match': match.group(0),
|
|
1148
|
+
'groups': match.groupdict(),
|
|
1149
|
+
'groupArray': list(match.groups())
|
|
1150
|
+
}
|
|
1151
|
+
for match in regex.finditer(string)
|
|
1152
|
+
]
|
|
1153
|
+
|
|
1154
|
+
# $function: regexNew
|
|
1155
|
+
# $group: Regex
|
|
1156
|
+
# $doc: Create a regular expression
|
|
1157
|
+
# $arg pattern: The regular expression pattern string
|
|
1158
|
+
# $arg flags: The [regular expression flags ("i", "m", "s", "u")
|
|
1159
|
+
# $return: The regular expression or null if the pattern is invalid
|
|
1160
|
+
def _regex_new(args, unused_options):
|
|
1161
|
+
pattern, flags = default_args(args, (None, None))
|
|
1162
|
+
if not isinstance(pattern, str) or (flags is not None and not isinstance(flags, str)):
|
|
1163
|
+
return None
|
|
1164
|
+
|
|
1165
|
+
# Translate JavaScript named group syntax to Python
|
|
1166
|
+
pattern = R_REGEX_NEW_NAMED.sub(r'(?P<\1>', pattern)
|
|
1167
|
+
|
|
1168
|
+
# Compute the flags mask
|
|
1169
|
+
flags_mask = 0
|
|
1170
|
+
if flags is not None:
|
|
1171
|
+
for flag in flags:
|
|
1172
|
+
if flag == 'i':
|
|
1173
|
+
flags_mask = flags_mask | re.I
|
|
1174
|
+
elif flag == 'm':
|
|
1175
|
+
flags_mask = flags_mask | re.M
|
|
1176
|
+
elif flag == 's':
|
|
1177
|
+
flags_mask = flags_mask | re.S
|
|
1178
|
+
else:
|
|
1179
|
+
return None
|
|
1180
|
+
|
|
1181
|
+
return re.compile(pattern, flags_mask)
|
|
1182
|
+
|
|
1183
|
+
|
|
1184
|
+
R_REGEX_NEW_NAMED = re.compile(r'\(\?<(\w+)>')
|
|
1185
|
+
|
|
1186
|
+
|
|
1187
|
+
# $function: regexReplace
|
|
1188
|
+
# $group: Regex
|
|
1189
|
+
# $doc: Replace regular expression matches with a string
|
|
1190
|
+
# $arg regex: The replacement regular expression
|
|
1191
|
+
# $arg string: The string
|
|
1192
|
+
# $arg substr: The replacement string
|
|
1193
|
+
# $return: The updated string
|
|
1194
|
+
def _regex_replace(args, unused_options):
|
|
1195
|
+
regex, string, substr = default_args(args, (None, None, None))
|
|
1196
|
+
if not isinstance(regex, REGEX_TYPE) or not isinstance(string, str) or not isinstance(substr, str):
|
|
1197
|
+
return None
|
|
1198
|
+
|
|
1199
|
+
# Escape Python escapes
|
|
1200
|
+
substr = substr.replace('\\', '\\\\')
|
|
1201
|
+
|
|
1202
|
+
# Un-escape Javascript escapes
|
|
1203
|
+
substr = substr.replace('$$', '$')
|
|
1204
|
+
|
|
1205
|
+
# Translate JavaScript replacers to Python replacers
|
|
1206
|
+
substr = R_REGEX_REPLACE_INDEX.sub(r'\\\1', substr)
|
|
1207
|
+
substr = R_REGEX_REPLACE_NAMED.sub(r'\\g<\1>', substr)
|
|
1208
|
+
|
|
1209
|
+
return regex.sub(substr, string)
|
|
1210
|
+
|
|
1211
|
+
|
|
1212
|
+
R_REGEX_REPLACE_INDEX = re.compile(r'\$(\d+)')
|
|
1213
|
+
R_REGEX_REPLACE_NAMED = re.compile(r'\$<(?P<name>[^>]+)>')
|
|
1214
|
+
|
|
1215
|
+
|
|
1216
|
+
# $function: regexSplit
|
|
1217
|
+
# $group: Regex
|
|
1218
|
+
# $doc: Split a string with a regular expression
|
|
1219
|
+
# $arg regex: The regular expression
|
|
1220
|
+
# $arg string: The string
|
|
1221
|
+
# $return: The array of split parts
|
|
1222
|
+
def _regex_split(args, unused_options):
|
|
1223
|
+
regex, string = default_args(args, (None, None))
|
|
1224
|
+
if not isinstance(regex, REGEX_TYPE) or not isinstance(string, str):
|
|
1225
|
+
return None
|
|
1226
|
+
|
|
1227
|
+
return regex.split(string)
|
|
1228
|
+
|
|
1229
|
+
|
|
1230
|
+
#
|
|
1231
|
+
# Schema functions
|
|
1232
|
+
#
|
|
1233
|
+
|
|
1234
|
+
|
|
1235
|
+
# $function: schemaParse
|
|
1236
|
+
# $group: Schema
|
|
1237
|
+
# $doc: Parse the [Schema Markdown](https://craigahobbs.github.io/schema-markdown-js/language/) text
|
|
1238
|
+
# $arg lines...: The [Schema Markdown](https://craigahobbs.github.io/schema-markdown-js/language/)
|
|
1239
|
+
# $arg lines...: text lines (may contain nested arrays of un-split lines)
|
|
1240
|
+
# $return: The schema's [type model](https://craigahobbs.github.io/schema-markdown-doc/doc/#var.vName='Types')
|
|
1241
|
+
def _schema_parse(args, unused_options):
|
|
1242
|
+
return parse_schema_markdown(args)
|
|
1243
|
+
|
|
1244
|
+
|
|
1245
|
+
# $function: schemaParseEx
|
|
1246
|
+
# $group: Schema
|
|
1247
|
+
# $doc: Parse the [Schema Markdown](https://craigahobbs.github.io/schema-markdown-js/language/) text with options
|
|
1248
|
+
# $arg lines: The array of [Schema Markdown](https://craigahobbs.github.io/schema-markdown-js/language/)
|
|
1249
|
+
# $arg lines: text lines (may contain nested arrays of un-split lines)
|
|
1250
|
+
# $arg types: Optional. The [type model](https://craigahobbs.github.io/schema-markdown-doc/doc/#var.vName='Types').
|
|
1251
|
+
# $arg filename: Optional (default is ""). The file name.
|
|
1252
|
+
# $return: The schema's [type model](https://craigahobbs.github.io/schema-markdown-doc/doc/#var.vName='Types')
|
|
1253
|
+
def _schema_parse_ex(args, unused_options):
|
|
1254
|
+
lines, types, filename = default_args(args, (None, {}, ''))
|
|
1255
|
+
if not isinstance(lines, (list, str)) or not isinstance(types, dict) or not isinstance(filename, str):
|
|
1256
|
+
return None
|
|
1257
|
+
|
|
1258
|
+
return parse_schema_markdown(lines, types, filename)
|
|
1259
|
+
|
|
1260
|
+
|
|
1261
|
+
# $function: schemaTypeModel
|
|
1262
|
+
# $group: Schema
|
|
1263
|
+
# $doc: Get the [Schema Markdown Type Model](https://craigahobbs.github.io/schema-markdown-doc/doc/#var.vName='Types')
|
|
1264
|
+
# $return: The [Schema Markdown Type Model](https://craigahobbs.github.io/schema-markdown-doc/doc/#var.vName='Types')
|
|
1265
|
+
def _schema_type_model(unused_args, unused_options):
|
|
1266
|
+
return TYPE_MODEL
|
|
1267
|
+
|
|
1268
|
+
|
|
1269
|
+
# $function: schemaValidate
|
|
1270
|
+
# $group: Schema
|
|
1271
|
+
# $doc: Validate an object to a schema type
|
|
1272
|
+
# $arg types: The [type model](https://craigahobbs.github.io/schema-markdown-doc/doc/#var.vName='Types')
|
|
1273
|
+
# $arg typeName: The type name
|
|
1274
|
+
# $arg value: The object to validate
|
|
1275
|
+
# $return: The validated object or null if validation fails
|
|
1276
|
+
def _schema_validate(args, unused_options):
|
|
1277
|
+
types, type_name, value = default_args(args, (None, None, None))
|
|
1278
|
+
if not isinstance(types, dict) or not isinstance(type_name, str):
|
|
1279
|
+
return None
|
|
1280
|
+
|
|
1281
|
+
validate_type_model(types)
|
|
1282
|
+
return validate_type(types, type_name, value)
|
|
1283
|
+
|
|
1284
|
+
|
|
1285
|
+
# $function: schemaValidateTypeModel
|
|
1286
|
+
# $group: Schema
|
|
1287
|
+
# $doc: Validate a [Schema Markdown Type Model](https://craigahobbs.github.io/schema-markdown-doc/doc/#var.vName='Types')
|
|
1288
|
+
# $arg types: The [type model](https://craigahobbs.github.io/schema-markdown-doc/doc/#var.vName='Types') to validate
|
|
1289
|
+
# $return: The validated [type model](https://craigahobbs.github.io/schema-markdown-doc/doc/#var.vName='Types')
|
|
1290
|
+
def _schema_validate_type_model(args, unused_options):
|
|
1291
|
+
types, = default_args(args, (None,))
|
|
1292
|
+
if not isinstance(types, dict):
|
|
1293
|
+
return None
|
|
1294
|
+
|
|
1295
|
+
return validate_type_model(types)
|
|
1296
|
+
|
|
1297
|
+
|
|
1298
|
+
#
|
|
1299
|
+
# String functions
|
|
1300
|
+
#
|
|
1301
|
+
|
|
1302
|
+
|
|
1303
|
+
# $function: stringCharCodeAt
|
|
1304
|
+
# $group: String
|
|
1305
|
+
# $doc: Get a string index's character code
|
|
1306
|
+
# $arg string: The string
|
|
1307
|
+
# $arg index: The character index
|
|
1308
|
+
# $return: The character code
|
|
1309
|
+
def _string_char_code_at(args, unused_options):
|
|
1310
|
+
string, index = default_args(args, (None, None))
|
|
1311
|
+
if not isinstance(string, str) or not isinstance(index, (int, float)) or int(index) != index or index < 0 or index >= len(string):
|
|
1312
|
+
return None
|
|
1313
|
+
|
|
1314
|
+
return ord(string[int(index)])
|
|
1315
|
+
|
|
1316
|
+
|
|
1317
|
+
# $function: stringEndsWith
|
|
1318
|
+
# $group: String
|
|
1319
|
+
# $doc: Determine if a string ends with a search string
|
|
1320
|
+
# $arg string: The string
|
|
1321
|
+
# $arg search: The search string
|
|
1322
|
+
# $return: true if the string ends with the search string, false otherwise
|
|
1323
|
+
def _string_ends_with(args, unused_options):
|
|
1324
|
+
string, search = default_args(args, (None, None))
|
|
1325
|
+
if not isinstance(string, str) or not isinstance(search, str):
|
|
1326
|
+
return None
|
|
1327
|
+
|
|
1328
|
+
return string.endswith(search)
|
|
1329
|
+
|
|
1330
|
+
|
|
1331
|
+
# $function: stringFromCharCode
|
|
1332
|
+
# $group: String
|
|
1333
|
+
# $doc: Create a string of characters from character codes
|
|
1334
|
+
# $arg charCodes...: The character codes
|
|
1335
|
+
# $return: The string of characters
|
|
1336
|
+
def _string_from_char_code(args, unused_options):
|
|
1337
|
+
if any((not isinstance(code, (int, float)) or int(code) != code or code < 0) for code in args):
|
|
1338
|
+
return None
|
|
1339
|
+
|
|
1340
|
+
return ''.join(chr(int(code)) for code in args)
|
|
1341
|
+
|
|
1342
|
+
|
|
1343
|
+
# $function: stringIndexOf
|
|
1344
|
+
# $group: String
|
|
1345
|
+
# $doc: Find the first index of a search string in a string
|
|
1346
|
+
# $arg string: The string
|
|
1347
|
+
# $arg search: The search string
|
|
1348
|
+
# $arg index: Optional (default is 0). The index at which to start the search.
|
|
1349
|
+
# $return: The first index of the search string; -1 if not found.
|
|
1350
|
+
def _string_index_of(args, unused_options):
|
|
1351
|
+
string, search, index = default_args(args, (None, None, 0))
|
|
1352
|
+
if not isinstance(string, str) or not isinstance(search, str) or \
|
|
1353
|
+
not isinstance(index, (int, float)) or int(index) != index or index < 0 or index >= len(string):
|
|
1354
|
+
return -1
|
|
1355
|
+
|
|
1356
|
+
return string.find(search, int(index))
|
|
1357
|
+
|
|
1358
|
+
|
|
1359
|
+
# $function: stringLastIndexOf
|
|
1360
|
+
# $group: String
|
|
1361
|
+
# $doc: Find the last index of a search string in a string
|
|
1362
|
+
# $arg string: The string
|
|
1363
|
+
# $arg search: The search string
|
|
1364
|
+
# $arg index: Optional (default is the end of the string). The index at which to start the search.
|
|
1365
|
+
# $return: The last index of the search string; -1 if not found.
|
|
1366
|
+
def _string_last_index_of(args, unused_options):
|
|
1367
|
+
string, search, index = default_args(args, (None, None, None))
|
|
1368
|
+
if index is None and isinstance(string, str):
|
|
1369
|
+
index = len(string) - 1
|
|
1370
|
+
if not isinstance(string, str) or not isinstance(search, str) or \
|
|
1371
|
+
not isinstance(index, (int, float)) or int(index) != index or index < 0 or index >= len(string):
|
|
1372
|
+
return -1
|
|
1373
|
+
|
|
1374
|
+
return string.rfind(search, 0, int(index) + len(search))
|
|
1375
|
+
|
|
1376
|
+
|
|
1377
|
+
# $function: stringLength
|
|
1378
|
+
# $group: String
|
|
1379
|
+
# $doc: Get the length of a string
|
|
1380
|
+
# $arg string: The string
|
|
1381
|
+
# $return: The string's length; zero if not a string
|
|
1382
|
+
def _string_length(args, unused_options):
|
|
1383
|
+
string, = default_args(args, (None,))
|
|
1384
|
+
if not isinstance(string, str):
|
|
1385
|
+
return 0
|
|
1386
|
+
|
|
1387
|
+
return len(string)
|
|
1388
|
+
|
|
1389
|
+
|
|
1390
|
+
# $function: stringLower
|
|
1391
|
+
# $group: String
|
|
1392
|
+
# $doc: Convert a string to lower-case
|
|
1393
|
+
# $arg string: The string
|
|
1394
|
+
# $return: The lower-case string
|
|
1395
|
+
def _string_lower(args, unused_options):
|
|
1396
|
+
string, = default_args(args, (None,))
|
|
1397
|
+
if not isinstance(string, str):
|
|
1398
|
+
return None
|
|
1399
|
+
|
|
1400
|
+
return string.lower()
|
|
1401
|
+
|
|
1402
|
+
|
|
1403
|
+
# $function: stringNew
|
|
1404
|
+
# $group: String
|
|
1405
|
+
# $doc: Create a new string from a value
|
|
1406
|
+
# $arg value: The value
|
|
1407
|
+
# $return: The new string
|
|
1408
|
+
def _string_new(args, unused_options):
|
|
1409
|
+
value, = default_args(args, (None,))
|
|
1410
|
+
return value_string(value)
|
|
1411
|
+
|
|
1412
|
+
|
|
1413
|
+
# $function: stringRepeat
|
|
1414
|
+
# $group: String
|
|
1415
|
+
# $doc: Repeat a string
|
|
1416
|
+
# $arg string: The string to repeat
|
|
1417
|
+
# $arg count: The number of times to repeat the string
|
|
1418
|
+
# $return: The repeated string
|
|
1419
|
+
def _string_repeat(args, unused_options):
|
|
1420
|
+
string, count = default_args(args, (None, None))
|
|
1421
|
+
if not isinstance(string, str) or not isinstance(count, (int, float)) or int(count) != count or count < 0:
|
|
1422
|
+
return None
|
|
1423
|
+
|
|
1424
|
+
return string * int(count)
|
|
1425
|
+
|
|
1426
|
+
|
|
1427
|
+
# $function: stringReplace
|
|
1428
|
+
# $group: String
|
|
1429
|
+
# $doc: Replace all instances of a string with another string
|
|
1430
|
+
# $arg string: The string to update
|
|
1431
|
+
# $arg substr: The string to replace
|
|
1432
|
+
# $arg newSubstr: The replacement string
|
|
1433
|
+
# $return: The updated string
|
|
1434
|
+
def _string_replace(args, unused_options):
|
|
1435
|
+
string, substr, new_substr = default_args(args, (None, None, None))
|
|
1436
|
+
if not isinstance(string, str) or not isinstance(substr, str) or not isinstance(new_substr, str):
|
|
1437
|
+
return None
|
|
1438
|
+
|
|
1439
|
+
return string.replace(substr, new_substr)
|
|
1440
|
+
|
|
1441
|
+
|
|
1442
|
+
# $function: stringSlice
|
|
1443
|
+
# $group: String
|
|
1444
|
+
# $doc: Copy a portion of a string
|
|
1445
|
+
# $arg string: The string
|
|
1446
|
+
# $arg start: The start index of the slice
|
|
1447
|
+
# $arg end: Optional (default is the end of the string). The end index of the slice.
|
|
1448
|
+
# $return: The new string slice
|
|
1449
|
+
def _string_slice(args, unused_options):
|
|
1450
|
+
string, begin, end = default_args(args, (None, None, None))
|
|
1451
|
+
if end is None and isinstance(string, str):
|
|
1452
|
+
end = len(string)
|
|
1453
|
+
if not isinstance(string, str) or \
|
|
1454
|
+
not isinstance(begin, (int, float)) or int(begin) != begin or begin < 0 or begin >= len(string) or \
|
|
1455
|
+
not isinstance(end, (int, float)) or int(end) != end or end < 0 or end > len(string):
|
|
1456
|
+
return None
|
|
1457
|
+
|
|
1458
|
+
return string[int(begin):int(end)]
|
|
1459
|
+
|
|
1460
|
+
|
|
1461
|
+
# $function: stringSplit
|
|
1462
|
+
# $group: String
|
|
1463
|
+
# $doc: Split a string
|
|
1464
|
+
# $arg string: The string to split
|
|
1465
|
+
# $arg separator: The separator string
|
|
1466
|
+
# $return: The array of split-out strings
|
|
1467
|
+
def _string_split(args, unused_options):
|
|
1468
|
+
string, separator = default_args(args, (None, None))
|
|
1469
|
+
if not isinstance(string, str) or not isinstance(separator, str):
|
|
1470
|
+
return None
|
|
1471
|
+
|
|
1472
|
+
return string.split(separator)
|
|
1473
|
+
|
|
1474
|
+
|
|
1475
|
+
# $function: stringStartsWith
|
|
1476
|
+
# $group: String
|
|
1477
|
+
# $doc: Determine if a string starts with a search string
|
|
1478
|
+
# $arg string: The string
|
|
1479
|
+
# $arg search: The search string
|
|
1480
|
+
# $return: true if the string starts with the search string, false otherwise
|
|
1481
|
+
def _string_starts_with(args, unused_options):
|
|
1482
|
+
string, search = default_args(args, (None, None))
|
|
1483
|
+
if not isinstance(string, str) or not isinstance(search, str):
|
|
1484
|
+
return None
|
|
1485
|
+
|
|
1486
|
+
return string.startswith(search)
|
|
1487
|
+
|
|
1488
|
+
|
|
1489
|
+
# $function: stringTrim
|
|
1490
|
+
# $group: String
|
|
1491
|
+
# $doc: Trim the whitespace from the beginning and end of a string
|
|
1492
|
+
# $arg string: The string
|
|
1493
|
+
# $return: The trimmed string
|
|
1494
|
+
def _string_trim(args, unused_options):
|
|
1495
|
+
string, = default_args(args, (None,))
|
|
1496
|
+
if not isinstance(string, str):
|
|
1497
|
+
return None
|
|
1498
|
+
|
|
1499
|
+
return string.strip()
|
|
1500
|
+
|
|
1501
|
+
|
|
1502
|
+
# $function: stringUpper
|
|
1503
|
+
# $group: String
|
|
1504
|
+
# $doc: Convert a string to upper-case
|
|
1505
|
+
# $arg string: The string
|
|
1506
|
+
# $return: The upper-case string
|
|
1507
|
+
def _string_upper(args, unused_options):
|
|
1508
|
+
string, = default_args(args, (None,))
|
|
1509
|
+
if not isinstance(string, str):
|
|
1510
|
+
return None
|
|
1511
|
+
|
|
1512
|
+
return string.upper()
|
|
1513
|
+
|
|
1514
|
+
|
|
1515
|
+
#
|
|
1516
|
+
# System functions
|
|
1517
|
+
#
|
|
1518
|
+
|
|
1519
|
+
|
|
1520
|
+
# $function: systemBoolean
|
|
1521
|
+
# $group: System
|
|
1522
|
+
# $doc: Interpret a value as a boolean
|
|
1523
|
+
# $arg value: The value
|
|
1524
|
+
# $return: true or false
|
|
1525
|
+
def _system_boolean(args, unused_options):
|
|
1526
|
+
value, = default_args(args, (None,))
|
|
1527
|
+
return value_boolean(value)
|
|
1528
|
+
|
|
1529
|
+
|
|
1530
|
+
# $function: systemCompare
|
|
1531
|
+
# $group: System
|
|
1532
|
+
# $doc: Compare two values
|
|
1533
|
+
# $arg left: The left value
|
|
1534
|
+
# $arg right: The right value
|
|
1535
|
+
# $return: -1 if the left value is less than the right value, 0 if equal, and 1 if greater than
|
|
1536
|
+
def _system_compare(args, unused_options):
|
|
1537
|
+
left, right = default_args(args, (None, None))
|
|
1538
|
+
return value_compare(left, right)
|
|
1539
|
+
|
|
1540
|
+
|
|
1541
|
+
# $function: systemFetch
|
|
1542
|
+
# $group: System
|
|
1543
|
+
# $doc: Retrieve a URL resource
|
|
1544
|
+
# $arg url: The resource URL, [request model](model.html#var.vName='SystemFetchRequest'), or array of URL and
|
|
1545
|
+
# $arg url: [request model](model.html#var.vName='SystemFetchRequest')
|
|
1546
|
+
# $return: The response string or array of strings; null if an error occurred
|
|
1547
|
+
def _system_fetch(args, options):
|
|
1548
|
+
url_arg, = default_args(args, (None,))
|
|
1549
|
+
|
|
1550
|
+
# Options
|
|
1551
|
+
log_fn = options.get('logFn') if options is not None else None
|
|
1552
|
+
url_fn = options.get('urlFn') if options is not None else None
|
|
1553
|
+
fetch_fn = options.get('fetchFn') if options is not None else None
|
|
1554
|
+
|
|
1555
|
+
# Validate the URL argument
|
|
1556
|
+
requests = []
|
|
1557
|
+
is_response_array = False
|
|
1558
|
+
if isinstance(url_arg, str):
|
|
1559
|
+
requests.append({'url': url_arg})
|
|
1560
|
+
elif isinstance(url_arg, dict):
|
|
1561
|
+
requests.append(validate_type(SYSTEM_FETCH_TYPES, 'SystemFetchRequest', url_arg))
|
|
1562
|
+
elif isinstance(url_arg, list):
|
|
1563
|
+
is_response_array = True
|
|
1564
|
+
for url_item in url_arg:
|
|
1565
|
+
if isinstance(url_item, str):
|
|
1566
|
+
requests.append({'url': url_item})
|
|
1567
|
+
else:
|
|
1568
|
+
requests.append(validate_type(SYSTEM_FETCH_TYPES, 'SystemFetchRequest', url_item))
|
|
1569
|
+
else:
|
|
1570
|
+
return None
|
|
1571
|
+
|
|
1572
|
+
# Get each response
|
|
1573
|
+
responses = []
|
|
1574
|
+
for request in requests:
|
|
1575
|
+
request_fetch = dict(request)
|
|
1576
|
+
|
|
1577
|
+
# Update the URL
|
|
1578
|
+
if url_fn is not None:
|
|
1579
|
+
request_fetch['url'] = url_fn(request_fetch['url'])
|
|
1580
|
+
|
|
1581
|
+
# Fetch the URL
|
|
1582
|
+
response = None
|
|
1583
|
+
if fetch_fn is not None:
|
|
1584
|
+
try:
|
|
1585
|
+
response = fetch_fn(request_fetch)
|
|
1586
|
+
except: # pylint: disable=bare-except
|
|
1587
|
+
pass
|
|
1588
|
+
responses.append(response)
|
|
1589
|
+
|
|
1590
|
+
# Log failure
|
|
1591
|
+
if response is None and log_fn is not None and options.get('debug'):
|
|
1592
|
+
log_fn(f'BareScript: Function "systemFetch" failed for resource "{request_fetch["url"]}"')
|
|
1593
|
+
|
|
1594
|
+
return responses if is_response_array else responses[0]
|
|
1595
|
+
|
|
1596
|
+
|
|
1597
|
+
# The aggregation model
|
|
1598
|
+
SYSTEM_FETCH_TYPES = parse_schema_markdown('''\
|
|
1599
|
+
group "SystemFetch"
|
|
1600
|
+
|
|
1601
|
+
|
|
1602
|
+
# A fetch request model
|
|
1603
|
+
struct SystemFetchRequest
|
|
1604
|
+
|
|
1605
|
+
# The resource URL
|
|
1606
|
+
string url
|
|
1607
|
+
|
|
1608
|
+
# The request body
|
|
1609
|
+
optional string body
|
|
1610
|
+
|
|
1611
|
+
# The request headers
|
|
1612
|
+
optional string{} headers
|
|
1613
|
+
''')
|
|
1614
|
+
|
|
1615
|
+
|
|
1616
|
+
# $function: systemGlobalGet
|
|
1617
|
+
# $group: System
|
|
1618
|
+
# $doc: Get a global variable value
|
|
1619
|
+
# $arg name: The global variable name
|
|
1620
|
+
# $arg defaultValue: The default value (optional)
|
|
1621
|
+
# $return: The global variable's value or null if it does not exist
|
|
1622
|
+
def _system_global_get(args, options):
|
|
1623
|
+
name, default_value = default_args(args, (None, None))
|
|
1624
|
+
if not isinstance(name, str):
|
|
1625
|
+
return default_value
|
|
1626
|
+
|
|
1627
|
+
globals_ = options.get('globals') if options is not None else None
|
|
1628
|
+
return globals_.get(name, default_value) if globals_ is not None else default_value
|
|
1629
|
+
|
|
1630
|
+
|
|
1631
|
+
# $function: systemGlobalSet
|
|
1632
|
+
# $group: System
|
|
1633
|
+
# $doc: Set a global variable value
|
|
1634
|
+
# $arg name: The global variable name
|
|
1635
|
+
# $arg value: The global variable's value
|
|
1636
|
+
# $return: The global variable's value
|
|
1637
|
+
def _system_global_set(args, options):
|
|
1638
|
+
name, value = default_args(args, (None, None))
|
|
1639
|
+
if not isinstance(name, str):
|
|
1640
|
+
return None
|
|
1641
|
+
|
|
1642
|
+
globals_ = options.get('globals') if options is not None else None
|
|
1643
|
+
if globals_ is not None:
|
|
1644
|
+
globals_[name] = value
|
|
1645
|
+
return value
|
|
1646
|
+
|
|
1647
|
+
|
|
1648
|
+
# $function: systemIs
|
|
1649
|
+
# $group: System
|
|
1650
|
+
# $doc: Test if one value is the same object as another
|
|
1651
|
+
# $arg value1: The first value
|
|
1652
|
+
# $arg value2: The second value
|
|
1653
|
+
# $return: true if values are the same object, false otherwise
|
|
1654
|
+
def _system_is(args, unused_options):
|
|
1655
|
+
value1, value2 = default_args(args, (None, None))
|
|
1656
|
+
return value_is(value1, value2)
|
|
1657
|
+
|
|
1658
|
+
|
|
1659
|
+
# $function: systemLog
|
|
1660
|
+
# $group: System
|
|
1661
|
+
# $doc: Log a message to the console
|
|
1662
|
+
# $arg string: The message
|
|
1663
|
+
def _system_log(args, options):
|
|
1664
|
+
string, = default_args(args, (None,))
|
|
1665
|
+
|
|
1666
|
+
log_fn = options.get('logFn') if options is not None else None
|
|
1667
|
+
if log_fn is not None:
|
|
1668
|
+
log_fn(value_string(string))
|
|
1669
|
+
|
|
1670
|
+
|
|
1671
|
+
# $function: systemLogDebug
|
|
1672
|
+
# $group: System
|
|
1673
|
+
# $doc: Log a message to the console, if in debug mode
|
|
1674
|
+
# $arg string: The message
|
|
1675
|
+
def _system_log_debug(args, options):
|
|
1676
|
+
string, = default_args(args, (None,))
|
|
1677
|
+
if not isinstance(string, str):
|
|
1678
|
+
return None
|
|
1679
|
+
|
|
1680
|
+
log_fn = options.get('logFn') if options is not None else None
|
|
1681
|
+
if log_fn is not None and options.get('debug'):
|
|
1682
|
+
log_fn(string)
|
|
1683
|
+
return None
|
|
1684
|
+
|
|
1685
|
+
|
|
1686
|
+
# $function: systemPartial
|
|
1687
|
+
# $group: System
|
|
1688
|
+
# $doc: Return a new function which behaves like "func" called with "args".
|
|
1689
|
+
# $doc: If additional arguments are passed to the returned function, they are appended to "args".
|
|
1690
|
+
# $arg func: The function
|
|
1691
|
+
# $arg args...: The function arguments
|
|
1692
|
+
# $return: The new function called with "args"
|
|
1693
|
+
def _system_partial(args, unused_options):
|
|
1694
|
+
fn, fn_args = default_args(args, (None,), True)
|
|
1695
|
+
if not callable(fn) or len(fn_args) < 1:
|
|
1696
|
+
return None
|
|
1697
|
+
|
|
1698
|
+
return lambda args_extra, options: fn([*fn_args, *args_extra], options)
|
|
1699
|
+
|
|
1700
|
+
|
|
1701
|
+
# $function: systemType
|
|
1702
|
+
# $group: System
|
|
1703
|
+
# $doc: Get a value's type string
|
|
1704
|
+
# $arg value: The value
|
|
1705
|
+
# $return: The type string of the value.
|
|
1706
|
+
# $return: Valid values are: 'array', 'boolean', 'datetime', 'function', 'null', 'number', 'object', 'regex', 'string'.
|
|
1707
|
+
def _system_type(args, unused_options):
|
|
1708
|
+
value, = default_args(args, (None,))
|
|
1709
|
+
return value_type(value)
|
|
1710
|
+
|
|
1711
|
+
|
|
1712
|
+
#
|
|
1713
|
+
# URL functions
|
|
1714
|
+
#
|
|
1715
|
+
|
|
1716
|
+
|
|
1717
|
+
# $function: urlEncode
|
|
1718
|
+
# $group: URL
|
|
1719
|
+
# $doc: Encode a URL
|
|
1720
|
+
# $arg url: The URL string
|
|
1721
|
+
# $arg extra: Optional (default is true). If true, encode extra characters for wider compatibility.
|
|
1722
|
+
# $return: The encoded URL string
|
|
1723
|
+
def _url_encode(args, unused_options):
|
|
1724
|
+
url, extra = default_args(args, (None, True))
|
|
1725
|
+
if not isinstance(url, str):
|
|
1726
|
+
return None
|
|
1727
|
+
|
|
1728
|
+
safe = "':/&(" if value_boolean(extra) else "':/&()"
|
|
1729
|
+
return urllib.parse.quote(url, safe=safe)
|
|
1730
|
+
|
|
1731
|
+
|
|
1732
|
+
# $function: urlEncodeComponent
|
|
1733
|
+
# $group: URL
|
|
1734
|
+
# $doc: Encode a URL component
|
|
1735
|
+
# $arg url: The URL component string
|
|
1736
|
+
# $arg extra: Optional (default is true). If true, encode extra characters for wider compatibility.
|
|
1737
|
+
# $return: The encoded URL component string
|
|
1738
|
+
def _url_encode_component(args, unused_options):
|
|
1739
|
+
url, extra = default_args(args, (None, True))
|
|
1740
|
+
if not isinstance(url, str):
|
|
1741
|
+
return None
|
|
1742
|
+
|
|
1743
|
+
safe = "'(" if value_boolean(extra) else "'()"
|
|
1744
|
+
return urllib.parse.quote(url, safe=safe)
|
|
1745
|
+
|
|
1746
|
+
|
|
1747
|
+
# The built-in script functions
|
|
1748
|
+
SCRIPT_FUNCTIONS = {
|
|
1749
|
+
'arrayCopy': _array_copy,
|
|
1750
|
+
'arrayExtend': _array_extend,
|
|
1751
|
+
'arrayGet': _array_get,
|
|
1752
|
+
'arrayIndexOf': _array_index_of,
|
|
1753
|
+
'arrayJoin': _array_join,
|
|
1754
|
+
'arrayLastIndexOf': _array_last_index_of,
|
|
1755
|
+
'arrayLength': _array_length,
|
|
1756
|
+
'arrayNew': _array_new,
|
|
1757
|
+
'arrayNewSize': _array_new_size,
|
|
1758
|
+
'arrayPop': _array_pop,
|
|
1759
|
+
'arrayPush': _array_push,
|
|
1760
|
+
'arraySet': _array_set,
|
|
1761
|
+
'arrayShift': _array_shift,
|
|
1762
|
+
'arraySlice': _array_slice,
|
|
1763
|
+
'arraySort': _array_sort,
|
|
1764
|
+
'dataAggregate': _data_aggregate,
|
|
1765
|
+
'dataCalculatedField': _data_calculated_field,
|
|
1766
|
+
'dataFilter': _data_filter,
|
|
1767
|
+
'dataJoin': _data_join,
|
|
1768
|
+
'dataParseCSV': _data_parse_csv,
|
|
1769
|
+
'dataSort': _data_sort,
|
|
1770
|
+
'dataTop': _data_top,
|
|
1771
|
+
'dataValidate': _data_validate,
|
|
1772
|
+
'datetimeDay': _datetime_day,
|
|
1773
|
+
'datetimeHour': _datetime_hour,
|
|
1774
|
+
'datetimeISOFormat': _datetime_iso_format,
|
|
1775
|
+
'datetimeISOParse': _datetime_iso_parse,
|
|
1776
|
+
'datetimeMillisecond': _datetime_millisecond,
|
|
1777
|
+
'datetimeMinute': _datetime_minute,
|
|
1778
|
+
'datetimeMonth': _datetime_month,
|
|
1779
|
+
'datetimeNew': _datetime_new,
|
|
1780
|
+
'datetimeNewUTC': _datetime_new_utc,
|
|
1781
|
+
'datetimeNow': _datetime_now,
|
|
1782
|
+
'datetimeSecond': _datetime_second,
|
|
1783
|
+
'datetimeToday': _datetime_today,
|
|
1784
|
+
'datetimeYear': _datetime_year,
|
|
1785
|
+
'jsonParse': _json_parse,
|
|
1786
|
+
'jsonStringify': _json_stringify,
|
|
1787
|
+
'mathAbs': _math_abs,
|
|
1788
|
+
'mathAcos': _math_acos,
|
|
1789
|
+
'mathAsin': _math_asin,
|
|
1790
|
+
'mathAtan': _math_atan,
|
|
1791
|
+
'mathAtan2': _math_atan2,
|
|
1792
|
+
'mathCeil': _math_ceil,
|
|
1793
|
+
'mathCos': _math_cos,
|
|
1794
|
+
'mathFloor': _math_floor,
|
|
1795
|
+
'mathLn': _math_ln,
|
|
1796
|
+
'mathLog': _math_log,
|
|
1797
|
+
'mathMax': _math_max,
|
|
1798
|
+
'mathMin': _math_min,
|
|
1799
|
+
'mathPi': _math_pi,
|
|
1800
|
+
'mathRandom': _math_random,
|
|
1801
|
+
'mathRound': _math_round,
|
|
1802
|
+
'mathSign': _math_sign,
|
|
1803
|
+
'mathSin': _math_sin,
|
|
1804
|
+
'mathSqrt': _math_sqrt,
|
|
1805
|
+
'mathTan': _math_tan,
|
|
1806
|
+
'numberParseInt': _number_parse_int,
|
|
1807
|
+
'numberParseFloat': _number_parse_float,
|
|
1808
|
+
'numberToFixed': _number_to_fixed,
|
|
1809
|
+
'objectAssign': _object_assign,
|
|
1810
|
+
'objectCopy': _object_copy,
|
|
1811
|
+
'objectDelete': _object_delete,
|
|
1812
|
+
'objectGet': _object_get,
|
|
1813
|
+
'objectHas': _object_has,
|
|
1814
|
+
'objectKeys': _object_keys,
|
|
1815
|
+
'objectNew': _object_new,
|
|
1816
|
+
'objectSet': _object_set,
|
|
1817
|
+
'regexEscape': _regex_escape,
|
|
1818
|
+
'regexMatch': _regex_match,
|
|
1819
|
+
'regexMatchAll': _regex_match_all,
|
|
1820
|
+
'regexNew': _regex_new,
|
|
1821
|
+
'regexReplace': _regex_replace,
|
|
1822
|
+
'regexSplit': _regex_split,
|
|
1823
|
+
'schemaParse': _schema_parse,
|
|
1824
|
+
'schemaParseEx': _schema_parse_ex,
|
|
1825
|
+
'schemaTypeModel': _schema_type_model,
|
|
1826
|
+
'schemaValidate': _schema_validate,
|
|
1827
|
+
'schemaValidateTypeModel': _schema_validate_type_model,
|
|
1828
|
+
'stringCharCodeAt': _string_char_code_at,
|
|
1829
|
+
'stringEndsWith': _string_ends_with,
|
|
1830
|
+
'stringFromCharCode': _string_from_char_code,
|
|
1831
|
+
'stringIndexOf': _string_index_of,
|
|
1832
|
+
'stringLastIndexOf': _string_last_index_of,
|
|
1833
|
+
'stringLength': _string_length,
|
|
1834
|
+
'stringLower': _string_lower,
|
|
1835
|
+
'stringNew': _string_new,
|
|
1836
|
+
'stringRepeat': _string_repeat,
|
|
1837
|
+
'stringReplace': _string_replace,
|
|
1838
|
+
'stringSlice': _string_slice,
|
|
1839
|
+
'stringSplit': _string_split,
|
|
1840
|
+
'stringStartsWith': _string_starts_with,
|
|
1841
|
+
'stringTrim': _string_trim,
|
|
1842
|
+
'stringUpper': _string_upper,
|
|
1843
|
+
'systemBoolean': _system_boolean,
|
|
1844
|
+
'systemCompare': _system_compare,
|
|
1845
|
+
'systemFetch': _system_fetch,
|
|
1846
|
+
'systemGlobalGet': _system_global_get,
|
|
1847
|
+
'systemGlobalSet': _system_global_set,
|
|
1848
|
+
'systemIs': _system_is,
|
|
1849
|
+
'systemLog': _system_log,
|
|
1850
|
+
'systemLogDebug': _system_log_debug,
|
|
1851
|
+
'systemPartial': _system_partial,
|
|
1852
|
+
'systemType': _system_type,
|
|
1853
|
+
'urlEncode': _url_encode,
|
|
1854
|
+
'urlEncodeComponent': _url_encode_component
|
|
1855
|
+
}
|
|
1856
|
+
|
|
1857
|
+
|
|
1858
|
+
# The built-in expression function name script function name map
|
|
1859
|
+
EXPRESSION_FUNCTION_MAP = {
|
|
1860
|
+
'abs': 'mathAbs',
|
|
1861
|
+
'acos': 'mathAcos',
|
|
1862
|
+
'asin': 'mathAsin',
|
|
1863
|
+
'atan': 'mathAtan',
|
|
1864
|
+
'atan2': 'mathAtan2',
|
|
1865
|
+
'ceil': 'mathCeil',
|
|
1866
|
+
'charCodeAt': 'stringCharCodeAt',
|
|
1867
|
+
'cos': 'mathCos',
|
|
1868
|
+
'date': 'datetimeNew',
|
|
1869
|
+
'day': 'datetimeDay',
|
|
1870
|
+
'endsWith': 'stringEndsWith',
|
|
1871
|
+
'indexOf': 'stringIndexOf',
|
|
1872
|
+
'fixed': 'numberToFixed',
|
|
1873
|
+
'floor': 'mathFloor',
|
|
1874
|
+
'fromCharCode': 'stringFromCharCode',
|
|
1875
|
+
'hour': 'datetimeHour',
|
|
1876
|
+
'lastIndexOf': 'stringLastIndexOf',
|
|
1877
|
+
'len': 'stringLength',
|
|
1878
|
+
'lower': 'stringLower',
|
|
1879
|
+
'ln': 'mathLn',
|
|
1880
|
+
'log': 'mathLog',
|
|
1881
|
+
'max': 'mathMax',
|
|
1882
|
+
'min': 'mathMin',
|
|
1883
|
+
'millisecond': 'datetimeMillisecond',
|
|
1884
|
+
'minute': 'datetimeMinute',
|
|
1885
|
+
'month': 'datetimeMonth',
|
|
1886
|
+
'now': 'datetimeNow',
|
|
1887
|
+
'parseInt': 'numberParseInt',
|
|
1888
|
+
'parseFloat': 'numberParseFloat',
|
|
1889
|
+
'pi': 'mathPi',
|
|
1890
|
+
'rand': 'mathRandom',
|
|
1891
|
+
'replace': 'stringReplace',
|
|
1892
|
+
'rept': 'stringRepeat',
|
|
1893
|
+
'round': 'mathRound',
|
|
1894
|
+
'second': 'datetimeSecond',
|
|
1895
|
+
'sign': 'mathSign',
|
|
1896
|
+
'sin': 'mathSin',
|
|
1897
|
+
'slice': 'stringSlice',
|
|
1898
|
+
'sqrt': 'mathSqrt',
|
|
1899
|
+
'startsWith': 'stringStartsWith',
|
|
1900
|
+
'text': 'stringNew',
|
|
1901
|
+
'tan': 'mathTan',
|
|
1902
|
+
'today': 'datetimeToday',
|
|
1903
|
+
'trim': 'stringTrim',
|
|
1904
|
+
'upper': 'stringUpper',
|
|
1905
|
+
'year': 'datetimeYear'
|
|
1906
|
+
}
|
|
1907
|
+
|
|
1908
|
+
|
|
1909
|
+
# The built-in expression functions
|
|
1910
|
+
EXPRESSION_FUNCTIONS = dict(
|
|
1911
|
+
(expr_fn_name, SCRIPT_FUNCTIONS[script_fn_name]) for expr_fn_name, script_fn_name in EXPRESSION_FUNCTION_MAP.items()
|
|
1912
|
+
)
|