bare-script 2.0.2 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +47 -9
- package/bin/bare.js +23 -0
- package/bin/bareDoc.js +23 -0
- package/lib/bare.js +176 -0
- package/lib/{libraryDoc.js → bareDoc.js} +54 -1
- package/lib/library.js +88 -99
- package/package.json +4 -3
- package/bin/bareScriptDoc.js +0 -15
package/README.md
CHANGED
|
@@ -42,7 +42,7 @@ return N + ' times 2 is ' + double(N)
|
|
|
42
42
|
|
|
43
43
|
// Execute the script
|
|
44
44
|
const globals = {'N': 10};
|
|
45
|
-
console.log(executeScript(script, {
|
|
45
|
+
console.log(executeScript(script, {globals}));
|
|
46
46
|
~~~
|
|
47
47
|
|
|
48
48
|
This outputs:
|
|
@@ -54,12 +54,14 @@ This outputs:
|
|
|
54
54
|
|
|
55
55
|
### The BareScript Library
|
|
56
56
|
|
|
57
|
-
[The BareScript Library](https://craigahobbs.github.io/bare-script/library/)
|
|
58
|
-
built-in functions for mathematical operations, object manipulation, array
|
|
59
|
-
expressions, HTTP fetch and more. The following example demonstrates the use
|
|
60
|
-
|
|
57
|
+
[The BareScript Library](https://craigahobbs.github.io/bare-script/library/)
|
|
58
|
+
includes a set of built-in functions for mathematical operations, object manipulation, array
|
|
59
|
+
manipulation, regular expressions, HTTP fetch and more. The following example demonstrates the use
|
|
60
|
+
of the
|
|
61
|
+
[systemFetch](https://craigahobbs.github.io/bare-script/library/#var.vName='systemFetch'),
|
|
61
62
|
[objectGet](https://craigahobbs.github.io/bare-script/library/#var.vName='objectGet'), and
|
|
62
|
-
[arrayLength](https://craigahobbs.github.io/bare-script/library/#var.vName='arrayLength')
|
|
63
|
+
[arrayLength](https://craigahobbs.github.io/bare-script/library/#var.vName='arrayLength')
|
|
64
|
+
functions.
|
|
63
65
|
|
|
64
66
|
~~~ javascript
|
|
65
67
|
import {executeScriptAsync} from 'bare-script/lib/runtimeAsync.js';
|
|
@@ -68,10 +70,10 @@ import {parseScript} from 'bare-script/lib/parser.js';
|
|
|
68
70
|
// Parse the script
|
|
69
71
|
const script = parseScript(`\
|
|
70
72
|
# Fetch the BareScript library documentation JSON
|
|
71
|
-
|
|
73
|
+
docs = systemFetch('https://craigahobbs.github.io/bare-script/library/library.json')
|
|
72
74
|
|
|
73
75
|
# Return the number of library functions
|
|
74
|
-
return 'The BareScript Library has ' + arrayLength(objectGet(
|
|
76
|
+
return 'The BareScript Library has ' + arrayLength(objectGet(docs, 'functions')) + ' functions'
|
|
75
77
|
`);
|
|
76
78
|
|
|
77
79
|
// Execute the script
|
|
@@ -81,7 +83,7 @@ console.log(await executeScriptAsync(script, {'fetchFn': fetch}));
|
|
|
81
83
|
This outputs:
|
|
82
84
|
|
|
83
85
|
~~~
|
|
84
|
-
The BareScript Library has
|
|
86
|
+
The BareScript Library has 89 functions
|
|
85
87
|
~~~
|
|
86
88
|
|
|
87
89
|
|
|
@@ -122,6 +124,42 @@ This outputs:
|
|
|
122
124
|
~~~
|
|
123
125
|
|
|
124
126
|
|
|
127
|
+
## The BareScript Command-Line Interface (CLI)
|
|
128
|
+
|
|
129
|
+
You can run BareScript from the command line using the BareScript CLI, "bare". BareScript script
|
|
130
|
+
files use the ".bare" file extension.
|
|
131
|
+
|
|
132
|
+
~~~
|
|
133
|
+
bare script.bare
|
|
134
|
+
~~~
|
|
135
|
+
|
|
136
|
+
**Note:** In the BareScript CLI, import statements and the
|
|
137
|
+
[systemFetch](https://craigahobbs.github.io/bare-script/library/#var.vName='systemFetch')
|
|
138
|
+
function read non-URL paths from the local file system.
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
## MarkdownUp, a Markdown Viewer with BareScript
|
|
142
|
+
|
|
143
|
+
[MarkdownUp](https://craigahobbs.github.io/markdown-up/)
|
|
144
|
+
is a Markdown Viewer that executes BareScript embedded within Markdown documents.
|
|
145
|
+
[MarkdownUp](https://craigahobbs.github.io/markdown-up/)
|
|
146
|
+
extends its
|
|
147
|
+
[standard library](https://craigahobbs.github.io/markdown-up/library/)
|
|
148
|
+
with functions for dynamically rendering Markdown text, drawing SVG images, etc.
|
|
149
|
+
|
|
150
|
+
For example:
|
|
151
|
+
|
|
152
|
+
```
|
|
153
|
+
# Markdown Application
|
|
154
|
+
|
|
155
|
+
This is a Markdown document with embedded BareScript:
|
|
156
|
+
|
|
157
|
+
~~~ markdown-script
|
|
158
|
+
markdownPrint('Hello, Markdown!')
|
|
159
|
+
~~~
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
|
|
125
163
|
## Development
|
|
126
164
|
|
|
127
165
|
This package is developed using [javascript-build](https://github.com/craigahobbs/javascript-build#readme).
|
package/bin/bare.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Licensed under the MIT License
|
|
3
|
+
// https://github.com/craigahobbs/bare-script/blob/main/LICENSE
|
|
4
|
+
|
|
5
|
+
import {argv, exit, stdout} from 'node:process';
|
|
6
|
+
import {main} from '../lib/bare.js';
|
|
7
|
+
import {readFile} from 'node:fs/promises';
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
const rURL = /^[a-z]+:/;
|
|
11
|
+
exit(await main({
|
|
12
|
+
argv,
|
|
13
|
+
'fetchFn': (fetchURL, fetchOptions) => {
|
|
14
|
+
if (rURL.test(fetchURL)) {
|
|
15
|
+
return fetch(fetchURL, fetchOptions);
|
|
16
|
+
}
|
|
17
|
+
return {
|
|
18
|
+
'ok': true,
|
|
19
|
+
'text': () => readFile(fetchURL, 'utf-8')
|
|
20
|
+
};
|
|
21
|
+
},
|
|
22
|
+
'logFn': (message) => stdout.write(`${message}\n`)
|
|
23
|
+
}));
|
package/bin/bareDoc.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Licensed under the MIT License
|
|
3
|
+
// https://github.com/craigahobbs/bare-script/blob/main/LICENSE
|
|
4
|
+
|
|
5
|
+
import {argv, exit, stdout} from 'node:process';
|
|
6
|
+
import {main} from '../lib/bareDoc.js';
|
|
7
|
+
import {readFile} from 'node:fs/promises';
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
const rURL = /^[a-z]+:/;
|
|
11
|
+
exit(await main({
|
|
12
|
+
argv,
|
|
13
|
+
'fetchFn': (fetchURL, fetchOptions) => {
|
|
14
|
+
if (rURL.test(fetchURL)) {
|
|
15
|
+
return fetch(fetchURL, fetchOptions);
|
|
16
|
+
}
|
|
17
|
+
return {
|
|
18
|
+
'ok': true,
|
|
19
|
+
'text': () => readFile(fetchURL, 'utf-8')
|
|
20
|
+
};
|
|
21
|
+
},
|
|
22
|
+
'logFn': (message) => stdout.write(`${message}\n`)
|
|
23
|
+
}));
|
package/lib/bare.js
ADDED
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
// Licensed under the MIT License
|
|
2
|
+
// https://github.com/craigahobbs/bare-script/blob/main/LICENSE
|
|
3
|
+
|
|
4
|
+
import {parseExpression, parseScript} from './parser.js';
|
|
5
|
+
import {evaluateExpression} from './runtime.js';
|
|
6
|
+
import {executeScriptAsync} from './runtimeAsync.js';
|
|
7
|
+
import {lintScript} from './model.js';
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
// The command-line interface (CLI) help text
|
|
11
|
+
export const helpText = `\
|
|
12
|
+
usage: bare [-h] [-c CODE] [-d] [-v VAR EXPR] [filename ...]
|
|
13
|
+
|
|
14
|
+
The BareScript command-line interface
|
|
15
|
+
|
|
16
|
+
positional arguments:
|
|
17
|
+
filename
|
|
18
|
+
|
|
19
|
+
options:
|
|
20
|
+
-h, --help show this help message and exit
|
|
21
|
+
-c, --code CODE execute the BareScript code
|
|
22
|
+
-d, --debug enable debug mode
|
|
23
|
+
-v, --var VAR EXPR set a global variable to an expression value`;
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* BareScript CLI options
|
|
28
|
+
*
|
|
29
|
+
* @typedef {Object} BareOptions
|
|
30
|
+
* @property {string[]} argv - The process command-line arguments
|
|
31
|
+
* @property {function} fetchFn - The [fetch function]{@link module:lib/runtime~FetchFn}
|
|
32
|
+
* @property {function} logFn - The [log function]{@link module:lib/runtime~LogFn}
|
|
33
|
+
* @ignore
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* BareScript command-line interface (CLI) main entry point
|
|
39
|
+
*
|
|
40
|
+
* @param {Object} options - The [CLI options]{@link module:lib/bare~BareOptions}
|
|
41
|
+
* @returns {Number} The exit code
|
|
42
|
+
* @ignore
|
|
43
|
+
*/
|
|
44
|
+
export async function main(options) {
|
|
45
|
+
let currentFile = null;
|
|
46
|
+
try {
|
|
47
|
+
const args = parseArgs(options.argv);
|
|
48
|
+
|
|
49
|
+
// Read the source files
|
|
50
|
+
const responses = await Promise.all(args.files.map(async ([url, source]) => {
|
|
51
|
+
if (source !== null) {
|
|
52
|
+
return {'ok': true, 'text': () => source};
|
|
53
|
+
}
|
|
54
|
+
try {
|
|
55
|
+
return await options.fetchFn(url);
|
|
56
|
+
} catch {
|
|
57
|
+
throw Error(`Failed to load "${url}"`);
|
|
58
|
+
}
|
|
59
|
+
}));
|
|
60
|
+
const files = await Promise.all(responses.map(async (response, ixResponse) => {
|
|
61
|
+
const [url] = args.files[ixResponse];
|
|
62
|
+
let source = null;
|
|
63
|
+
if (response.ok) {
|
|
64
|
+
try {
|
|
65
|
+
source = await response.text();
|
|
66
|
+
} catch {
|
|
67
|
+
// Do nothing
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
if (source === null) {
|
|
71
|
+
throw Error(`Failed to load "${url}"`);
|
|
72
|
+
}
|
|
73
|
+
return [url, source];
|
|
74
|
+
}));
|
|
75
|
+
|
|
76
|
+
// Parse the source files
|
|
77
|
+
const scripts = [];
|
|
78
|
+
for (const [file, source] of files) {
|
|
79
|
+
currentFile = file;
|
|
80
|
+
scripts.push([file, parseScript(source)]);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Lint and execute the source scripts
|
|
84
|
+
for (const [file, script] of scripts) {
|
|
85
|
+
currentFile = file;
|
|
86
|
+
|
|
87
|
+
// Run the bare-script linter?
|
|
88
|
+
if (args.debug) {
|
|
89
|
+
const warnings = lintScript(script);
|
|
90
|
+
const warningPrefix = `BareScript: Static analysis...`;
|
|
91
|
+
if (warnings.length === 0) {
|
|
92
|
+
options.logFn(`${warningPrefix} OK`);
|
|
93
|
+
} else {
|
|
94
|
+
options.logFn(`${warningPrefix} ${warnings.length} warning${warnings.length > 1 ? 's' : ''}:`);
|
|
95
|
+
for (const warning of warnings) {
|
|
96
|
+
options.logFn(`BareScript: ${warning}`);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Execute the script
|
|
102
|
+
const timeBegin = performance.now();
|
|
103
|
+
// eslint-disable-next-line no-await-in-loop
|
|
104
|
+
await executeScriptAsync(script, {
|
|
105
|
+
'debug': args.debug ?? false,
|
|
106
|
+
'fetchFn': options.fetchFn,
|
|
107
|
+
'globals': args.variables,
|
|
108
|
+
'logFn': (message) => options.logFn(message),
|
|
109
|
+
'systemPrefix': 'https://craigahobbs.github.io/markdown-up/include/',
|
|
110
|
+
'urlFn': (url) => (rURL.test(url) || url.startsWith('/') ? url : `${file.slice(0, file.lastIndexOf('/') + 1)}${url}`)
|
|
111
|
+
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
// Log script execution end with timing
|
|
115
|
+
if (args.debug) {
|
|
116
|
+
const timeEnd = performance.now();
|
|
117
|
+
options.logFn(`BareScript: Script executed in ${(timeEnd - timeBegin).toFixed(1)} milliseconds`);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
} catch ({message}) {
|
|
121
|
+
const fileStr = (currentFile !== null ? `${currentFile}:\n` : '');
|
|
122
|
+
options.logFn(`${fileStr}${message}`);
|
|
123
|
+
return 1;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return 0;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
// Regex to match a URL
|
|
131
|
+
const rURL = /^[a-z]+:/;
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Parse the BareScript command-line interface (CLI) arguments
|
|
136
|
+
*
|
|
137
|
+
* @param {string} argv - The command-line arguments
|
|
138
|
+
* @returns {Object} The arguments object
|
|
139
|
+
* @throws {Error}
|
|
140
|
+
* @ignore
|
|
141
|
+
*/
|
|
142
|
+
export function parseArgs(argv) {
|
|
143
|
+
const args = {'files': [], 'variables': {}};
|
|
144
|
+
let codeCount = 0;
|
|
145
|
+
for (let iArg = 2; iArg < argv.length; iArg++) {
|
|
146
|
+
const arg = argv[iArg];
|
|
147
|
+
if (arg === '-c' || arg === '--code') {
|
|
148
|
+
if (iArg + 1 >= argv.length) {
|
|
149
|
+
throw new Error(`Missing value for ${arg}`);
|
|
150
|
+
}
|
|
151
|
+
args.files.push([`-c ${++codeCount}`, argv[iArg + 1]]);
|
|
152
|
+
iArg++;
|
|
153
|
+
} else if (arg === '-d' || arg === '--debug') {
|
|
154
|
+
args.debug = true;
|
|
155
|
+
} else if (arg === '-h' || arg === '--help') {
|
|
156
|
+
args.help = true;
|
|
157
|
+
} else if (arg === '-v' || arg === '--var') {
|
|
158
|
+
if (iArg + 2 >= argv.length) {
|
|
159
|
+
throw new Error(`Missing values for ${arg}`);
|
|
160
|
+
}
|
|
161
|
+
args.variables[argv[iArg + 1]] = evaluateExpression(parseExpression(argv[iArg + 2]));
|
|
162
|
+
iArg += 2;
|
|
163
|
+
} else if (arg.startsWith('-')) {
|
|
164
|
+
throw new Error(`Unknown option ${arg}`);
|
|
165
|
+
} else {
|
|
166
|
+
args.files.push([arg, null]);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Show help, if necessary
|
|
171
|
+
if (args.help || args.files.length === 0) {
|
|
172
|
+
throw new Error(helpText);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
return args;
|
|
176
|
+
}
|
|
@@ -2,6 +2,59 @@
|
|
|
2
2
|
// https://github.com/craigahobbs/bare-script/blob/main/LICENSE
|
|
3
3
|
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* BareScript library documentation CLI options
|
|
7
|
+
*
|
|
8
|
+
* @typedef {Object} BareDocOptions
|
|
9
|
+
* @property {string[]} argv - The process command-line arguments
|
|
10
|
+
* @property {function} fetchFn - The [fetch function]{@link module:lib/runtime~FetchFn}
|
|
11
|
+
* @property {function} logFn - The [log function]{@link module:lib/runtime~LogFn}
|
|
12
|
+
* @ignore
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* BareScript library documentation command-line interface (CLI) main entry point
|
|
18
|
+
*
|
|
19
|
+
* @param {Object} options - The CLI [options]{@link module:lib/bare~BareDocOptions}
|
|
20
|
+
* @returns {Number} The exit code
|
|
21
|
+
* @ignore
|
|
22
|
+
*/
|
|
23
|
+
export async function main(options) {
|
|
24
|
+
try {
|
|
25
|
+
const urls = options.argv.slice(2);
|
|
26
|
+
const responses = await Promise.all(urls.map(async (url) => {
|
|
27
|
+
try {
|
|
28
|
+
return await options.fetchFn(url);
|
|
29
|
+
} catch {
|
|
30
|
+
throw Error(`Failed to load "${url}"`);
|
|
31
|
+
}
|
|
32
|
+
}));
|
|
33
|
+
const files = await Promise.all(responses.map(async (response, ixResponse) => {
|
|
34
|
+
const url = urls[ixResponse];
|
|
35
|
+
let text = null;
|
|
36
|
+
if (response.ok) {
|
|
37
|
+
try {
|
|
38
|
+
text = await response.text();
|
|
39
|
+
} catch {
|
|
40
|
+
// Do nothing
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
if (text === null) {
|
|
44
|
+
throw Error(`Failed to load "${url}"`);
|
|
45
|
+
}
|
|
46
|
+
return [url, text];
|
|
47
|
+
}));
|
|
48
|
+
options.logFn(JSON.stringify(parseBareDoc(files), null, 4));
|
|
49
|
+
} catch ({message}) {
|
|
50
|
+
options.logFn(message);
|
|
51
|
+
return 1;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return 0;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
|
|
5
58
|
/**
|
|
6
59
|
* Parse the library source for documentation tags
|
|
7
60
|
*
|
|
@@ -10,7 +63,7 @@
|
|
|
10
63
|
* @throws {Error}
|
|
11
64
|
* @ignore
|
|
12
65
|
*/
|
|
13
|
-
export function
|
|
66
|
+
export function parseBareDoc(files) {
|
|
14
67
|
// Parse each source file line-by-line
|
|
15
68
|
const errors = [];
|
|
16
69
|
const funcs = {};
|
package/lib/library.js
CHANGED
|
@@ -149,31 +149,6 @@ export const scriptFunctions = {
|
|
|
149
149
|
),
|
|
150
150
|
|
|
151
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
152
|
//
|
|
178
153
|
// Datetime functions
|
|
179
154
|
//
|
|
@@ -283,47 +258,6 @@ export const scriptFunctions = {
|
|
|
283
258
|
'datetimeYear': ([datetime]) => (datetime instanceof Date ? datetime.getFullYear() : null),
|
|
284
259
|
|
|
285
260
|
|
|
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
261
|
//
|
|
328
262
|
// JSON functions
|
|
329
263
|
//
|
|
@@ -664,37 +598,6 @@ export const scriptFunctions = {
|
|
|
664
598
|
'regexTest': ([regex, string]) => (regex instanceof RegExp ? regex.test(string) : null),
|
|
665
599
|
|
|
666
600
|
|
|
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
601
|
//
|
|
699
602
|
// Schema functions
|
|
700
603
|
//
|
|
@@ -875,6 +778,93 @@ export const scriptFunctions = {
|
|
|
875
778
|
'stringUpper': ([string]) => (typeof string === 'string' ? string.toUpperCase() : null),
|
|
876
779
|
|
|
877
780
|
|
|
781
|
+
//
|
|
782
|
+
// System functions
|
|
783
|
+
//
|
|
784
|
+
|
|
785
|
+
// $function: systemFetch
|
|
786
|
+
// $group: System
|
|
787
|
+
// $doc: Retrieve a remote JSON or text resource
|
|
788
|
+
// $arg url: The resource URL or array of URLs
|
|
789
|
+
// $arg options: Optional (default is null). The [fetch options](https://developer.mozilla.org/en-US/docs/Web/API/fetch#parameters).
|
|
790
|
+
// $arg isText: Optional (default is false). If true, retrieve the resource as text.
|
|
791
|
+
// $return: The resource object/string or array of objects/strings; null if an error occurred.
|
|
792
|
+
'systemFetch': async ([url, fetchOptions = null, isText = false], options) => {
|
|
793
|
+
const isArray = Array.isArray(url);
|
|
794
|
+
const urls = (isArray ? url : [url]).map((mURL) => (options !== null && 'urlFn' in options ? options.urlFn(mURL) : mURL));
|
|
795
|
+
const responses = await Promise.all(urls.map(async (fURL) => {
|
|
796
|
+
try {
|
|
797
|
+
return 'fetchFn' in options ? await (fetchOptions ? options.fetchFn(fURL, fetchOptions) : options.fetchFn(fURL)) : null;
|
|
798
|
+
} catch {
|
|
799
|
+
return null;
|
|
800
|
+
}
|
|
801
|
+
}));
|
|
802
|
+
const values = await Promise.all(responses.map(async (response) => {
|
|
803
|
+
try {
|
|
804
|
+
return response !== null && response.ok ? await (isText ? response.text() : response.json()) : null;
|
|
805
|
+
} catch {
|
|
806
|
+
return null;
|
|
807
|
+
}
|
|
808
|
+
}));
|
|
809
|
+
|
|
810
|
+
// Log failures
|
|
811
|
+
for (const [ixValue, value] of values.entries()) {
|
|
812
|
+
if (value === null && options !== null && 'logFn' in options && options.debug) {
|
|
813
|
+
const errorURL = urls[ixValue];
|
|
814
|
+
options.logFn(`BareScript: Function "systemFetch" failed for ${isText ? 'text' : 'JSON'} resource "${errorURL}"`);
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
return isArray ? values : values[0];
|
|
819
|
+
},
|
|
820
|
+
|
|
821
|
+
// $function: systemGlobalGet
|
|
822
|
+
// $group: System
|
|
823
|
+
// $doc: Get a global variable value
|
|
824
|
+
// $arg name: The global variable name
|
|
825
|
+
// $return: The global variable's value or null if it does not exist
|
|
826
|
+
'systemGlobalGet': ([name], options) => {
|
|
827
|
+
const globals = (options !== null ? (options.globals ?? null) : null);
|
|
828
|
+
return (globals !== null ? (globals[name] ?? null) : null);
|
|
829
|
+
},
|
|
830
|
+
|
|
831
|
+
// $function: systemGlobalSet
|
|
832
|
+
// $group: System
|
|
833
|
+
// $doc: Set a global variable value
|
|
834
|
+
// $arg name: The global variable name
|
|
835
|
+
// $arg value: The global variable's value
|
|
836
|
+
// $return: The global variable's value
|
|
837
|
+
'systemGlobalSet': ([name, value], options) => {
|
|
838
|
+
if (options !== null) {
|
|
839
|
+
const globals = options.globals ?? null;
|
|
840
|
+
if (globals !== null) {
|
|
841
|
+
globals[name] = value;
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
return value;
|
|
845
|
+
},
|
|
846
|
+
|
|
847
|
+
// $function: systemLog
|
|
848
|
+
// $group: System
|
|
849
|
+
// $doc: Log a message to the console
|
|
850
|
+
// $arg string: The message
|
|
851
|
+
'systemLog': ([string], options) => {
|
|
852
|
+
if (options !== null && 'logFn' in options) {
|
|
853
|
+
options.logFn(string);
|
|
854
|
+
}
|
|
855
|
+
},
|
|
856
|
+
|
|
857
|
+
// $function: systemLogDebug
|
|
858
|
+
// $group: System
|
|
859
|
+
// $doc: Log a message to the console, if in debug mode
|
|
860
|
+
// $arg string: The message
|
|
861
|
+
'systemLogDebug': ([string], options) => {
|
|
862
|
+
if (options !== null && 'logFn' in options && options.debug) {
|
|
863
|
+
options.logFn(string);
|
|
864
|
+
}
|
|
865
|
+
},
|
|
866
|
+
|
|
867
|
+
|
|
878
868
|
//
|
|
879
869
|
// URL functions
|
|
880
870
|
//
|
|
@@ -932,7 +922,6 @@ export const expressionFunctionMap = {
|
|
|
932
922
|
'date': 'datetimeNew',
|
|
933
923
|
'day': 'datetimeDay',
|
|
934
924
|
'endsWith': 'stringEndsWith',
|
|
935
|
-
'if': 'if',
|
|
936
925
|
'indexOf': 'stringIndexOf',
|
|
937
926
|
'fixed': 'numberToFixed',
|
|
938
927
|
'floor': 'mathFloor',
|
|
@@ -974,5 +963,5 @@ export const expressionFunctionMap = {
|
|
|
974
963
|
|
|
975
964
|
// The built-in expression functions
|
|
976
965
|
export const expressionFunctions = Object.fromEntries(Object.entries(expressionFunctionMap).map(
|
|
977
|
-
([exprFnName, scriptFnName]) => [exprFnName, scriptFunctions[scriptFnName]
|
|
966
|
+
([exprFnName, scriptFnName]) => [exprFnName, scriptFunctions[scriptFnName]]
|
|
978
967
|
).filter(([, exprFn]) => exprFn !== null));
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "bare-script",
|
|
4
|
-
"version": "2.0
|
|
4
|
+
"version": "2.1.0",
|
|
5
5
|
"description": "BareScript; a lightweight scripting and expression language",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"expression",
|
|
@@ -17,7 +17,8 @@
|
|
|
17
17
|
"url": "https://github.com/craigahobbs"
|
|
18
18
|
},
|
|
19
19
|
"bin": {
|
|
20
|
-
"
|
|
20
|
+
"bare": "./bin/bare.js",
|
|
21
|
+
"baredoc": "./bin/bareDoc.js"
|
|
21
22
|
},
|
|
22
23
|
"files": [
|
|
23
24
|
"lib/**/*"
|
|
@@ -30,7 +31,7 @@
|
|
|
30
31
|
},
|
|
31
32
|
"devDependencies": {
|
|
32
33
|
"c8": "~8.0",
|
|
33
|
-
"eslint": "~8.
|
|
34
|
+
"eslint": "~8.48",
|
|
34
35
|
"jsdoc": "~4.0"
|
|
35
36
|
}
|
|
36
37
|
}
|
package/bin/bareScriptDoc.js
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
// Licensed under the MIT License
|
|
3
|
-
// https://github.com/craigahobbs/bare-script/blob/main/LICENSE
|
|
4
|
-
|
|
5
|
-
import {argv, exit, stderr, stdout} from 'node:process';
|
|
6
|
-
import {parseLibraryDoc} from '../lib/libraryDoc.js';
|
|
7
|
-
import {readFileSync} from 'node:fs';
|
|
8
|
-
|
|
9
|
-
try {
|
|
10
|
-
stdout.write(JSON.stringify(parseLibraryDoc(argv.slice(2).map((file) => [file, readFileSync(file, 'utf-8')])), null, 4));
|
|
11
|
-
} catch (error) {
|
|
12
|
-
stderr.write(error.message);
|
|
13
|
-
stderr.write('\n');
|
|
14
|
-
exit(1);
|
|
15
|
-
}
|