bare-script 3.8.6 → 3.8.8

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.
@@ -2,6 +2,7 @@
2
2
  # https://github.com/craigahobbs/bare-script/blob/main/LICENSE
3
3
 
4
4
  include <args.bare>
5
+ include <schemaDoc.bare>
5
6
 
6
7
 
7
8
  # $function: baredocMain
@@ -22,7 +23,7 @@ async function baredocMain(url, title, menuLinks, groupURLs):
22
23
  # Render library JSON documentation page?
23
24
  if objectGet(args, 'doc'):
24
25
  documentSetTitle('Library')
25
- elementModelRender(schemaElements(baredocTypes, 'Library'))
26
+ markdownPrint(schemaDocMarkdown(baredocTypes, 'Library'))
26
27
  return
27
28
  endif
28
29
 
@@ -195,13 +196,14 @@ async function baredocSinglePage(args, title, menuLinks, groupURLs, groups):
195
196
  # Render the library function index
196
197
  for groupName in arraySort(objectKeys(groups)):
197
198
  markdownPrint('', '---', '')
198
- baredocGroupPage(args, title, groupURLs, groups, groupName, true)
199
+ baredocGroupPage(args, title, groupURLs, groups, groupName)
199
200
  endfor
200
201
  endfunction
201
202
 
202
203
 
203
204
  # Render a library documentation group page
204
205
  async function baredocGroupPage(args, title, groupURLs, groups, groupName):
206
+ publish = objectGet(args, 'publish')
205
207
  single = objectGet(args, 'single')
206
208
  baseHeader = if(single, '##', '#')
207
209
 
@@ -221,7 +223,7 @@ async function baredocGroupPage(args, title, groupURLs, groups, groupName):
221
223
  markdownPrint(argsLink(baredocArguments, 'Index', {'group': null}), '')
222
224
  endif
223
225
  markdownPrint(baseHeader + ' ' + markdownEscape(groupName))
224
- if single:
226
+ if single && !publish:
225
227
  markdownPrint('', argsLink(baredocArguments, 'Back to top', null, false, '_top'))
226
228
  endif
227
229
 
@@ -0,0 +1,600 @@
1
+ # Licensed under the MIT License
2
+ # https://github.com/craigahobbs/bare-script/blob/main/LICENSE
3
+
4
+ include <dataTable.bare>
5
+
6
+
7
+ # $function: schemaDocMarkdown
8
+ # $group: schemaDoc.bare
9
+ # $doc: Generate the Schema Markdown user type documentation as an array of Markdown text lines
10
+ # $arg types: The [type model](https://craigahobbs.github.io/schema-markdown-doc/doc/#var.vName='Types')
11
+ # $arg typeName: The type name
12
+ # $arg options: Optional (default is null). The options object with optional members:
13
+ # $arg options: - **actionURLs** - The [action URLs](https://craigahobbs.github.io/schema-markdown-doc/doc/#var.vName='ActionURL') override
14
+ # $arg options: - **actionCustom** - If true, the action has a custom response (default is false)
15
+ # $arg options: - **headerPrefix** - The top-level header prefix string (default is "#")
16
+ # $arg options: - **hideReferenced** - If true, referenced types are not rendered (default is false)
17
+ # $return: The array of Markdown text lines
18
+ function schemaDocMarkdown(types, typeName, options):
19
+ headerPrefix = if(options != null, objectGet(options, 'headerPrefix', '#'), '#')
20
+ hideReferenced = if(options != null, objectGet(options, 'hideReferenced', false), false)
21
+
22
+ # Get the user type
23
+ if !objectHas(types, typeName):
24
+ systemLogDebug('schemaDoc.bare: Unknown type "' + typeName + '"')
25
+ return null
26
+ endif
27
+ userType = objectGet(types, typeName)
28
+ action = objectGet(userType, 'action')
29
+
30
+ # Compute the referenced types
31
+ referencedTypes = schemaDocGetReferencedTypes(types, typeName)
32
+ if action != null:
33
+ typesFilter = [ \
34
+ typeName, objectGet(action, 'path'), objectGet(action, 'query'), objectGet(action, 'input'), \
35
+ objectGet(action, 'output'), objectGet(action, 'errors') \
36
+ ]
37
+ else:
38
+ typesFilter = [typeName]
39
+ endif
40
+
41
+ # Filter and sort referenced types
42
+ filteredTypeNames = []
43
+ for refTypeName in arraySort(objectKeys(referencedTypes)):
44
+ if arrayIndexOf(typesFilter, refTypeName) == -1:
45
+ arrayPush(filteredTypeNames, refTypeName)
46
+ endif
47
+ endfor
48
+
49
+ # The user type documentation
50
+ lines = []
51
+ arrayExtend(lines, schemaDocUserTypeMarkdown(types, typeName, options, headerPrefix))
52
+
53
+ # Referenced type documentation
54
+ if filteredTypeNames && !hideReferenced:
55
+ arrayPush(lines, '')
56
+ arrayPush(lines, '---')
57
+ arrayPush(lines, '')
58
+ arrayPush(lines, headerPrefix + '# Referenced Types')
59
+ for refTypeName in filteredTypeNames:
60
+ arrayPush(lines, '')
61
+ arrayExtend(lines, schemaDocUserTypeMarkdown(types, refTypeName, options, headerPrefix + '##'))
62
+ endfor
63
+ endif
64
+
65
+ return lines
66
+ endfunction
67
+
68
+
69
+ # Helper function to generate user type documentation
70
+ function schemaDocUserTypeMarkdown(types, typeName, options, headerPrefix, title, introLines):
71
+ userType = objectGet(types, typeName)
72
+ lines = []
73
+
74
+ # Title
75
+ arrayPush(lines, headerPrefix + ' ' + if(title != null, title, schemaDocTypeTitle(userType)))
76
+
77
+ # Struct?
78
+ if objectHas(userType, 'struct'):
79
+ struct = objectGet(userType, 'struct')
80
+
81
+ # Bases
82
+ if objectHas(struct, 'bases'):
83
+ bases = objectGet(struct, 'bases')
84
+ basesLinks = []
85
+ for base in bases:
86
+ arrayPush(basesLinks, '[' + markdownEscape(base) + '](#' + schemaDocTypeHref(objectGet(types, base)) + ')')
87
+ endfor
88
+ arrayPush(lines, '')
89
+ arrayPush(lines, 'Bases: ' + arrayJoin(basesLinks, ', '))
90
+ endif
91
+
92
+ # Documentation
93
+ if objectHas(struct, 'doc'):
94
+ arrayPush(lines, '')
95
+ arrayExtend(lines, objectGet(struct, 'doc'))
96
+ endif
97
+
98
+ # Members table
99
+ members = schemaDocGetStructMembers(types, struct)
100
+ if !members:
101
+ arrayPush(lines, '')
102
+ arrayPush(lines, 'The struct is empty.')
103
+ else:
104
+ # Any attributes or documentation?
105
+ hasAttr = false
106
+ hasDoc = false
107
+ for member in members:
108
+ hasAttr = hasAttr || schemaDocAttrText(member) != null
109
+ hasDoc = hasDoc || objectGet(member, 'doc')
110
+ endfor
111
+
112
+ # Members table data
113
+ tableData = []
114
+ for member in members:
115
+ memberName = objectGet(member, 'name')
116
+ row = { \
117
+ 'Name': memberName, \
118
+ 'Type': schemaDocTypeText(types, objectGet(member, 'type')) \
119
+ }
120
+ if hasAttr:
121
+ objectSet(row, 'Attributes', schemaDocAttrText(member) || '')
122
+ endif
123
+ if hasDoc:
124
+ doc = objectGet(member, 'doc')
125
+ objectSet(row, 'Description', if(doc != null, arrayJoin(doc, ' '), ''))
126
+ endif
127
+ arrayPush(tableData, row)
128
+ endfor
129
+
130
+ # Members table
131
+ tableFields = ['Name', 'Type']
132
+ if hasAttr:
133
+ arrayPush(tableFields, 'Attributes')
134
+ endif
135
+ if hasDoc:
136
+ arrayPush(tableFields, 'Description')
137
+ endif
138
+ tableModel = {'fields': tableFields}
139
+ arrayPush(lines, '')
140
+ arrayExtend(lines, dataTableMarkdown(tableData, tableModel))
141
+ endif
142
+
143
+ # Enum?
144
+ elif objectHas(userType, 'enum'):
145
+ enum = objectGet(userType, 'enum')
146
+
147
+ # Bases
148
+ if objectHas(enum, 'bases'):
149
+ bases = objectGet(enum, 'bases')
150
+ basesLinks = []
151
+ for base in bases:
152
+ arrayPush(basesLinks, '[' + markdownEscape(base) + '](#' + schemaDocTypeHref(objectGet(types, base)) + ')')
153
+ endfor
154
+ arrayPush(lines, '')
155
+ arrayPush(lines, 'Bases: ' + arrayJoin(basesLinks, ', '))
156
+ endif
157
+
158
+ # Documentation
159
+ if objectHas(enum, 'doc'):
160
+ arrayPush(lines, '')
161
+ arrayExtend(lines, objectGet(enum, 'doc'))
162
+ endif
163
+
164
+ # Intro markdown
165
+ if systemType(introLines) == 'array':
166
+ arrayPush(lines, '')
167
+ arrayExtend(lines, introLines)
168
+ endif
169
+
170
+ # Values table
171
+ values = if(objectHas(enum, 'values'), schemaDocGetEnumValues(types, enum), null)
172
+ if values == null || !values:
173
+ arrayPush(lines, '')
174
+ arrayPush(lines, 'The enum is empty.')
175
+ else:
176
+ # Compute value documentation
177
+ hasDoc = false
178
+ for value in values:
179
+ hasDoc = hasDoc || objectGet(value, 'doc')
180
+ endfor
181
+
182
+ # Values table data
183
+ tableData = []
184
+ for value in values:
185
+ valueName = objectGet(value, 'name')
186
+ row = {'Value': valueName}
187
+ if hasDoc:
188
+ doc = objectGet(value, 'doc')
189
+ objectSet(row, 'Description', if(doc != null, arrayJoin(doc, ' '), ''))
190
+ endif
191
+ arrayPush(tableData, row)
192
+ endfor
193
+
194
+ # Values table
195
+ tableFields = ['Value']
196
+ if hasDoc:
197
+ arrayPush(tableFields, 'Description')
198
+ endif
199
+ tableModel = {'fields': tableFields}
200
+ arrayPush(lines, '')
201
+ arrayExtend(lines, dataTableMarkdown(tableData, tableModel))
202
+ endif
203
+
204
+ # Typedef?
205
+ elif objectHas(userType, 'typedef'):
206
+ typedef = objectGet(userType, 'typedef')
207
+
208
+ # Documentation
209
+ if objectHas(typedef, 'doc'):
210
+ arrayPush(lines, '')
211
+ arrayExtend(lines, objectGet(typedef, 'doc'))
212
+ endif
213
+
214
+ # Type table data
215
+ attrText = if(objectHas(typedef, 'attr'), schemaDocAttrText(typedef))
216
+ tableData = [{'Type': schemaDocTypeText(types, objectGet(typedef, 'type'))}]
217
+ if attrText != null:
218
+ objectSet(arrayGet(tableData, 0), 'Attributes', attrText)
219
+ endif
220
+
221
+ # Type table
222
+ tableFields = ['Type']
223
+ if attrText != null:
224
+ arrayPush(tableFields, 'Attributes')
225
+ endif
226
+ tableModel = {'fields': tableFields}
227
+ arrayPush(lines, '')
228
+ arrayExtend(lines, dataTableMarkdown(tableData, tableModel))
229
+
230
+ # Action?
231
+ elif objectHas(userType, 'action'):
232
+ action = objectGet(userType, 'action')
233
+
234
+ # Documentation
235
+ if objectHas(action, 'doc'):
236
+ arrayPush(lines, '')
237
+ arrayExtend(lines, objectGet(action, 'doc'))
238
+ endif
239
+
240
+ # URLs
241
+ actionURLs = if(options != null && objectHas(options, 'actionURLs'), objectGet(options, 'actionURLs'), objectGet(action, 'urls'))
242
+ if actionURLs:
243
+ arrayPush(lines, '')
244
+ arrayPush(lines, '**Note:** The request is exposed at the following ' + if(arrayLength(actionURLs) == 1, 'URL:', 'URLs:'))
245
+ for actionURL in actionURLs:
246
+ method = objectGet(actionURL, 'method')
247
+ path = objectGet(actionURL, 'path', '/' + typeName)
248
+ arrayPush(lines, '')
249
+ arrayPush(lines, '- [' + if(method, method + ' ', '') + markdownEscape(path) + '](' + urlEncode(path) + ')')
250
+ endfor
251
+ endif
252
+
253
+ # Path struct
254
+ if objectHas(action, 'path'):
255
+ arrayPush(lines, '')
256
+ arrayExtend( \
257
+ lines, \
258
+ schemaDocUserTypeMarkdown(types, objectGet(action, 'path'), options, headerPrefix + '#', 'Path Parameters') \
259
+ )
260
+ endif
261
+
262
+ # Query struct
263
+ if objectHas(action, 'query'):
264
+ arrayPush(lines, '')
265
+ arrayExtend( \
266
+ lines, \
267
+ schemaDocUserTypeMarkdown(types, objectGet(action, 'query'), options, headerPrefix + '#', 'Query Parameters') \
268
+ )
269
+ endif
270
+
271
+ # Input struct
272
+ if objectHas(action, 'input'):
273
+ arrayPush(lines, '')
274
+ arrayExtend( \
275
+ lines, \
276
+ schemaDocUserTypeMarkdown(types, objectGet(action, 'input'), options, headerPrefix + '#', 'Input Parameters') \
277
+ )
278
+ endif
279
+
280
+ # Output struct
281
+ actionCustom = options != null && objectGet(options, 'actionCustom')
282
+ if objectHas(action, 'output') && !actionCustom:
283
+ arrayPush(lines, '')
284
+ arrayExtend( \
285
+ lines, \
286
+ schemaDocUserTypeMarkdown(types, objectGet(action, 'output'), options, headerPrefix + '#', 'Output Parameters') \
287
+ )
288
+ endif
289
+
290
+ # Error enum
291
+ if !actionCustom:
292
+ # Add "UnexpectedError" to the action's errors
293
+ if objectHas(action, 'errors'):
294
+ actionErrorTypeName = objectGet(action, 'errors')
295
+ actionErrorTypes = schemaDocGetReferencedTypes(types, actionErrorTypeName)
296
+ actionErrorEnum = objectCopy(objectGet(objectGet(types, actionErrorTypeName), 'enum'))
297
+ if objectHas(actionErrorEnum, 'values'):
298
+ objectSet(actionErrorEnum, 'values', arrayCopy(objectGet(actionErrorEnum, 'values')))
299
+ else:
300
+ objectSet(actionErrorEnum, 'values', [])
301
+ endif
302
+ else:
303
+ actionErrorTypeName = typeName + '_errors'
304
+ actionErrorTypes = {}
305
+ actionErrorEnum = {'name': actionErrorTypeName, 'values': []}
306
+ endif
307
+
308
+ # Add UnexpectedError if not already present
309
+ values = objectGet(actionErrorEnum, 'values')
310
+ hasUnexpectedError = false
311
+ for value in values:
312
+ if objectGet(value, 'name') == 'UnexpectedError':
313
+ hasUnexpectedError = true
314
+ break
315
+ endif
316
+ endfor
317
+ if !hasUnexpectedError:
318
+ arrayPush(values, {'name': 'UnexpectedError'})
319
+ endif
320
+ objectSet(actionErrorTypes, actionErrorTypeName, {'enum': actionErrorEnum})
321
+ arrayPush(lines, '')
322
+ arrayExtend( \
323
+ lines, \
324
+ schemaDocUserTypeMarkdown( \
325
+ actionErrorTypes, actionErrorTypeName, options, headerPrefix + '#', 'Error Codes', schemaDocActionErrorIntroLines \
326
+ ) \
327
+ )
328
+ endif
329
+ endif
330
+
331
+ return lines
332
+ endfunction
333
+
334
+
335
+ # Action error enum introduction text
336
+ schemaDocActionErrorIntroLines = [ \
337
+ 'If an application error occurs, the response is of the form:', \
338
+ '', \
339
+ '```json', \
340
+ '{', \
341
+ ' "error": "<error>",', \
342
+ ' "message": "<message>"', \
343
+ '}', \
344
+ '```', \
345
+ '', \
346
+ '`message` is optional. `error` is one of the following values:' \
347
+ ]
348
+
349
+
350
+ # Helper function to get a type's title
351
+ function schemaDocTypeTitle(userType):
352
+ if objectHas(userType, 'struct'):
353
+ struct = objectGet(userType, 'struct')
354
+ return if(objectGet(struct, 'union'), 'union ' + objectGet(struct, 'name'), 'struct ' + objectGet(struct, 'name'))
355
+ elif objectHas(userType, 'enum'):
356
+ return 'enum ' + objectGet(objectGet(userType, 'enum'), 'name')
357
+ elif objectHas(userType, 'typedef'):
358
+ return 'typedef ' + objectGet(objectGet(userType, 'typedef'), 'name')
359
+ endif
360
+ # objectHas(userType, 'action'):
361
+ return 'action ' + objectGet(objectGet(userType, 'action'), 'name')
362
+ endfunction
363
+
364
+
365
+ # Helper function to get a type href
366
+ function schemaDocTypeHref(userType):
367
+ return markdownHeaderId(schemaDocTypeTitle(userType))
368
+ endfunction
369
+
370
+
371
+ # Helper function to get a type's text
372
+ function schemaDocTypeText(types, type):
373
+ if objectHas(type, 'array'):
374
+ return schemaDocTypeText(types, objectGet(objectGet(type, 'array'), 'type')) + ' []'
375
+ elif objectHas(type, 'dict'):
376
+ dict = objectGet(type, 'dict')
377
+ keyType = objectGet(dict, 'keyType')
378
+ if keyType != null && !objectHas(keyType, 'builtin'):
379
+ return schemaDocTypeText(types, keyType) + ' : ' + schemaDocTypeText(types, objectGet(dict, 'type')) + ' {}'
380
+ endif
381
+ return schemaDocTypeText(types, objectGet(dict, 'type')) + ' {}'
382
+ elif objectHas(type, 'user'):
383
+ userName = objectGet(type, 'user')
384
+ userType = objectGet(types, userName)
385
+ return '[' + markdownEscape(userName) + '](#' + schemaDocTypeHref(userType) + ')'
386
+ endif
387
+ # objectHas(type, 'builtin'):
388
+ return objectGet(type, 'builtin')
389
+ endfunction
390
+
391
+
392
+ # Helper function to get a type's attribute text
393
+ function schemaDocAttrText(member):
394
+ type = objectGet(member, 'type')
395
+ attr = objectGet(member, 'attr')
396
+ optional = objectGet(member, 'optional')
397
+
398
+ # Collect attribute parts
399
+ parts = []
400
+ typeName = if(objectHas(type, 'array'), 'array', if(objectHas(type, 'dict'), 'dict', 'value'))
401
+ schemaDocAttrParts(parts, typeName, attr, optional)
402
+
403
+ # Array or dict key/value attributes
404
+ if objectHas(type, 'array'):
405
+ array = objectGet(type, 'array')
406
+ if objectHas(array, 'attr'):
407
+ schemaDocAttrParts(parts, 'value', objectGet(array, 'attr'), false)
408
+ endif
409
+ elif objectHas(type, 'dict'):
410
+ dict = objectGet(type, 'dict')
411
+ if objectHas(dict, 'keyAttr'):
412
+ schemaDocAttrParts(parts, 'key', objectGet(dict, 'keyAttr'), false)
413
+ endif
414
+ if objectHas(dict, 'attr'):
415
+ schemaDocAttrParts(parts, 'value', objectGet(dict, 'attr'), false)
416
+ endif
417
+ endif
418
+
419
+ return if(parts, arrayJoin(parts, '<br>'), null)
420
+ endfunction
421
+
422
+
423
+ # Helper function to get a type's attribute parts
424
+ function schemaDocAttrParts(parts, noun, attr, optional):
425
+ if optional:
426
+ arrayPush(parts, 'optional')
427
+ endif
428
+
429
+ if attr != null:
430
+ if objectHas(attr, 'nullable'):
431
+ arrayPush(parts, 'nullable')
432
+ endif
433
+ if objectHas(attr, 'gt'):
434
+ arrayPush(parts, noun + ' > ' + objectGet(attr, 'gt'))
435
+ endif
436
+ if objectHas(attr, 'gte'):
437
+ arrayPush(parts, noun + ' >= ' + objectGet(attr, 'gte'))
438
+ endif
439
+ if objectHas(attr, 'lt'):
440
+ arrayPush(parts, noun + ' < '+ objectGet(attr, 'lt'))
441
+ endif
442
+ if objectHas(attr, 'lte'):
443
+ arrayPush(parts, noun + ' <= ' + objectGet(attr, 'lte'))
444
+ endif
445
+ if objectHas(attr, 'eq'):
446
+ arrayPush(parts, noun + ' == ' + objectGet(attr, 'eq'))
447
+ endif
448
+ if objectHas(attr, 'lenGT'):
449
+ arrayPush(parts, 'len(' + noun + ')' + ' > ' + objectGet(attr, 'lenGT'))
450
+ endif
451
+ if objectHas(attr, 'lenGTE'):
452
+ arrayPush(parts, 'len(' + noun + ')' + ' >= ' + objectGet(attr, 'lenGTE'))
453
+ endif
454
+ if objectHas(attr, 'lenLT'):
455
+ arrayPush(parts, 'len(' + noun + ')' + ' < ' + objectGet(attr, 'lenLT'))
456
+ endif
457
+ if objectHas(attr, 'lenLTE'):
458
+ arrayPush(parts, 'len(' + noun + ')' + ' <= ' + objectGet(attr, 'lenLTE'))
459
+ endif
460
+ if objectHas(attr, 'lenEq'):
461
+ arrayPush(parts, 'len(' + noun + ')' + ' == ' + objectGet(attr, 'lenEq'))
462
+ endif
463
+ endif
464
+ endfunction
465
+
466
+
467
+ # Helper function to get struct members (with base members)
468
+ function schemaDocGetStructMembers(types, struct):
469
+ members = []
470
+
471
+ # Add base members first
472
+ if objectHas(struct, 'bases'):
473
+ for baseName in objectGet(struct, 'bases'):
474
+ if objectHas(types, baseName):
475
+ baseType = objectGet(types, baseName)
476
+ if objectHas(baseType, 'struct'):
477
+ baseMembers = schemaDocGetStructMembers(types, objectGet(baseType, 'struct'))
478
+ arrayExtend(members, baseMembers)
479
+ endif
480
+ endif
481
+ endfor
482
+ endif
483
+
484
+ # Add this struct's members
485
+ if objectHas(struct, 'members'):
486
+ arrayExtend(members, objectGet(struct, 'members'))
487
+ endif
488
+
489
+ return members
490
+ endfunction
491
+
492
+
493
+ # Helper function to get enum values (with base values)
494
+ function schemaDocGetEnumValues(types, enum):
495
+ values = []
496
+
497
+ # Add base values first
498
+ if objectHas(enum, 'bases'):
499
+ for baseName in objectGet(enum, 'bases'):
500
+ if objectHas(types, baseName):
501
+ baseType = objectGet(types, baseName)
502
+ if objectHas(baseType, 'enum'):
503
+ baseValues = schemaDocGetEnumValues(types, objectGet(baseType, 'enum'))
504
+ if baseValues != null:
505
+ arrayExtend(values, baseValues)
506
+ endif
507
+ endif
508
+ endif
509
+ endfor
510
+ endif
511
+
512
+ # Add this enum's values
513
+ if objectHas(enum, 'values'):
514
+ arrayExtend(values, objectGet(enum, 'values'))
515
+ endif
516
+
517
+ return values
518
+ endfunction
519
+
520
+
521
+ # Helper function to get a user type's referenced type model
522
+ function schemaDocGetReferencedTypes(types, typeName, referencedTypes):
523
+ referencedTypes = if(referencedTypes, referencedTypes, {})
524
+ return schemaDocGetReferencedTypesHelper(types, {'user': typeName}, referencedTypes)
525
+ endfunction
526
+
527
+
528
+ function schemaDocGetReferencedTypesHelper(types, type, referencedTypes):
529
+ # Array?
530
+ if objectHas(type, 'array'):
531
+ array = objectGet(type, 'array')
532
+ schemaDocGetReferencedTypesHelper(types, objectGet(array, 'type'), referencedTypes)
533
+
534
+ # Dict?
535
+ elif objectHas(type, 'dict'):
536
+ dict = objectGet(type, 'dict')
537
+ schemaDocGetReferencedTypesHelper(types, objectGet(dict, 'type'), referencedTypes)
538
+ if objectHas(dict, 'keyType'):
539
+ schemaDocGetReferencedTypesHelper(types, objectGet(dict, 'keyType'), referencedTypes)
540
+ endif
541
+
542
+ # User type?
543
+ elif objectHas(type, 'user'):
544
+ typeName = objectGet(type, 'user')
545
+
546
+ # Already encountered?
547
+ if !objectHas(referencedTypes, typeName):
548
+ userType = objectGet(types, typeName)
549
+ objectSet(referencedTypes, typeName, userType)
550
+
551
+ # Struct?
552
+ if objectHas(userType, 'struct'):
553
+ struct = objectGet(userType, 'struct')
554
+ if objectHas(struct, 'bases'):
555
+ for base in objectGet(struct, 'bases'):
556
+ schemaDocGetReferencedTypesHelper(types, {'user': base}, referencedTypes)
557
+ endfor
558
+ endif
559
+ for member in schemaDocGetStructMembers(types, struct):
560
+ schemaDocGetReferencedTypesHelper(types, objectGet(member, 'type'), referencedTypes)
561
+ endfor
562
+
563
+ # Enum?
564
+ elif objectHas(userType, 'enum'):
565
+ enum = objectGet(userType, 'enum')
566
+ if objectHas(enum, 'bases'):
567
+ for base in objectGet(enum, 'bases'):
568
+ schemaDocGetReferencedTypesHelper(types, {'user': base}, referencedTypes)
569
+ endfor
570
+ endif
571
+
572
+ # Typedef?
573
+ elif objectHas(userType, 'typedef'):
574
+ typedef = objectGet(userType, 'typedef')
575
+ schemaDocGetReferencedTypesHelper(types, objectGet(typedef, 'type'), referencedTypes)
576
+
577
+ # Action?
578
+ elif objectHas(userType, 'action'):
579
+ action = objectGet(userType, 'action')
580
+ if objectHas(action, 'path'):
581
+ schemaDocGetReferencedTypesHelper(types, {'user': objectGet(action, 'path')}, referencedTypes)
582
+ endif
583
+ if objectHas(action, 'query'):
584
+ schemaDocGetReferencedTypesHelper(types, {'user': objectGet(action, 'query')}, referencedTypes)
585
+ endif
586
+ if objectHas(action, 'input'):
587
+ schemaDocGetReferencedTypesHelper(types, {'user': objectGet(action, 'input')}, referencedTypes)
588
+ endif
589
+ if objectHas(action, 'output'):
590
+ schemaDocGetReferencedTypesHelper(types, {'user': objectGet(action, 'output')}, referencedTypes)
591
+ endif
592
+ if objectHas(action, 'errors'):
593
+ schemaDocGetReferencedTypesHelper(types, {'user': objectGet(action, 'errors')}, referencedTypes)
594
+ endif
595
+ endif
596
+ endif
597
+ endif
598
+
599
+ return referencedTypes
600
+ endfunction
@@ -0,0 +1,149 @@
1
+ # Licensed under the MIT License
2
+ # https://github.com/craigahobbs/bare-script/blob/main/LICENSE
3
+
4
+ include <args.bare>
5
+ include <schemaDoc.bare>
6
+
7
+
8
+ # $function: schemaDocAppMain
9
+ # $group: schemaDocApp.bare
10
+ # $doc: The Schema Markdown documentation viewer main entry point
11
+ # $arg url: Optional (default is null). The Schema Markdown text or JSON resource URL. If null, the Schema Markdown type model is displayed.
12
+ # $arg title: Optional. The schema title.
13
+ # $arg hideNoGroup: Optional (default is false). If true, hide types with no group.
14
+ async function schemaDocAppMain(url, title, hideNoGroup):
15
+ # Parse arguments
16
+ args = argsParse(schemaDocAppArguments)
17
+ name = objectGet(args, 'name')
18
+ url = objectGet(args, 'url', url)
19
+ title = if(title != null && !objectHas(args, 'url'), title, url)
20
+
21
+ # If no URL was provided, use the Schema Markdown type model schema
22
+ if url == null || url == '':
23
+ types = schemaTypeModel()
24
+ title = 'The Schema Markdown Type Model'
25
+ else:
26
+ # Fetch the Schema Markdown resource
27
+ types = null
28
+ schemaText = systemFetch(url)
29
+ if schemaText != null:
30
+ if stringEndsWith(url, '.json'):
31
+ schemaJSON = jsonParse(schemaText)
32
+ if schemaJSON != null:
33
+ types = schemaValidateTypeModel(schemaJSON)
34
+ endif
35
+ else:
36
+ types = schemaParse(schemaText)
37
+ endif
38
+ endif
39
+
40
+ # Error?
41
+ if types == null:
42
+ markdownPrint('**Error:** Failed to fetch Schema Markdown resource "' + url + '"')
43
+ return
44
+ endif
45
+ endif
46
+
47
+ # Render the page
48
+ if name != null:
49
+ schemaDocAppTypePage(types, title, name)
50
+ else:
51
+ schemaDocAppIndexPage(args, types, title, hideNoGroup)
52
+ endif
53
+ endfunction
54
+
55
+
56
+ # The Schema Markdown documentation viewer arguments
57
+ schemaDocAppArguments = argsValidate([ \
58
+ {'name': 'name'}, \
59
+ {'name': 'publish', 'type': 'bool', 'default': false}, \
60
+ {'name': 'single', 'type': 'bool', 'default': false}, \
61
+ {'name': 'url', 'global': 'vURL'} \
62
+ ])
63
+
64
+
65
+ # Render the Schema Markdown documentation viewer index page
66
+ function schemaDocAppIndexPage(args, types, title, hideNoGroup):
67
+ publish = objectGet(args, 'publish')
68
+ single = objectGet(args, 'single')
69
+
70
+ # Set the page title
71
+ documentSetTitle(title)
72
+ markdownPrint('# ' + markdownEscape(title))
73
+
74
+ # Render the single page toggle
75
+ if !publish:
76
+ markdownPrint('', argsLink(schemaDocAppArguments, if(single, 'Multi Page', 'Single Page'), {'single': !single}))
77
+ endif
78
+
79
+ # Group the types
80
+ groups = {}
81
+ typeNames = arraySort(objectKeys(types))
82
+ typeGroups = {'action': 'Actions', 'enum': 'Enums', 'struct': 'Structs', 'typedef': 'Typedefs'}
83
+ for typeName in typeNames:
84
+ type = objectGet(types, typeName)
85
+ group = objectGet(objectGet(type, arrayGet(objectKeys(type), 0)), 'docGroup')
86
+
87
+ # No group? Use the type's default group.
88
+ if group == null:
89
+ if hideNoGroup:
90
+ continue
91
+ endif
92
+ group = objectGet(typeGroups, arrayGet(objectKeys(type), 0))
93
+ endif
94
+
95
+ # Add the type to the group
96
+ if !objectHas(groups, group):
97
+ objectSet(groups, group, [])
98
+ endif
99
+ arrayPush(objectGet(groups, group), type)
100
+ endfor
101
+ groupNames = arraySort(objectKeys(groups))
102
+
103
+ # The table of contents
104
+ if single:
105
+ markdownPrint('', '## Table of Contents', '')
106
+ for groupName in groupNames:
107
+ markdownPrint('- ' + argsLink(schemaDocAppArguments, groupName, null, false, groupName))
108
+ endfor
109
+ endif
110
+
111
+ # Render the index groups
112
+ for groupName in groupNames:
113
+ if single:
114
+ markdownPrint('', '---')
115
+ endif
116
+ markdownPrint('', '## ' + markdownEscape(groupName))
117
+ if single && !publish:
118
+ markdownPrint('', argsLink(schemaDocAppArguments, 'Back to top', null, false, '_top'))
119
+ endif
120
+
121
+ # Render the group type links
122
+ groupTypes = objectGet(groups, groupName)
123
+ for groupType in groupTypes:
124
+ groupTypeName = objectGet(objectGet(groupType, arrayGet(objectKeys(groupType), 0)), 'name')
125
+ if single:
126
+ markdownPrint('', schemaDocMarkdown(types, groupTypeName, {'headerPrefix': '###', 'hideReferenced': true}))
127
+ else:
128
+ markdownPrint('', argsLink(schemaDocAppArguments, groupTypeName, {'name': groupTypeName}, false, '_top'))
129
+ endif
130
+ endfor
131
+ endfor
132
+ endfunction
133
+
134
+
135
+ # Render the Schema Markdown documentation viewer type page
136
+ function schemaDocAppTypePage(types, title, typeName):
137
+ # Set the page title
138
+ documentSetTitle(title + ' - ' + typeName)
139
+ markdownPrint(argsLink(schemaDocAppArguments, 'Index', {'name': null}))
140
+
141
+ # Type exist?
142
+ if !objectHas(types, typeName):
143
+ markdownPrint('', '**Error:** Unknown type "' + typeName + '"')
144
+ return
145
+ endif
146
+
147
+ # Render the type's documentation
148
+ markdownPrint(schemaDocMarkdown(types, typeName))
149
+ endfunction
package/lib/runtime.js CHANGED
@@ -74,7 +74,8 @@ function executeScriptHelper(script, statements, options, locals) {
74
74
  // Jump?
75
75
  } else if (statementKey === 'jump') {
76
76
  // Evaluate the expression (if any)
77
- if (!('expr' in statement.jump) || evaluateExpression(statement.jump.expr, options, locals, false, script, statement)) {
77
+ if (!('expr' in statement.jump) ||
78
+ valueBoolean(evaluateExpression(statement.jump.expr, options, locals, false, script, statement))) {
78
79
  // Find the label
79
80
  if (labelIndexes !== null && statement.jump.label in labelIndexes) {
80
81
  ixStatement = labelIndexes[statement.jump.label];
@@ -222,7 +223,7 @@ export function evaluateExpression(expr, options = null, locals = null, builtins
222
223
  if (funcName === 'if') {
223
224
  const [valueExpr = null, trueExpr = null, falseExpr = null] = expr.function.args ?? [];
224
225
  const value = (valueExpr !== null ? evaluateExpression(valueExpr, options, locals, builtins, script, statement) : false);
225
- const resultExpr = (value ? trueExpr : falseExpr);
226
+ const resultExpr = (valueBoolean(value) ? trueExpr : falseExpr);
226
227
  return resultExpr !== null ? evaluateExpression(resultExpr, options, locals, builtins, script, statement) : null;
227
228
  }
228
229
 
@@ -80,7 +80,7 @@ async function executeScriptHelperAsync(script, statements, options, locals) {
80
80
  } else if (statementKey === 'jump') {
81
81
  // Evaluate the expression (if any)
82
82
  if (!('expr' in statement.jump) ||
83
- await evaluateExpressionAsync(statement.jump.expr, options, locals, false, script, statement)) {
83
+ valueBoolean(await evaluateExpressionAsync(statement.jump.expr, options, locals, false, script, statement))) {
84
84
  // Find the label
85
85
  if (labelIndexes !== null && statement.jump.label in labelIndexes) {
86
86
  ixStatement = labelIndexes[statement.jump.label];
@@ -289,7 +289,7 @@ export async function evaluateExpressionAsync(expr, options = null, locals = nul
289
289
  if (funcName === 'if') {
290
290
  const [valueExpr, trueExpr = null, falseExpr = null] = expr.function.args;
291
291
  const value = await evaluateExpressionAsync(valueExpr, options, locals, builtins, script, statement);
292
- const resultExpr = (value ? trueExpr : falseExpr);
292
+ const resultExpr = (valueBoolean(value) ? trueExpr : falseExpr);
293
293
  return resultExpr !== null ? evaluateExpressionAsync(resultExpr, options, locals, builtins, script, statement) : null;
294
294
  }
295
295
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "bare-script",
4
- "version": "3.8.6",
4
+ "version": "3.8.8",
5
5
  "description": "BareScript; a lightweight scripting and expression language",
6
6
  "keywords": [
7
7
  "expression",