bare-script 3.2.2 → 3.3.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.
@@ -1,235 +1,12 @@
1
1
  # Licensed under the MIT License
2
2
  # https://github.com/craigahobbs/markdown-up/blob/main/LICENSE
3
3
 
4
- include <args.mds>
5
-
6
4
 
7
5
  # Include sentinel
8
6
  if systemGlobalGet('pagerSentinel'):
9
7
  return
10
8
  endif
11
- pagerSentinel = true
12
-
13
-
14
- # The pager model
15
- pagerTypes = schemaParse( \
16
- 'group "Pager"', \
17
- '', \
18
- '', \
19
- '# A pager application model', \
20
- 'struct Pager', \
21
- '', \
22
- " # The application's pages", \
23
- ' PagerPage[len > 0] pages', \
24
- '', \
25
- '', \
26
- '# A page model', \
27
- 'struct PagerPage', \
28
- '', \
29
- ' # The page name', \
30
- ' string name', \
31
- '', \
32
- ' # If true, the page is hidden', \
33
- ' optional bool hidden', \
34
- '', \
35
- ' # The page type', \
36
- ' PagerPageType type', \
37
- '', \
38
- '', \
39
- '# The page type', \
40
- 'union PagerPageType', \
41
- '', \
42
- ' # A function page', \
43
- ' PagerPageFunction function', \
44
- '', \
45
- ' # A markdown resource page', \
46
- ' PagerPageMarkdown markdown', \
47
- '', \
48
- ' # A navigation link', \
49
- ' PagerPageLink link', \
50
- '', \
51
- '', \
52
- '# A page function', \
53
- 'struct PagerPageFunction', \
54
- '', \
55
- ' # The page function', \
56
- ' object function', \
57
- '', \
58
- ' # The page title', \
59
- ' optional string title', \
60
- '', \
61
- '', \
62
- '# A Markdown resource page', \
63
- 'struct PagerPageMarkdown', \
64
- '', \
65
- ' # The Markdown resource URL', \
66
- ' string url', \
67
- '', \
68
- '', \
69
- '# A page link', \
70
- 'struct PagerPageLink', \
71
- '', \
72
- ' # The link URL', \
73
- ' string url' \
74
- )
75
-
76
-
77
- # $function: pagerValidate
78
- # $group: pager.mds
79
- # $doc: Validate a pager model
80
- # $arg pagerModel: The [pager model](includeModel.html#var.vName='Pager')
81
- # $return: The validated [pager model](includeModel.html#var.vName='Pager') or null if validation fails
82
- function pagerValidate(pagerModel):
83
- return schemaValidate(pagerTypes, 'Pager', pagerModel)
84
- endfunction
85
-
86
-
87
- # $function: pagerMain
88
- # $group: pager.mds
89
- # $doc: The pager application main entry point
90
- # $arg pagerModel: The [pager model](includeModel.html#var.vName='Pager')
91
- # $arg options: The pager application options. The following options are available:
92
- # $arg options: - **arguments** - The [arguments model](includeModel.html#var.vName='ArgsArguments').
93
- # $arg options: Must contain a string argument named "page".
94
- # $arg options: - **hideMenu** - Hide the menu links
95
- # $arg options: - **hideNav** - Hide the navigation links
96
- # $arg options: - **start** - The start page name
97
- async function pagerMain(pagerModel, options):
98
- if options == null:
99
- options = objectNew()
100
- endif
101
-
102
- # Validate the pager model
103
- pagerModel = pagerValidate(pagerModel)
104
- if pagerModel == null:
105
- return
106
- endif
107
-
108
- # Compute the visible and navigable pages
109
- pages = objectGet(pagerModel, 'pages')
110
- visiblePages = arrayNew()
111
- navPages = arrayNew()
112
- for page in pages:
113
- # Visible page?
114
- if !objectGet(page, 'hidden'):
115
- arrayPush(visiblePages, page)
116
-
117
- # Navigable page?
118
- pageTypeKey = arrayGet(objectKeys(objectGet(page, 'type')), 0)
119
- if pageTypeKey != 'link':
120
- arrayPush(navPages, page)
121
- endif
122
- endif
123
- endfor
124
-
125
- # Parse arguments
126
- startPageName = objectGet(options, 'start', if(arrayLength(navPages), objectGet(arrayGet(navPages, 0), 'name'), null))
127
- if objectHas(options, 'arguments'):
128
- arguments = argsValidate(objectGet(options, 'arguments'))
129
- if arguments == null:
130
- return
131
- endif
132
- else:
133
- arguments = arrayNew(objectNew('name', 'page', 'default', startPageName))
134
- endif
135
- args = argsParse(arguments)
136
-
137
- # Determine the current page
138
- curPage = null
139
- startPage = null
140
- for page in pages:
141
- if objectGet(page, 'name') == objectGet(args, 'page'):
142
- curPage = page
143
- endif
144
- if objectGet(page, 'name') == startPageName:
145
- startPage = page
146
- endif
147
- endfor
148
- if startPage == null:
149
- systemLogDebug('MarkdownUp - pager.mds: Unknown start page' + if(startPageName != null, '"' + startPageName + '"', ''))
150
- return
151
- endif
152
- if curPage == null:
153
- curPage = startPage
154
- endif
155
-
156
- # Determine the current page's navigable index, if any
157
- ixCurPage = -1
158
- for navPage, ixNavPage in navPages:
159
- if objectGet(navPage, 'name') == objectGet(curPage, 'name'):
160
- ixCurPage = ixNavPage
161
- break
162
- endif
163
- endfor
164
-
165
- # Render the menu
166
- if !objectGet(options, 'hideMenu'):
167
- for page, ixPage in visiblePages:
168
- pageName = objectGet(page, 'name')
169
- pageType = objectGet(page, 'type')
170
- pageTypeKey = arrayGet(objectKeys(pageType), 0)
171
-
172
- # Render the menu link
173
- pageNameNbsp = stringReplace(pageName, ' ', '&nbsp;')
174
- separator = if(ixPage != arrayLength(visiblePages) - 1, '&nbsp;|', '')
175
- if pageTypeKey == 'link':
176
- pageLinkURL = objectGet(objectGet(pageType, 'link'), 'url')
177
- markdownPrint('[' + markdownEscape(pageNameNbsp) + '](' + urlEncode(pageLinkURL) + ')' + separator)
178
- elif pageName == objectGet(curPage, 'name'):
179
- markdownPrint(markdownEscape(pageNameNbsp) + separator)
180
- else:
181
- markdownPrint(argsLink(arguments, pageNameNbsp, objectNew('page', pageName)) + separator)
182
- endif
183
- endfor
184
- markdownPrint('')
185
- endif
186
-
187
- # Render the start/next/prev buttons
188
- if !objectGet(options, 'hideNav') && arrayLength(navPages) > 1 && ixCurPage != -1:
189
- if startPageName == objectGet(curPage, 'name'):
190
- startPageName = null
191
- endif
192
- prevPageName = if(ixCurPage != -1 && ixCurPage - 1 >= 0, objectGet(arrayGet(navPages, ixCurPage - 1), 'name'), null)
193
- nextPageName = if(ixCurPage != -1 && ixCurPage + 1 < arrayLength(navPages), objectGet(arrayGet(navPages, ixCurPage + 1), 'name'), null)
194
- markdownPrint( \
195
- '(&nbsp;' + if(startPageName != null, argsLink(arguments, 'Start', objectNew('page', startPageName)), 'Start') + '&nbsp;|', \
196
- if(prevPageName != null, argsLink(arguments, 'Previous', objectNew('page', prevPageName)), 'Previous') + '&nbsp;|', \
197
- if(nextPageName != null, argsLink(arguments, 'Next', objectNew('page', nextPageName)), 'Next') + '&nbsp;)', \
198
- '' \
199
- )
200
- endif
201
-
202
- # Function page?
203
- curPageType = objectGet(curPage, 'type')
204
- curPageTypeKey = arrayGet(objectKeys(curPageType), 0)
205
- if curPageTypeKey == 'function':
206
- # Set the title
207
- title = objectGet(objectGet(curPageType, 'function'), 'title')
208
- if title != null:
209
- documentSetTitle(title)
210
- markdownPrint('# ' + markdownEscape(title), '')
211
- endif
212
9
 
213
- # Call the page function
214
- pageFn = objectGet(objectGet(curPageType, 'function'), 'function')
215
- pageFn(args)
216
- elif curPageTypeKey == 'markdown':
217
- # Fetch the Markdown text
218
- url = objectGet(objectGet(curPageType, 'markdown'), 'url')
219
- markdownText = systemFetch(url)
220
- if markdownText == null:
221
- markdownPrint('**Error:** Failed to load "' + url + '"')
222
- else:
223
- # Compute and set the page title
224
- markdownModel = markdownParse(markdownText)
225
- title = markdownTitle(markdownModel)
226
- if title == null:
227
- title = 'No Title'
228
- endif
229
- documentSetTitle(title)
230
10
 
231
- # Render the Markdown text
232
- markdownPrint('', markdownText)
233
- endif
234
- endif
235
- endfunction
11
+ systemLog('MarkdownUp - pager.mds: pager.mds is now pager.bare - please update before 2025-06-01')
12
+ include 'pager.bare'
@@ -0,0 +1,229 @@
1
+ # Licensed under the MIT License
2
+ # https://github.com/craigahobbs/markdown-up/blob/main/LICENSE
3
+
4
+
5
+ # Include sentinel
6
+ if systemGlobalGet('unittestSentinel'):
7
+ return
8
+ endif
9
+ unittestSentinel = true
10
+
11
+
12
+ include 'diff.bare'
13
+
14
+
15
+ # Test statistics
16
+ unittestTests = objectNew()
17
+ unittestWarnings = arrayNew()
18
+
19
+
20
+ # $function: unittestRunTest
21
+ # $group: unittest.bare
22
+ # $doc: Run a unit test
23
+ # $arg testName: The test function name
24
+ function unittestRunTest(testName):
25
+ testFn = unittestRunTestHelper(testName)
26
+ if testFn:
27
+ testFn()
28
+ systemGlobalSet('unittestTestName', null)
29
+ endif
30
+ endfunction
31
+
32
+
33
+ # $function: unittestRunTestAsync
34
+ # $group: unittest.bare
35
+ # $doc: Run an asyncronous unit test
36
+ # $arg testName: The test function name
37
+ async function unittestRunTestAsync(testName):
38
+ testFn = unittestRunTestHelper(testName)
39
+ if testFn:
40
+ testFn()
41
+ systemGlobalSet('unittestTestName', null)
42
+ endif
43
+ endfunction
44
+
45
+
46
+ # unittestRunTest helper function
47
+ function unittestRunTestHelper(testName):
48
+ # Single test argument?
49
+ if vTest != null && vTest != testName:
50
+ return null
51
+ endif
52
+
53
+ # Test run multiple times?
54
+ if objectHas(unittestTests, testName):
55
+ arrayPush(unittestWarnings, 'Test "' + testName + '" run multiple times')
56
+ return null
57
+ endif
58
+
59
+ # Get the test func
60
+ testFn = systemGlobalGet(testName)
61
+ if testFn == null:
62
+ arrayPush(unittestWarnings, 'Test "' + testName + '" not found')
63
+ return null
64
+ endif
65
+
66
+ # Add the unit test result array
67
+ testFailures = arrayNew()
68
+ objectSet(unittestTests, testName, testFailures)
69
+ systemGlobalSet('unittestTestName', testName)
70
+
71
+ return testFn
72
+ endfunction
73
+
74
+
75
+ # $function: unittestReport
76
+ # $group: unittest.bare
77
+ # $doc: Render the unit test report
78
+ # $return: The number of unit test failures
79
+ function unittestReport():
80
+ # Compute test statistics
81
+ testNames = arraySort(objectKeys(unittestTests))
82
+ testCount = arrayLength(testNames)
83
+ testFailCount = 0
84
+ for testName in testNames:
85
+ testFailures = objectGet(unittestTests, testName)
86
+ if arrayLength(testFailures):
87
+ testFailCount = testFailCount + 1
88
+ endif
89
+ endfor
90
+ testPassCount = testCount - testFailCount
91
+
92
+ # Report statistics
93
+ markdownPrint('', 'Ran ' + testCount + ' tests - ' + testPassCount + ' passed, ' + testFailCount + ' failed')
94
+ if vTest != null:
95
+ testURL = if(vTestArgs != null, '#' + vTestArgs, '#var=')
96
+ markdownPrint('([all tests](' + testURL + '))')
97
+ endif
98
+
99
+ # Report any warnings
100
+ testWarningCount = arrayLength(unittestWarnings)
101
+ if testWarningCount:
102
+ markdownPrint('', '## Warnings')
103
+ for warning in unittestWarnings:
104
+ markdownPrint('', '- ' + markdownEscape(warning))
105
+ endfor
106
+ endif
107
+
108
+ # Report the failing tests
109
+ if testFailCount:
110
+ markdownPrint('', '## Failing Tests')
111
+ for testName in testNames:
112
+ testFailures = objectGet(unittestTests, testName)
113
+ if arrayLength(testFailures):
114
+ testURL = '#' + if(vTestArgs != null, vTestArgs + '&', '') + "var.vTest='" + urlEncodeComponent(testName) + "'"
115
+ failureLines = arrayNew('', '[' + markdownEscape(testName) + '](' + testURL + ") - FAIL")
116
+ for errorLines in testFailures:
117
+ for errorLine, ixErrorLine in errorLines:
118
+ if ixErrorLine == 0:
119
+ arrayPush(failureLines, '')
120
+ arrayPush(failureLines, '- ' + errorLine)
121
+ else:
122
+ arrayPush(failureLines, if(errorLine, ' ' + errorLine, ''))
123
+ endif
124
+ endfor
125
+ endfor
126
+ markdownPrint(failureLines)
127
+ endif
128
+ endfor
129
+ endif
130
+
131
+ # Report the passing tests
132
+ if testPassCount:
133
+ markdownPrint('', '## Passing Tests')
134
+ for testName in testNames:
135
+ testFailures = objectGet(unittestTests, testName)
136
+ if !arrayLength(testFailures):
137
+ testURL = '#' + if(vTestArgs != null, vTestArgs + '&', '') + "var.vTest='" + urlEncodeComponent(testName) + "'"
138
+ markdownPrint('', '[' + markdownEscape(testName) + '](' + testURL + ") - OK")
139
+ endif
140
+ endfor
141
+ endif
142
+
143
+ return testWarningCount + testFailCount
144
+ endfunction
145
+
146
+
147
+ # $function: unittestEqual
148
+ # $group: unittest.bare
149
+ # $doc: Assert an actual value is equal to the expected value
150
+ # $arg actual: The actual value
151
+ # $arg expected: The expected value
152
+ # $arg description: The description of the assertion
153
+ function unittestEqual(actual, expected, description):
154
+ if actual == expected:
155
+ return
156
+ endif
157
+
158
+ # Add the test failure error lines
159
+ testFailures = objectGet(unittestTests, unittestTestName)
160
+ errorLines = arrayNew( \
161
+ 'Equal:', \
162
+ '', \
163
+ '```', \
164
+ jsonStringify(actual), \
165
+ '```', \
166
+ '', \
167
+ '```', \
168
+ jsonStringify(expected), \
169
+ '```' \
170
+ )
171
+ if description != null:
172
+ arrayPush(testFailures, arrayExtend(arrayNew(markdownEscape(description), errorLines)))
173
+ else:
174
+ arrayPush(testFailures, errorLines)
175
+ endif
176
+ endfunction
177
+
178
+
179
+ # $function: unittestDeepEqual
180
+ # $group: unittest.bare
181
+ # $doc: Assert an actual value is *deeply* equal to the expected value
182
+ # $arg actual: The actual value
183
+ # $arg expected: The expected value
184
+ # $arg description: The description of the assertion
185
+ function unittestDeepEqual(actual, expected, description):
186
+ # Serialize as JSON
187
+ actualJSON = if(systemType(actual) == 'string', actual, jsonStringify(actual, 4))
188
+ expectedJSON = if(systemType(expected) == 'string', expected, jsonStringify(expected, 4))
189
+ if actualJSON == expectedJSON:
190
+ return
191
+ endif
192
+
193
+ # Compute the difference lines
194
+ errorLines = arrayNew()
195
+ diffErrorLines = arrayNew()
196
+ for diff in diffLines(actualJSON, expectedJSON):
197
+ diffType = objectGet(diff, 'type')
198
+ if diffType == 'Remove':
199
+ for diffLine in objectGet(diff, 'lines'):
200
+ arrayPush(diffErrorLines, '--- ' + diffLine)
201
+ endfor
202
+ elif diffType == 'Add':
203
+ for diffLine in objectGet(diff, 'lines'):
204
+ arrayPush(diffErrorLines, '+++ ' + diffLine)
205
+ endfor
206
+ else:
207
+ # diffType == 'Identical'
208
+ if diffErrorLines:
209
+ arrayExtend(errorLines, arrayNew('Deep-equal:', '', '```'))
210
+ arrayExtend(errorLines, diffErrorLines)
211
+ arrayPush(errorLines, '```')
212
+ diffErrorLines = arrayNew()
213
+ endif
214
+ endif
215
+ endfor
216
+ if diffErrorLines:
217
+ arrayExtend(errorLines, arrayNew('Deep-equal:', '', '```'))
218
+ arrayExtend(errorLines, diffErrorLines)
219
+ arrayPush(errorLines, '```')
220
+ endif
221
+
222
+ # Add the test failure error lines
223
+ testFailures = objectGet(unittestTests, unittestTestName)
224
+ if description != null:
225
+ arrayPush(testFailures, arrayExtend(arrayNew(markdownEscape(description), errorLines)))
226
+ else:
227
+ arrayPush(testFailures, errorLines)
228
+ endif
229
+ endfunction
@@ -6,186 +6,7 @@
6
6
  if systemGlobalGet('unittestSentinel'):
7
7
  return
8
8
  endif
9
- unittestSentinel = true
10
9
 
11
10
 
12
- # Test statistics
13
- unittestTests = objectNew()
14
- unittestWarnings = arrayNew()
15
-
16
-
17
- # $function: unittestRunTest
18
- # $group: unittest.mds
19
- # $doc: Run a unit test
20
- # $arg testName: The test function name
21
- function unittestRunTest(testName):
22
- testFn = unittestRunTestHelper(testName)
23
- if testFn:
24
- testFn()
25
- systemGlobalSet('unittestTestName', null)
26
- endif
27
- endfunction
28
-
29
-
30
- # $function: unittestRunTestAsync
31
- # $group: unittest.mds
32
- # $doc: Run an asyncronous unit test
33
- # $arg testName: The test function name
34
- async function unittestRunTestAsync(testName):
35
- testFn = unittestRunTestHelper(testName)
36
- if testFn:
37
- testFn()
38
- systemGlobalSet('unittestTestName', null)
39
- endif
40
- endfunction
41
-
42
-
43
- # unittestRunTest helper function
44
- function unittestRunTestHelper(testName):
45
- # Single test argument?
46
- if vTest != null && vTest != testName:
47
- return null
48
- endif
49
-
50
- # Test run multiple times?
51
- if objectHas(unittestTests, testName):
52
- arrayPush(unittestWarnings, 'Test "' + testName + '" run multiple times')
53
- return null
54
- endif
55
-
56
- # Get the test func
57
- testFn = systemGlobalGet(testName)
58
- if testFn == null:
59
- arrayPush(unittestWarnings, 'Test "' + testName + '" not found')
60
- return null
61
- endif
62
-
63
- # Add the unit test result array
64
- testFailures = arrayNew()
65
- objectSet(unittestTests, testName, testFailures)
66
- systemGlobalSet('unittestTestName', testName)
67
-
68
- return testFn
69
- endfunction
70
-
71
-
72
- # $function: unittestReport
73
- # $group: unittest.mds
74
- # $doc: Render the unit test report
75
- # $return: The number of unit test failures
76
- function unittestReport():
77
- # Compute test statistics
78
- testNames = arraySort(objectKeys(unittestTests))
79
- testCount = arrayLength(testNames)
80
- testFailCount = 0
81
- for testName in testNames:
82
- testFailures = objectGet(unittestTests, testName)
83
- if arrayLength(testFailures):
84
- testFailCount = testFailCount + 1
85
- endif
86
- endfor
87
- testPassCount = testCount - testFailCount
88
-
89
- # Report statistics
90
- markdownPrint('', 'Ran ' + testCount + ' tests - ' + testPassCount + ' passed, ' + testFailCount + ' failed')
91
- if vTest != null:
92
- testURL = if(vTestArgs != null, '#' + vTestArgs, '#var=')
93
- markdownPrint('([all tests](' + testURL + '))')
94
- endif
95
-
96
- # Report any warnings
97
- testWarningCount = arrayLength(unittestWarnings)
98
- if testWarningCount:
99
- markdownPrint('', '## Warnings')
100
- for warning in unittestWarnings:
101
- markdownPrint('', '- ' + markdownEscape(warning))
102
- endfor
103
- endif
104
-
105
- # Report the failing tests
106
- if testFailCount:
107
- markdownPrint('', '## Failing Tests')
108
- for testName in testNames:
109
- testFailures = objectGet(unittestTests, testName)
110
- if arrayLength(testFailures):
111
- testURL = '#' + if(vTestArgs != null, vTestArgs + '&', '') + "var.vTest='" + urlEncodeComponent(testName) + "'"
112
- failureLines = arrayNew('', '[' + markdownEscape(testName) + '](' + testURL + ") - FAIL")
113
- for errorLines in testFailures:
114
- for errorLine, ixErrorLine in errorLines:
115
- if ixErrorLine == 0:
116
- arrayPush(failureLines, '')
117
- arrayPush(failureLines, '- ' + errorLine)
118
- else:
119
- arrayPush(failureLines, ' ' + errorLine)
120
- endif
121
- endfor
122
- endfor
123
- markdownPrint(failureLines)
124
- endif
125
- endfor
126
- endif
127
-
128
- # Report the passing tests
129
- if testPassCount:
130
- markdownPrint('', '## Passing Tests')
131
- for testName in testNames:
132
- testFailures = objectGet(unittestTests, testName)
133
- if !arrayLength(testFailures):
134
- testURL = '#' + if(vTestArgs != null, vTestArgs + '&', '') + "var.vTest='" + urlEncodeComponent(testName) + "'"
135
- markdownPrint('', '[' + markdownEscape(testName) + '](' + testURL + ") - OK")
136
- endif
137
- endfor
138
- endif
139
-
140
- return testWarningCount + testFailCount
141
- endfunction
142
-
143
-
144
- # $function: unittestEqual
145
- # $group: unittest.mds
146
- # $doc: Assert an actual value is equal to the expected value
147
- # $arg actual: The actual value
148
- # $arg expected: The expected value
149
- # $arg description: The description of the assertion
150
- function unittestEqual(actual, expected, description):
151
- if actual != expected:
152
- unittestRecordError(jsonStringify(actual), jsonStringify(expected), description)
153
- endif
154
- endfunction
155
-
156
-
157
- # $function: unittestDeepEqual
158
- # $group: unittest.mds
159
- # $doc: Assert an actual value is *deeply* equal to the expected value
160
- # $arg actual: The actual value
161
- # $arg expected: The expected value
162
- # $arg description: The description of the assertion
163
- function unittestDeepEqual(actual, expected, description):
164
- actualJSON = jsonStringify(actual)
165
- expectedJSON = jsonStringify(expected)
166
- if actualJSON != expectedJSON:
167
- unittestRecordError(actualJSON, expectedJSON, description)
168
- endif
169
- endfunction
170
-
171
-
172
- # Helper function to record a unit test error
173
- function unittestRecordError(actualStr, expectedStr, description):
174
- testFailures = objectGet(unittestTests, unittestTestName)
175
- errorLines = arrayNew( \
176
- '~~~', \
177
- actualStr, \
178
- '~~~', \
179
- '', \
180
- '!=', \
181
- '', \
182
- '~~~', \
183
- expectedStr, \
184
- '~~~' \
185
- )
186
- if description != null:
187
- arrayPush(testFailures, arrayExtend(arrayNew(markdownEscape(description), errorLines)))
188
- else:
189
- arrayPush(testFailures, errorLines)
190
- endif
191
- endfunction
11
+ systemLog('MarkdownUp - unittest.mds: unittest.mds is now unittest.bare - please update before 2025-06-01')
12
+ include 'unittest.bare'