bare-script 3.0.15 → 3.2.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/lib/bare.js CHANGED
@@ -1,10 +1,13 @@
1
1
  // Licensed under the MIT License
2
2
  // https://github.com/craigahobbs/bare-script/blob/main/LICENSE
3
3
 
4
+ import {dirname, join} from 'path';
4
5
  import {parseExpression, parseScript} from './parser.js';
5
6
  import {evaluateExpression} from './runtime.js';
6
7
  import {executeScriptAsync} from './runtimeAsync.js';
8
+ import {fileURLToPath} from 'url';
7
9
  import {lintScript} from './model.js';
10
+ import {readFile} from 'fs/promises';
8
11
  import {urlFileRelative} from './options.js';
9
12
  import {valueBoolean} from './value.js';
10
13
 
@@ -51,8 +54,14 @@ export async function main(options) {
51
54
  globals[varName] = evaluateExpression(parseExpression(varExpr));
52
55
  }
53
56
 
57
+ // Get the scripts to run
58
+ let {scripts} = args;
59
+ if (args.markdownUp) {
60
+ scripts = [['code', 'include <markdownUp.bare>'], ...scripts];
61
+ }
62
+
54
63
  // Parse and execute all source files in order
55
- for (const [scriptType, scriptValue] of args.scripts) {
64
+ for (const [scriptType, scriptValue] of scripts) {
56
65
  // Get the script source
57
66
  let scriptName;
58
67
  let scriptSource;
@@ -103,12 +112,14 @@ export async function main(options) {
103
112
 
104
113
  // Execute the script
105
114
  const timeBegin = performance.now();
115
+ const {fetchFn} = options;
116
+ const fetchIncludeFn = (fetchURL, fetchOptions) => fetchInclude(fetchFn, fetchURL, fetchOptions);
106
117
  const result = await executeScriptAsync(script, {
107
118
  'debug': args.debug ?? false,
108
- 'fetchFn': options.fetchFn,
119
+ 'fetchFn': fetchIncludeFn,
109
120
  'globals': globals,
110
121
  'logFn': options.logFn,
111
- 'systemPrefix': 'https://craigahobbs.github.io/markdown-up/include/',
122
+ 'systemPrefix': fetchIncludePrefix,
112
123
  'urlFn': scriptType === 'file' ? (url) => urlFileRelative(scriptName, url) : null
113
124
 
114
125
  });
@@ -141,6 +152,35 @@ export async function main(options) {
141
152
  }
142
153
 
143
154
 
155
+ function fetchInclude(fetchFn, url, options) {
156
+ // Is this a bare system include?
157
+ if (url.startsWith(fetchIncludePrefix)) {
158
+ const includePath = url.slice(fetchIncludePrefixPrefix.length);
159
+
160
+ // Get the include file path
161
+ const packageDir = dirname(fileURLToPath(import.meta.url));
162
+ const packagePath = join(packageDir, includePath);
163
+
164
+ // Return the include fetch-like promise
165
+ return new Promise((resolve) => {
166
+ const response = {
167
+ 'ok': true,
168
+ 'status': 200,
169
+ 'statusText': 'OK',
170
+ 'text': () => readFile(packagePath, 'utf8')
171
+ };
172
+ resolve(response);
173
+ });
174
+ }
175
+
176
+ return fetchFn(url, options);
177
+ }
178
+
179
+
180
+ const fetchIncludePrefixPrefix = ':bare-include:/';
181
+ const fetchIncludePrefix = `${fetchIncludePrefixPrefix}include/`;
182
+
183
+
144
184
  /**
145
185
  * Parse the BareScript command-line interface (CLI) arguments
146
186
  *
@@ -163,6 +203,8 @@ export function parseArgs(argv) {
163
203
  args.debug = true;
164
204
  } else if (arg === '-h' || arg === '--help') {
165
205
  args.help = true;
206
+ } else if (arg === '-m' || arg === '--markdown-up') {
207
+ args.markdownUp = true;
166
208
  } else if (arg === '-s' || arg === '--static') {
167
209
  args.static = true;
168
210
  } else if (arg === '-v' || arg === '--var') {
@@ -184,7 +226,7 @@ export function parseArgs(argv) {
184
226
 
185
227
  // The command-line interface (CLI) help text
186
228
  export const helpText = `\
187
- usage: bare [-h] [-c CODE] [-d] [-s] [-v VAR EXPR] [file ...]
229
+ usage: bare [-h] [-c CODE] [-d] [-m] [-s] [-v VAR EXPR] [file ...]
188
230
 
189
231
  The BareScript command-line interface
190
232
 
@@ -195,5 +237,6 @@ options:
195
237
  -h, --help show this help message and exit
196
238
  -c, --code CODE execute the BareScript code
197
239
  -d, --debug enable debug mode
240
+ -m, --markdown-up run with MarkdownUp stubs
198
241
  -s, --static perform static analysis
199
242
  -v, --var VAR EXPR set a global variable to an expression value`;
@@ -0,0 +1,344 @@
1
+ # Licensed under the MIT License
2
+ # https://github.com/craigahobbs/markdown-up/blob/main/LICENSE
3
+
4
+
5
+ # Include sentinel
6
+ if systemGlobalGet('argsSentinel'):
7
+ return
8
+ endif
9
+ argsSentinel = true
10
+
11
+
12
+ # The URL arguments model
13
+ argsTypes = schemaParse( \
14
+ 'group "Args"', \
15
+ '', \
16
+ '', \
17
+ '# An argument model list', \
18
+ 'typedef ArgsArgument[len > 0] ArgsArguments', \
19
+ '', \
20
+ '', \
21
+ '# An argument model', \
22
+ 'struct ArgsArgument', \
23
+ '', \
24
+ ' # The argument name', \
25
+ ' string(len > 0) name', \
26
+ '', \
27
+ ' # The argument type', \
28
+ ' optional ArgsType type', \
29
+ '', \
30
+ " # The argument's global variable name", \
31
+ ' optional string(len > 0) global', \
32
+ '', \
33
+ ' # If true, the argument is explicit.', \
34
+ ' # An explicit argument is only included in the URL if it is in the arguments object.', \
35
+ ' optional bool explicit', \
36
+ '', \
37
+ ' # The default argument value', \
38
+ ' optional object default', \
39
+ '', \
40
+ ' # The argument description', \
41
+ ' optional string(len > 0) description', \
42
+ '', \
43
+ '', \
44
+ '# An argument value type', \
45
+ 'enum ArgsType', \
46
+ ' bool', \
47
+ ' date', \
48
+ ' datetime', \
49
+ ' float', \
50
+ ' int', \
51
+ ' string' \
52
+ )
53
+
54
+
55
+ # $function: argsValidate
56
+ # $group: args.mds
57
+ # $doc: Validate an arguments model
58
+ # $arg arguments: The [arguments model](includeModel.html#var.vName='ArgsArguments')
59
+ # $return: The validated [arguments model](includeModel.html#var.vName='ArgsArguments') or null if validation fails
60
+ function argsValidate(arguments):
61
+ validatedArguments = schemaValidate(argsTypes, 'ArgsArguments', arguments)
62
+
63
+ # Check for duplicate arguments
64
+ if validatedArguments != null:
65
+ argNames = objectNew()
66
+ for argument in arguments:
67
+ name = objectGet(argument, 'name')
68
+ if objectHas(argNames, name):
69
+ validatedArguments = null
70
+ systemLogDebug('MarkdownUp - args.mds: Duplicate argument "' + name + '"')
71
+ else:
72
+ objectSet(argNames, name, true)
73
+ endif
74
+ endfor
75
+ endif
76
+
77
+ return validatedArguments
78
+ endfunction
79
+
80
+
81
+ # $function: argsParse
82
+ # $group: args.mds
83
+ # $doc: Parse an [arguments model](includeModel.html#var.vName='ArgsArguments').
84
+ # $doc: Argument globals are validated and added to the arguments object using the argument name.
85
+ # $arg arguments: The [arguments model](includeModel.html#var.vName='ArgsArguments')
86
+ # $return: The arguments object
87
+ function argsParse(arguments):
88
+ # Create the arguments object
89
+ args = objectNew()
90
+ for argument in arguments:
91
+ # Get the argument value
92
+ global = argsGlobalName(argument)
93
+ value = argsValidateValue(systemGlobalGet(global), objectGet(argument, 'type'), global)
94
+
95
+ # Apply the default argument value, if any
96
+ if value == null:
97
+ value = objectGet(argument, 'default')
98
+ endif
99
+
100
+ # Set the argument value, if any
101
+ if value != null:
102
+ objectSet(args, objectGet(argument, 'name'), value)
103
+ endif
104
+ endfor
105
+
106
+ return args
107
+ endfunction
108
+
109
+
110
+ # $function: argsURL
111
+ # $group: args.mds
112
+ # $doc: Create a MarkdownUp application URL
113
+ # $arg arguments: The [arguments model](includeModel.html#var.vName='ArgsArguments')
114
+ # $arg args: Optional (default is null). The arguments object. Null argument values are excluded from the URL.
115
+ # $arg explicit: Optional (default is false). If true, arguments are only included in the URL if they are in the arguments object.
116
+ # $arg headerText: Optional (default is null). If non-null, the URL's header text.
117
+ # $arg headerText: The special "_top" header ID scrolls to the top of the page.
118
+ # $arg url: Optional (default is null). If non-null, the MarkdownUp URL hash parameter.
119
+ # $return: The MarkdownUp application URL
120
+ function argsURL(arguments, args, explicit, headerText, url):
121
+ # Get the URL variables
122
+ urlVars = arrayNew()
123
+ argNames = objectNew()
124
+ for argument in arguments:
125
+ name = objectGet(argument, 'name')
126
+ type = objectGet(argument, 'type')
127
+ global = argsGlobalName(argument)
128
+ default = objectGet(argument, 'default')
129
+
130
+ # Add the argument name (for unknown argument check below)
131
+ objectSet(argNames, name, null)
132
+
133
+ # Add the URL variable, if any
134
+ value = null
135
+ if args != null && objectHas(args, name):
136
+ value = argsValidateValue(objectGet(args, name), type, global)
137
+ elif !(explicit || objectGet(argument, 'explicit')):
138
+ value = argsValidateValue(systemGlobalGet(global), type, global, false)
139
+ endif
140
+
141
+ # Add the URL variable
142
+ if value != null && (default == null || !argsValuesEqual(value, default, type)):
143
+ arrayPush(urlVars, 'var.' + global + '=' + urlEncodeComponent(argsFormatValue(value, type)))
144
+ endif
145
+ endfor
146
+
147
+ # Sort the URL variables for general consistency
148
+ arraySort(urlVars)
149
+
150
+ # Check for unknown arguments
151
+ if args != null:
152
+ for name in objectKeys(args):
153
+ if !objectHas(argNames, name):
154
+ systemLogDebug('MarkdownUp - args.mds: Unknown argument "' + name + '"')
155
+ endif
156
+ endfor
157
+ endif
158
+
159
+ # Create the URL
160
+ return '#' + if(url != null, 'url=' + urlEncodeComponent(url) + '&', '') + \
161
+ if(arrayLength(urlVars), arrayJoin(urlVars, '&'), 'var=') + \
162
+ if(headerText != null, '&' + if(headerText == argsTopHeaderId, argsTopHeaderId, markdownHeaderId(headerText)), '')
163
+ endfunction
164
+
165
+
166
+ # The special "top" header ID
167
+ argsTopHeaderId = '_top'
168
+
169
+
170
+ # $function: argsLink
171
+ # $group: args.mds
172
+ # $doc: Create a Markdown link text to a MarkdownUp application URL
173
+ # $arg arguments: The [arguments model](includeModel.html#var.vName='ArgsArguments')
174
+ # $arg text: The link text
175
+ # $arg args: Optional (default is null). The arguments object.
176
+ # $arg explicit: Optional (default is false). If true, arguments are only included in the URL if they are in the arguments object.
177
+ # $arg headerText: Optional (default is null). If non-null, the URL's header text.
178
+ # $arg headerText: The special "_top" header ID scrolls to the top of the page.
179
+ # $arg url: Optional (default is null). If non-null, the MarkdownUp URL hash parameter.
180
+ # $return: The Markdown link text
181
+ function argsLink(arguments, text, args, explicit, headerText, url):
182
+ return '[' + markdownEscape(text) + '](' + argsURL(arguments, args, explicit, headerText, url) + ')'
183
+ endfunction
184
+
185
+
186
+ # $function: argsHelp
187
+ # $group: args.mds
188
+ # $doc: Output the [arguments model's](includeModel.html#var.vName='ArgsArguments') help
189
+ # $arg arguments: The [arguments model](includeModel.html#var.vName='ArgsArguments')
190
+ function argsHelp(arguments):
191
+ # Create the help data
192
+ helpData = arrayNew()
193
+ anyDefault = false
194
+ anyExplicit = false
195
+ anyDescription = false
196
+ for argument in arguments:
197
+ type = objectGet(argument, 'type', 'string')
198
+ default = objectGet(argument, 'default')
199
+ explicit = objectGet(argument, 'explicit')
200
+ description = objectGet(argument, 'description')
201
+
202
+ # Add the help data row
203
+ arrayPush(helpData, objectNew( \
204
+ 'Variable', argsGlobalName(argument), \
205
+ 'Type', type, \
206
+ 'Default', argsFormatValue(default, type), \
207
+ 'Explicit', if(explicit, 'Yes', ''), \
208
+ 'Description', if(description != null, description, '') \
209
+ ))
210
+
211
+ # Update the "any" field bools
212
+ anyDefault = anyDefault || (default != null)
213
+ anyExplicit = anyExplicit || explicit
214
+ anyDescription = anyDescription || (description != null)
215
+ endfor
216
+
217
+ # Render the help table
218
+ helpFields = arrayNew('Variable', 'Type')
219
+ if anyDefault:
220
+ arrayPush(helpFields, 'Default')
221
+ endif
222
+ if anyExplicit:
223
+ arrayPush(helpFields, 'Explicit')
224
+ endif
225
+ if anyDescription:
226
+ arrayPush(helpFields, 'Description')
227
+ endif
228
+ dataTable(helpData, objectNew('fields', helpFields))
229
+ endfunction
230
+
231
+
232
+ # Helper function to compute an argument's global name
233
+ function argsGlobalName(argument):
234
+ global = objectGet(argument, 'global')
235
+ if global == null:
236
+ name = objectGet(argument, 'name')
237
+ global = 'v' + stringUpper(stringSlice(name, 0, 1)) + stringSlice(name, 1)
238
+ endif
239
+ return global
240
+ endfunction
241
+
242
+
243
+ # Helper function to format an argument value
244
+ function argsFormatValue(value, type):
245
+ # No value?
246
+ if value == null:
247
+ return ''
248
+ endif
249
+
250
+ # Return the formatted value
251
+ if type == 'bool':
252
+ return if(value, 'true', 'false')
253
+ elif type == 'date':
254
+ return "'" + datetimeISOFormat(value, true) + "'"
255
+ elif type == 'datetime':
256
+ return "'" + datetimeISOFormat(value) + "'"
257
+ elif type == 'float':
258
+ return stringNew(value)
259
+ elif type == 'int':
260
+ return stringNew(value)
261
+ endif
262
+
263
+ # type == 'string'
264
+ return "'" + value + "'"
265
+ endfunction
266
+
267
+
268
+ # Helper function to validate an argument value's type
269
+ function argsValidateValue(value, type, global, warn):
270
+ # No value?
271
+ if value == null:
272
+ return null
273
+ endif
274
+
275
+ # Validate the value's type
276
+ valueType = systemType(value)
277
+ if type == 'bool':
278
+ if valueType == 'number' && (value == 0 || value == 1):
279
+ value = !!value
280
+ elif valueType != 'boolean':
281
+ if warn != false:
282
+ systemLogDebug('MarkdownUp - args.mds: Invalid value ' + jsonStringify(value) + ' for URL argument "' + global + '"')
283
+ endif
284
+ value = null
285
+ endif
286
+ elif type == 'date':
287
+ valueOrig = value
288
+ if valueType == 'string':
289
+ value = datetimeISOParse(value)
290
+ valueType = systemType(value)
291
+ endif
292
+ if valueType != 'datetime' || datetimeHour(value) != 0 || datetimeMinute(value) != 0 || datetimeSecond(value) != 0:
293
+ if warn != false:
294
+ systemLogDebug('MarkdownUp - args.mds: Invalid value ' + jsonStringify(valueOrig) + ' for URL argument "' + global + '"')
295
+ endif
296
+ value = null
297
+ endif
298
+ elif type == 'datetime':
299
+ valueOrig = value
300
+ if valueType == 'string':
301
+ value = datetimeISOParse(value)
302
+ valueType = systemType(value)
303
+ endif
304
+ if valueType != 'datetime':
305
+ if warn != false:
306
+ systemLogDebug('MarkdownUp - args.mds: Invalid value ' + jsonStringify(valueOrig) + ' for URL argument "' + global + '"')
307
+ endif
308
+ value = null
309
+ endif
310
+ elif type == 'float':
311
+ if valueType != 'number':
312
+ if warn != false:
313
+ systemLogDebug('MarkdownUp - args.mds: Invalid value ' + jsonStringify(value) + ' for URL argument "' + global + '"')
314
+ endif
315
+ value = null
316
+ endif
317
+ elif type == 'int':
318
+ if valueType != 'number' || value != mathFloor(value):
319
+ if warn != false:
320
+ systemLogDebug('MarkdownUp - args.mds: Invalid value ' + jsonStringify(value) + ' for URL argument "' + global + '"')
321
+ endif
322
+ value = null
323
+ endif
324
+ else:
325
+ # type == 'string'
326
+ if valueType != 'string':
327
+ if warn != false:
328
+ systemLogDebug('MarkdownUp - args.mds: Invalid value ' + jsonStringify(value) + ' for URL argument "' + global + '"')
329
+ endif
330
+ value = null
331
+ endif
332
+ endif
333
+
334
+ return value
335
+ endfunction
336
+
337
+
338
+ # Helper function to determine if two values are equal
339
+ function argsValuesEqual(value, valueOther, type):
340
+ if type == 'date' || type == 'datetime':
341
+ return (value - valueOther) == 0
342
+ endif
343
+ return value == valueOther
344
+ endfunction
@@ -0,0 +1,79 @@
1
+ # Licensed under the MIT License
2
+ # https://github.com/craigahobbs/markdown-up/blob/main/LICENSE
3
+
4
+
5
+ # Include sentinel
6
+ if systemGlobalGet('formsSentinel'):
7
+ return
8
+ endif
9
+ formsSentinel = true
10
+
11
+
12
+ # $function: formsTextElements
13
+ # $group: forms.mds
14
+ # $doc: Create a text input [element model](https://github.com/craigahobbs/element-model#readme)
15
+ # $arg id: The text input element ID
16
+ # $arg text: The initial text of the text input element
17
+ # $arg size: Optional (default is null). The size, in characters, of the text input element
18
+ # $arg onEnter: Optional (default is null). The text input element on-enter event handler
19
+ # $return: The text input [element model](https://github.com/craigahobbs/element-model#readme)
20
+ function formsTextElements(id, text, size, onEnter):
21
+ return objectNew( \
22
+ 'html', 'input', \
23
+ 'attr', objectNew( \
24
+ 'autocomplete', 'off', \
25
+ 'id', id, \
26
+ 'style', 'font-size: inherit; border: thin solid black; padding: 0.4em;', \
27
+ 'type', 'text', \
28
+ 'value', text, \
29
+ 'size', size \
30
+ ), \
31
+ 'callback', if(onEnter != null, objectNew('keyup', systemPartial(formsTextOnKeyup, onEnter))) \
32
+ )
33
+ endfunction
34
+
35
+
36
+ async function formsTextOnKeyup(onEnter, keyCode):
37
+ if keyCode == 13:
38
+ onEnter()
39
+ endif
40
+ endfunction
41
+
42
+
43
+ # $function: formsLinkButtonElements
44
+ # $group: forms.mds
45
+ # $doc: Create a link button [element model](https://github.com/craigahobbs/element-model#readme)
46
+ # $arg text: The link button's text
47
+ # $arg onClick: The link button's click event handler
48
+ # $return: The link button [element model](https://github.com/craigahobbs/element-model#readme)
49
+ function formsLinkButtonElements(text, onClick):
50
+ return objectNew( \
51
+ 'html', 'a', \
52
+ 'attr', objectNew('style', 'cursor: pointer; user-select: none;'), \
53
+ 'elem', objectNew('text', text), \
54
+ 'callback', objectNew('click', onClick) \
55
+ )
56
+ endfunction
57
+
58
+
59
+ # $function: formsLinkElements
60
+ # $group: forms.mds
61
+ # $doc: Create a link [element model](https://github.com/craigahobbs/element-model#readme)
62
+ # $arg text: The link's text
63
+ # $arg url: The link's URL. If null, the link is rendered as text.
64
+ # $return: The link [element model](https://github.com/craigahobbs/element-model#readme)
65
+ function formsLinkElements(text, url):
66
+ if url == null:
67
+ return objectNew( \
68
+ 'html', 'span', \
69
+ 'attr', objectNew('style', 'user-select: none;'), \
70
+ 'elem', objectNew('text', text) \
71
+ )
72
+ endif
73
+
74
+ return objectNew( \
75
+ 'html', 'a', \
76
+ 'attr', objectNew('href', documentURL(url)), \
77
+ 'elem', objectNew('text', text) \
78
+ )
79
+ endfunction