Skip to content

Commit c13d4be

Browse files
committed
tools,doc: add support for several flavors of JS code snippets
Enable code example using both modern ESM syntax and legacy CJS syntax. It adds a toggle on the web interface to let users switch from one JavaScript flavor to the other.
1 parent 433badd commit c13d4be

File tree

8 files changed

+153
-11
lines changed

8 files changed

+153
-11
lines changed

doc/api/wasi.md

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ The WASI API provides an implementation of the [WebAssembly System Interface][]
1010
specification. WASI gives sandboxed WebAssembly applications access to the
1111
underlying operating system via a collection of POSIX-like functions.
1212

13-
```js
13+
```js esm
1414
import fs from 'fs';
1515
import { WASI } from 'wasi';
1616

@@ -28,6 +28,26 @@ const instance = await WebAssembly.instantiate(wasm, importObject);
2828

2929
wasi.start(instance);
3030
```
31+
```js cjs
32+
'use strict';
33+
const fs = require('fs');
34+
const { WASI } = require('wasi');
35+
const wasi = new WASI({
36+
args: process.argv,
37+
env: process.env,
38+
preopens: {
39+
'/sandbox': '/some/real/path/that/wasm/can/access'
40+
}
41+
});
42+
const importObject = { wasi_snapshot_preview1: wasi.wasiImport };
43+
44+
(async () => {
45+
const wasm = await WebAssembly.compile(fs.readFileSync('./demo.wasm'));
46+
const instance = await WebAssembly.instantiate(wasm, importObject);
47+
48+
wasi.start(instance);
49+
})();
50+
```
3151

3252
To run the above example, create a new WebAssembly text format file named
3353
`demo.wat`:

doc/api_assets/js-flavor-cjs.svg

Lines changed: 5 additions & 0 deletions
Loading

doc/api_assets/js-flavor-esm.svg

Lines changed: 5 additions & 0 deletions
Loading

doc/api_assets/style.css

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -765,6 +765,33 @@ kbd {
765765
display: block;
766766
}
767767

768+
.js-flavor-selector {
769+
appearance: none;
770+
float: right;
771+
background-image: url(./js-flavor-cjs.svg);
772+
background-size: contain;
773+
background-repeat: no-repeat;
774+
width: 142px;
775+
height: 20px;
776+
}
777+
.js-flavor-selector:checked {
778+
background-image: url(./js-flavor-esm.svg);
779+
}
780+
.js-flavor-selector:not(:checked) ~ .esm,
781+
.js-flavor-selector:checked ~ .cjs {
782+
display: none;
783+
}
784+
.dark-mode .js-flavor-selector {
785+
filter: invert(1);
786+
}
787+
@supports (aspect-ratio: 1 / 1) {
788+
.js-flavor-selector {
789+
height: 1.5em;
790+
width: auto;
791+
aspect-ratio: 2719 / 384;
792+
}
793+
}
794+
768795
@media print {
769796
html {
770797
height: auto;
@@ -815,4 +842,24 @@ kbd {
815842
#apicontent {
816843
overflow: hidden;
817844
}
845+
.js-flavor-selector {
846+
display: none;
847+
}
848+
.js-flavor-selector + * {
849+
margin-bottom: 2rem;
850+
padding-bottom: 2rem;
851+
border-bottom: 1px solid var(--color-text-primary);
852+
}
853+
.js-flavor-selector ~ * {
854+
display: block !important;
855+
background-position: top right;
856+
background-size: 142px 20px;
857+
background-repeat: no-repeat;
858+
}
859+
.js-flavor-selector ~ .cjs {
860+
background-image: url(./js-flavor-cjs.svg);
861+
}
862+
.js-flavor-selector ~ .esm {
863+
background-image: url(./js-flavor-esm.svg);
864+
}
818865
}

test/doctool/test-doctool-html.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,15 @@ const testData = [
129129
{
130130
file: fixtures.path('document_with_special_heading.md'),
131131
html: '<title>Sample markdown with special heading |',
132-
}
132+
},
133+
{
134+
file: fixtures.path('document_with_esm_and_cjs_code_snippet.md'),
135+
html: '<input class="js-flavor-selector" type="checkbox" checked',
136+
},
137+
{
138+
file: fixtures.path('document_with_cjs_and_esm_code_snippet.md'),
139+
html: '<input class="js-flavor-selector" type="checkbox" aria-label',
140+
},
133141
];
134142

135143
const spaces = /\s/g;
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Usage and Example
2+
3+
CJS snippet is first, it should be the one displayed by default.
4+
5+
```js cjs
6+
require('path');
7+
```
8+
9+
```js esm
10+
import 'node:url';
11+
```
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Usage and Example
2+
3+
ESM snippet is first, it should be the one displayed by default.
4+
5+
```js esm
6+
import 'node:url';
7+
```
8+
9+
```js cjs
10+
require('path');
11+
```

tools/doc/html.js

Lines changed: 44 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -187,14 +187,16 @@ function linkJsTypeDocs(text) {
187187
return parts.join('`');
188188
}
189189

190+
const isJSFlavorSnippet = (node) => node.lang === 'js' && node.meta;
191+
190192
// Preprocess headers, stability blockquotes, and YAML blocks.
191193
function preprocessElements({ filename }) {
192194
return (tree) => {
193195
const STABILITY_RE = /(.*:)\s*(\d)([\s\S]*)/;
194196
let headingIndex = -1;
195197
let heading = null;
196198

197-
visit(tree, null, (node, index) => {
199+
visit(tree, null, (node, index, parent) => {
198200
if (node.type === 'heading') {
199201
headingIndex = index;
200202
heading = node;
@@ -204,15 +206,48 @@ function preprocessElements({ filename }) {
204206
`No language set in ${filename}, ` +
205207
`line ${node.position.start.line}`);
206208
}
207-
const language = (node.lang || '').split(' ')[0];
208-
const highlighted = getLanguage(language) ?
209-
highlight(language, node.value).value :
210-
node.value;
209+
const highlighted =
210+
`<code class='language-${node.lang} ${node.meta}'>` +
211+
(getLanguage(node.lang || '') ?
212+
highlight(node.lang, node.value) : node).value +
213+
'</code>';
211214
node.type = 'html';
212-
node.value = '<pre>' +
213-
`<code class = 'language-${node.lang}'>` +
214-
highlighted +
215-
'</code></pre>';
215+
216+
if (isJSFlavorSnippet(node)) {
217+
const previousNode = parent.children[index - 1] || {};
218+
const nextNode = parent.children[index + 1] || {};
219+
220+
if (node.meta !== 'esm' && node.meta !== 'cjs') {
221+
console.warn(
222+
`Unknown JavaScript flavor in ${filename}` +
223+
`:${node.position.start.line}:${node.position.start.column}`);
224+
node.value = `<pre>${highlighted}</pre>`;
225+
node.meta = null;
226+
} else if (!isJSFlavorSnippet(previousNode) &&
227+
isJSFlavorSnippet(nextNode) &&
228+
nextNode.meta !== node.meta) {
229+
node.value = highlighted;
230+
} else if (isJSFlavorSnippet(previousNode)) {
231+
node.value = '<pre>' +
232+
'<input class="js-flavor-selector" type="checkbox"' +
233+
(node.meta === 'cjs' ? ' checked' : '') +
234+
' aria-label="Show modern ES modules syntax">' +
235+
previousNode.value +
236+
highlighted +
237+
'</pre>';
238+
node.meta = null;
239+
previousNode.value = '';
240+
previousNode.meta = null;
241+
} else {
242+
console.warn(
243+
`Unused JavaScript flavored block in ${filename}` +
244+
`:${node.position.start.line}:${node.position.start.column}`);
245+
node.value = `<pre>${highlighted}</pre>`;
246+
node.meta = null;
247+
}
248+
} else {
249+
node.value = `<pre>${highlighted}</pre>`;
250+
}
216251
} else if (node.type === 'html' && common.isYAMLBlock(node.value)) {
217252
node.value = parseYAML(node.value);
218253

0 commit comments

Comments
 (0)