Skip to content

Commit 9c0ca46

Browse files
aduh95danielleadams
authored andcommitted
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. PR-URL: #37162 Reviewed-By: James M Snell <[email protected]> Reviewed-By: Rich Trott <[email protected]> Reviewed-By: Michaël Zasso <[email protected]>
1 parent 07fc61b commit 9c0ca46

8 files changed

+149
-10
lines changed

doc/api/wasi.md

+21
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,27 @@ const instance = await WebAssembly.instantiate(wasm, importObject);
2929
wasi.start(instance);
3030
```
3131

32+
```cjs
33+
'use strict';
34+
const fs = require('fs');
35+
const { WASI } = require('wasi');
36+
const wasi = new WASI({
37+
args: process.argv,
38+
env: process.env,
39+
preopens: {
40+
'/sandbox': '/some/real/path/that/wasm/can/access'
41+
}
42+
});
43+
const importObject = { wasi_snapshot_preview1: wasi.wasiImport };
44+
45+
(async () => {
46+
const wasm = await WebAssembly.compile(fs.readFileSync('./demo.wasm'));
47+
const instance = await WebAssembly.instantiate(wasm, importObject);
48+
49+
wasi.start(instance);
50+
})();
51+
```
52+
3253
To run the above example, create a new WebAssembly text format file named
3354
`demo.wat`:
3455

doc/api_assets/js-flavor-cjs.svg

+5
Loading

doc/api_assets/js-flavor-esm.svg

+5
Loading

doc/api_assets/style.css

+47
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 ~ .mjs {
863+
background-image: url(./js-flavor-esm.svg);
864+
}
818865
}

test/doctool/test-doctool-html.js

+9-1
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;
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+
```cjs
6+
require('path');
7+
```
8+
9+
```mjs
10+
import 'node:url';
11+
```
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+
```mjs
6+
import 'node:url';
7+
```
8+
9+
```cjs
10+
require('path');
11+
```

tools/doc/html.js

+40-9
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 === 'cjs' || node.lang === 'mjs';
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,44 @@ 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 className = isJSFlavorSnippet(node) ?
210+
`language-js ${node.lang}` :
211+
`language-${node.lang}`;
212+
const highlighted =
213+
`<code class='${className}'>` +
214+
(getLanguage(node.lang || '') ?
215+
highlight(node.lang, node.value) : node).value +
216+
'</code>';
211217
node.type = 'html';
212-
node.value = '<pre>' +
213-
`<code class = 'language-${node.lang}'>` +
214-
highlighted +
215-
'</code></pre>';
218+
219+
if (isJSFlavorSnippet(node)) {
220+
const previousNode = parent.children[index - 1] || {};
221+
const nextNode = parent.children[index + 1] || {};
222+
223+
if (!isJSFlavorSnippet(previousNode) &&
224+
isJSFlavorSnippet(nextNode) &&
225+
nextNode.lang !== node.lang) {
226+
// Saving the highlight code as value to be added in the next node.
227+
node.value = highlighted;
228+
} else if (isJSFlavorSnippet(previousNode)) {
229+
node.value = '<pre>' +
230+
'<input class="js-flavor-selector" type="checkbox"' +
231+
// If CJS comes in second, ESM should display by default.
232+
(node.lang === 'cjs' ? ' checked' : '') +
233+
' aria-label="Show modern ES modules syntax">' +
234+
previousNode.value +
235+
highlighted +
236+
'</pre>';
237+
node.lang = null;
238+
previousNode.value = '';
239+
previousNode.lang = null;
240+
} else {
241+
// Isolated JS snippet, no need to add the checkbox.
242+
node.value = `<pre>${highlighted}</pre>`;
243+
}
244+
} else {
245+
node.value = `<pre>${highlighted}</pre>`;
246+
}
216247
} else if (node.type === 'html' && common.isYAMLBlock(node.value)) {
217248
node.value = parseYAML(node.value);
218249

0 commit comments

Comments
 (0)