bare-script 3.0.5 → 3.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -8
- package/lib/data.js +1 -1
- package/lib/library.js +672 -466
- package/lib/runtime.js +4 -1
- package/lib/runtimeAsync.js +4 -1
- package/lib/value.js +223 -0
- package/package.json +1 -1
package/lib/runtime.js
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
|
|
4
4
|
/** @module lib/runtime */
|
|
5
5
|
|
|
6
|
+
import {ValueArgsError, valueBoolean, valueCompare, valueString} from './value.js';
|
|
6
7
|
import {defaultMaxStatements, expressionFunctions, scriptFunctions} from './library.js';
|
|
7
|
-
import {valueBoolean, valueCompare, valueString} from './value.js';
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
/**
|
|
@@ -211,6 +211,9 @@ export function evaluateExpression(expr, options = null, locals = null, builtins
|
|
|
211
211
|
if (options !== null && 'logFn' in options && options.debug) {
|
|
212
212
|
options.logFn(`BareScript: Function "${funcName}" failed with error: ${error.message}`);
|
|
213
213
|
}
|
|
214
|
+
if (error instanceof ValueArgsError) {
|
|
215
|
+
return error.returnValue;
|
|
216
|
+
}
|
|
214
217
|
return null;
|
|
215
218
|
}
|
|
216
219
|
}
|
package/lib/runtimeAsync.js
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
|
|
6
6
|
import {BareScriptParserError, parseScript} from './parser.js';
|
|
7
7
|
import {BareScriptRuntimeError, evaluateExpression, scriptFunction} from './runtime.js';
|
|
8
|
+
import {ValueArgsError, valueBoolean, valueCompare, valueString} from './value.js';
|
|
8
9
|
import {defaultMaxStatements, expressionFunctions, scriptFunctions} from './library.js';
|
|
9
|
-
import {valueBoolean, valueCompare, valueString} from './value.js';
|
|
10
10
|
import {lintScript} from './model.js';
|
|
11
11
|
import {urlFileRelative} from './options.js';
|
|
12
12
|
|
|
@@ -281,6 +281,9 @@ export async function evaluateExpressionAsync(expr, options = null, locals = nul
|
|
|
281
281
|
if (options !== null && 'logFn' in options && options.debug) {
|
|
282
282
|
options.logFn(`BareScript: Function "${funcName}" failed with error: ${error.message}`);
|
|
283
283
|
}
|
|
284
|
+
if (error instanceof ValueArgsError) {
|
|
285
|
+
return error.returnValue;
|
|
286
|
+
}
|
|
284
287
|
return null;
|
|
285
288
|
}
|
|
286
289
|
}
|
package/lib/value.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
// Licensed under the MIT License
|
|
2
2
|
// https://github.com/craigahobbs/bare-script/blob/main/LICENSE
|
|
3
3
|
|
|
4
|
+
import {parseSchemaMarkdown} from 'schema-markdown/lib/parser.js';
|
|
5
|
+
import {validateType} from 'schema-markdown/lib/schema.js';
|
|
6
|
+
|
|
4
7
|
|
|
5
8
|
/**
|
|
6
9
|
* Get a value's type string
|
|
@@ -205,6 +208,221 @@ export function valueCompare(left, right) {
|
|
|
205
208
|
}
|
|
206
209
|
|
|
207
210
|
|
|
211
|
+
//
|
|
212
|
+
// Function arguments validation
|
|
213
|
+
//
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Validate a function's arguments
|
|
218
|
+
*
|
|
219
|
+
* @param {Object[]} fnArgs - The function arguments model
|
|
220
|
+
* @param {Array} args - The function arguments
|
|
221
|
+
* @param {*} [errorReturnValue = null] - The function's return value on error
|
|
222
|
+
* @returns {Array} The validated function arguments
|
|
223
|
+
* @ignore
|
|
224
|
+
*/
|
|
225
|
+
export function valueArgsValidate(fnArgs, args, errorReturnValue = null) {
|
|
226
|
+
const fnArgsLength = fnArgs.length;
|
|
227
|
+
for (let ix = 0; ix < fnArgsLength; ix++) {
|
|
228
|
+
const fnArg = fnArgs[ix];
|
|
229
|
+
const {'type': argType = null, 'default': argDefault = null, lastArgArray = false} = fnArg;
|
|
230
|
+
|
|
231
|
+
// Missing argument?
|
|
232
|
+
if (ix >= args.length) {
|
|
233
|
+
// Last argument array?
|
|
234
|
+
if (lastArgArray) {
|
|
235
|
+
args.push([]);
|
|
236
|
+
continue;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// Argument default?
|
|
240
|
+
if (argDefault !== null) {
|
|
241
|
+
args.push(argDefault);
|
|
242
|
+
continue;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// Boolean argument?
|
|
246
|
+
if (argType === 'boolean') {
|
|
247
|
+
args.push(false);
|
|
248
|
+
continue;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// Argument nullable?
|
|
252
|
+
if (argType === null || fnArg.nullable) {
|
|
253
|
+
args.push(null);
|
|
254
|
+
continue;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// Invalid null value...
|
|
258
|
+
throw new ValueArgsError(fnArg.name, null, errorReturnValue);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// Last arg array?
|
|
262
|
+
if (lastArgArray) {
|
|
263
|
+
args.push(args.splice(ix));
|
|
264
|
+
continue;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// Any type OK?
|
|
268
|
+
if (argType === null) {
|
|
269
|
+
continue;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// Boolean argument?
|
|
273
|
+
const argValue = args[ix];
|
|
274
|
+
if (argType === 'boolean') {
|
|
275
|
+
args[ix] = valueBoolean(argValue);
|
|
276
|
+
continue;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// Null value?
|
|
280
|
+
const argValueType = typeof argValue;
|
|
281
|
+
if (argValue === null || argValueType === 'undefined') {
|
|
282
|
+
// Argument nullable?
|
|
283
|
+
if (!fnArg.nullable) {
|
|
284
|
+
throw new ValueArgsError(fnArg.name, argValue, errorReturnValue);
|
|
285
|
+
}
|
|
286
|
+
continue;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// Invalid value?
|
|
290
|
+
if ((argType === 'number' && argValueType !== 'number') ||
|
|
291
|
+
(argType === 'string' && argValueType !== 'string') ||
|
|
292
|
+
(argType === 'array' && !Array.isArray(argValue)) ||
|
|
293
|
+
(argType === 'object' && !(argValueType === 'object' && Object.getPrototypeOf(argValue) === Object.prototype)) ||
|
|
294
|
+
(argType === 'datetime' && !(argValue instanceof Date)) ||
|
|
295
|
+
(argType === 'regex' && !(argValue instanceof RegExp)) ||
|
|
296
|
+
(argType === 'function' && argValueType !== 'function')
|
|
297
|
+
) {
|
|
298
|
+
throw new ValueArgsError(fnArg.name, argValue, errorReturnValue);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// Number constraints
|
|
302
|
+
if (argType === 'number') {
|
|
303
|
+
const {integer = false, lt = null, lte = null, gt = null, gte = null} = fnArg;
|
|
304
|
+
if ((integer && Math.floor(argValue) !== argValue) ||
|
|
305
|
+
(lt !== null && !(argValue < lt)) ||
|
|
306
|
+
(lte !== null && !(argValue <= lte)) ||
|
|
307
|
+
(gt !== null && !(argValue > gt)) ||
|
|
308
|
+
(gte !== null && !(argValue >= gte))) {
|
|
309
|
+
throw new ValueArgsError(fnArg.name, argValue, errorReturnValue);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// Extra arguments?
|
|
315
|
+
if (args.length > fnArgsLength) {
|
|
316
|
+
args.splice(fnArgsLength);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
return args;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* A function arguments validation error
|
|
325
|
+
*
|
|
326
|
+
* @extends {Error}
|
|
327
|
+
* @property {*} returnValue - The function's error return value
|
|
328
|
+
* @ignore
|
|
329
|
+
*/
|
|
330
|
+
export class ValueArgsError extends Error {
|
|
331
|
+
/**
|
|
332
|
+
* Create a BareScript runtime error
|
|
333
|
+
*
|
|
334
|
+
* @param {string} argName - The function argument name
|
|
335
|
+
* @param {*} argValue - The function argument value
|
|
336
|
+
* @param {*} [returnValue = null] - The function's error return value
|
|
337
|
+
*/
|
|
338
|
+
constructor(argName, argValue, returnValue = null) {
|
|
339
|
+
const message = `Invalid "${argName}" argument value, ${valueJSON(argValue)}`;
|
|
340
|
+
super(message);
|
|
341
|
+
this.name = this.constructor.name;
|
|
342
|
+
this.returnValue = returnValue;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* Validate a function arguments model
|
|
349
|
+
*
|
|
350
|
+
* @param {Object[]} fnArgs - The function arguments model
|
|
351
|
+
* @returns {Object[]} The validated function arguments model
|
|
352
|
+
* @ignore
|
|
353
|
+
*/
|
|
354
|
+
export function valueArgsModel(fnArgs) {
|
|
355
|
+
validateType(valueArgsTypes, 'FunctionArguments', fnArgs);
|
|
356
|
+
|
|
357
|
+
// Use nullable instead of default-null
|
|
358
|
+
for (const fnArg of fnArgs) {
|
|
359
|
+
if (fnArg.default === null) {
|
|
360
|
+
throw Error(`Argument "${fnArg.name}" has default value of null - use nullable instead`);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
return fnArgs;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
|
|
368
|
+
// Function arguments type model
|
|
369
|
+
const valueArgsTypes = parseSchemaMarkdown(`\
|
|
370
|
+
# A function arguments model
|
|
371
|
+
typedef FunctionArgument[len > 0] FunctionArguments
|
|
372
|
+
|
|
373
|
+
|
|
374
|
+
# A function argument model
|
|
375
|
+
struct FunctionArgument
|
|
376
|
+
|
|
377
|
+
# The argument name
|
|
378
|
+
string name
|
|
379
|
+
|
|
380
|
+
# The argument type
|
|
381
|
+
optional FunctionArgumentType type
|
|
382
|
+
|
|
383
|
+
# If true, the argument may be null
|
|
384
|
+
optional bool nullable
|
|
385
|
+
|
|
386
|
+
# The default argument value
|
|
387
|
+
optional object default
|
|
388
|
+
|
|
389
|
+
# If true, this argument is the array of remaining arguments
|
|
390
|
+
optional object lastArgArray
|
|
391
|
+
|
|
392
|
+
# If true, the number argument must be an integer
|
|
393
|
+
optional bool integer
|
|
394
|
+
|
|
395
|
+
# The number argument must be less-than
|
|
396
|
+
optional object lt
|
|
397
|
+
|
|
398
|
+
# The number argument must be less-than-or-equal-to
|
|
399
|
+
optional object lte
|
|
400
|
+
|
|
401
|
+
# The number argument must be greater-than
|
|
402
|
+
optional object gt
|
|
403
|
+
|
|
404
|
+
# The number argument must be greater-than-or-equal-to
|
|
405
|
+
optional object gte
|
|
406
|
+
|
|
407
|
+
|
|
408
|
+
# The function argument types
|
|
409
|
+
enum FunctionArgumentType
|
|
410
|
+
array
|
|
411
|
+
boolean
|
|
412
|
+
datetime
|
|
413
|
+
function
|
|
414
|
+
number
|
|
415
|
+
object
|
|
416
|
+
regex
|
|
417
|
+
string
|
|
418
|
+
`);
|
|
419
|
+
|
|
420
|
+
|
|
421
|
+
//
|
|
422
|
+
// Number value functions
|
|
423
|
+
//
|
|
424
|
+
|
|
425
|
+
|
|
208
426
|
/**
|
|
209
427
|
* Round a number
|
|
210
428
|
*
|
|
@@ -256,6 +474,11 @@ export function valueParseInteger(text, radix = 10) {
|
|
|
256
474
|
const rInteger = /^\s*[-+]?\d+\s*$/;
|
|
257
475
|
|
|
258
476
|
|
|
477
|
+
//
|
|
478
|
+
// Datetime value functions
|
|
479
|
+
//
|
|
480
|
+
|
|
481
|
+
|
|
259
482
|
/**
|
|
260
483
|
* Parse a datetime string
|
|
261
484
|
*
|