-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.html
244 lines (221 loc) · 9.32 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
<!DOCTYPE html><!--*-js-indent-level:2;css-indent-offset:2-*-->
<!-- Copyright (c) 2022-2025 by zrajm. License: GPLv2 -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<link rel=icon href=baremark.svg>
<title>Baremark: A Tiny Markdown Engine</title>
<link rel=stylesheet href=index.css>
<input id=invertmode type=checkbox>
<h1 id=top>Baremark: A Tiny Markdown Engine</h1>
<details>
<summary>README</summary>
<div id=readme>Loading… (Requires Javascript)</div>
</details>
<script src=baremark.js></script>
<script src=baremark-toc.js></script>
<script>
fetch('README.md')
.then(x => x.text())
.then(md => document.getElementById('readme').innerHTML = baremark(md))
</script>
<h2 id=baremark>Test Cases</h2>
<p>The test cases below are intended as specs for Baremark, though they will
evolve as Baremark does so.
<p><b>Legend:</b>
<span class="legend pass">Passed</span>
<span class="legend fail">Failed</span>
<span class="legend ignore"><s>All ignored</s></span></p>
<div data-testsuite="tests-baremark.json" data-function="baremark"></div>
<h2 id=commonmark>CommmonMark 0.30 Test Cases</h2>
<p>These are the <a href="https://spec.commonmark.org/0.30/spec.json"
target=_blank>test cases</a> of the <a href="https://spec.commonmark.org/0.30/"
target=_blank>CommonMark 0.30 spec</a> run against Baremark. As Baremark is
intended to be minimal in size, not all of these CommonMark tests will ever
pass, but they can give you an idea of how compatible Baremark is.</p>
<p>The HTML generated by Baremark is not necessarily identical to that of other
CommonMark compliant Markdown generators. Among other things, Baremark favor
older HTML tags, such as <tt><i></tt>, <tt><b></tt> and <tt><s></tt>
(over the newer <tt><em></tt>, <tt><strong></tt> and <tt><del></tt>
etc) simply because they’re shorter. (<i>Semantic markup, pha!</i>—Who are we
kidding anyway?!) Neither does Baremark spend any effort on collapsing or
cleaning up your whitespace for you (your browser will collapse for you
anyway), so for the most part, the whitespace found in the outputted HTML is
the same as the one found in the Markdown (with the obvious exceptions being
the processing of newlines and linebreaks mandated by the Markdown specs). For
source brevity Baremark uses HTML character code entities (such
as <tt>&#38;</tt>), rather than more commonly seen named entities
(<tt>&amp;</tt>).</p>
<p><b>Legend:</b>
<span class="legend pass">Passed</span>
<span class="legend fail">Failed</span>
<span class="legend ignore"><s>All ignored</s></span></p>
<div data-testsuite="tests-commonmark.json" data-function="baremark"></div>
<h2 id=framework>Test Framework</h2>
<p>I kinda, sorta, accidentally put this very simple test framework/page
together to present how well Baremark fared with the CommonMark test suite. The
below “test results” are only meant to show what different kind of test results
look like on the page.</p>
<p><b>Legend:</b>
<span class="legend pass">Passed</span>
<span class="legend fail">Failed</span>
<span class="legend ignore"><s>All ignored</s></span></p>
<div data-testsuite="tests-framework.json" data-function="baremark"></div>
<footer>© 2022–2025 by zrajm, Uppsala.</footer>
<script src="jquery-3.6.0.slim.min.js"></script>
<script src="baremark.js"></script>
<script>
$(()=>{
// jQuery plugins.
jQuery.fn.forEach = [].forEach
jQuery.fn.reduce = [].reduce
function escapeHtml(x) {
return x.replace(
/["&<>]/g,
x => `&${{ '"': 'quot', '&': 'amp', '<': 'lt', '>': 'gt' }[x]};`)
}
function inputComment(x) {
if (typeof x === "string") { x = [x] }
return x.map(
x => '<div class="comment">'
+ (escapeAscii(escapeHtml(x))
.replace(/\S+/g, '<span>$&</span>')
.replace(/\S.*/g, '<span>$&</span>')
)
+ '</div>'
).join('')
}
// Escape any ASCII control characters with C escape sequences.
function escapeAscii(x) {
return x.replace(
/[\x00-\x1f\x7f-\x9f\\]/g,
m => ({
'\a': '\\a', '\b': '\\b', '\f': '\\f', '\n' : '\\n', '\r': '\\r',
'\t': '\\t', '\v': '\\v', '\\': '\\\\', '\x1B': '\\e', ' ' : '␣',
}[m] ||
'\\x' + m.charCodeAt(0).toString(16).toUpperCase().padStart(2, '0')))
}
function warn(html) {
if (/<style\b/.test(html)) {
return '!!! Contains <tt><style></tt> tag, won’t display here!'
} else if (/<script\b/.test(html)) {
return '!!! Contains <tt><script></tt> tag, won’t display here!'
} else if (/<img\b/.test(html)) {
return '!!! Contains <tt><img></tt> tag, won’t display here!'
}
return ''
}
function processTests(tests, $e, cb) {
if (!tests.length) {
$e.html('[NONE YET]')
return
}
let sectionName, $section
tests.forEach((test) => {
// If test is just a string (not object) turn it into section heading.
if (typeof test === 'string') {
test = { section: test }
}
// If section name as changed, append new section.
if (test.section !== undefined && sectionName !== test.section) {
sectionName = test.section
$section = $(`<details class=group>
<summary>${test.section}</summary>
</details>`).appendTo($e)
}
if (test.markdown === undefined) { return }
// Count as pass, fail or ignore.
const expect = test.bare || test.html
const got = (() => {
try {
return cb(test.markdown)
} catch (e) {
return `CAUGHT ERROR: ${e}`
}
})()
// Add test result to current section.
$section.append(
`<details class="test ${test.ignore ? 'ignore' : ''} ${got === expect ? 'pass' : 'fail'}">
<summary>
${test.example ? `Test ${test.example}` : ''}${test.example && test.title ? ': ' : ''}
${test.title ? escapeAscii(test.title) : ''}
${test.hasOwnProperty('FIXME') ? ` <span class=fixme>(FIXME${test.FIXME ? ': ' + escapeAscii(test.FIXME) : ''})</span>` : ''}
${test.hasOwnProperty('NOTE') ? ` <span class=note >(NOTE${ test.NOTE ? ': ' + escapeAscii(test.NOTE) : ''})</span>` : ''}
${test.comment ? '<div style="float:right;opacity:.5">#</div>' : ''}
</summary>
<table>
<thead><tr><th><th>Code<th>Appearance</thead>
<tr><th>Input
<td>
<pre>${test.comment ? inputComment(test.comment) : ''}${escapeAscii(escapeHtml(test.markdown))}</pre>
<td><pre>${warn(test.markdown) || escapeHtml(test.markdown)}</pre>
<tr><th>Expect
<td><pre>${escapeAscii(escapeHtml(expect))}</pre>
<td>${warn(expect) || expect}
<tr><th>Got
<td><pre>${escapeAscii(escapeHtml(got))}</pre>
<td>${warn(got) || got}
</table>
</details>`)
})
// Go through sections, set color and append counters.
$e.find('> details.group').forEach(e => {
const $e = $(e)
const counter = $e.find('> details.test').reduce((a, e) => {
const $e = $(e)
a[$e.hasClass('ignore') ? 'ignore' : $e.hasClass('pass') ? 'pass' : 'fail'] += 1
return a
}, { pass: 0, fail: 0, ignore: 0 })
$e.addClass(`
${counter.fail ? 'fail' : ''}
${counter.pass ? 'pass' : ''}
${counter.ignore ? 'ignore' : ''}`)
.find('> summary').append(
`<div class=count>
<span class=fail>${counter.fail}</span>
<span class=pass>${counter.pass}</span>
<span class=ignore>${counter.ignore}</span>
</div>`)
})
}
// Load test cases from jsonUrl and show in $e (jQuery DOM element).
function testSuite(jsonUrl, $e, cb) {
window.fetch(jsonUrl)
.then(response => response.text())
.then(json => {
try {
return processTests(JSON.parse(json), $e, cb)
} catch (e) {
$e.append(`<div class=error><b>Failed to load JSON file ‘${jsonUrl}’</b><br>${e}`)
}
})
}
$('[data-testsuite]')
.forEach(e => testSuite(
e.dataset.testsuite,
$(e),
self[e.dataset.function]
))
})
</script>
<script>
// Org-mode style opening of <details>. Clicking a <summary> cycles through:
// + children = opens this <details> (but none of its children)
// + subtree = opens up all child <details> recursively
// + folded = closes this & all child <details>
$(document).on('click', 'details > summary', e => {
e.preventDefault()
const $tag = $(e.currentTarget.parentElement) // get parent <details> tag
if ($tag.attr('open')) {
const $subtags = $tag.find('> details')
const $opened = $subtags.filter((_,t)=>t.hasAttribute('open'))
if ($subtags.length && $opened.length === 0) {
$subtags.attr('open', 1) // open subtags
} else {
$opened.add($tag).attr('open', null) // close this & subtags
}
} else {
$tag.attr('open', 1) // open
}
})
</script>
<!--[eof]-->