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.
- package/lib/include/baredoc.bare +5 -3
- package/lib/include/schemaDoc.bare +600 -0
- package/lib/include/schemaDocApp.bare +149 -0
- package/lib/runtime.js +3 -2
- package/lib/runtimeAsync.js +2 -2
- package/package.json +1 -1
package/lib/include/baredoc.bare
CHANGED
|
@@ -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
|
-
|
|
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
|
|
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) ||
|
|
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
|
|
package/lib/runtimeAsync.js
CHANGED
|
@@ -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
|
|