Skip to content

Commit 9a5411a

Browse files
aduh95targos
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 <jasnell@gmail.com> Reviewed-By: Rich Trott <rtrott@gmail.com> Reviewed-By: Michaël Zasso <targos@protonmail.com>
1 parent 8399766 commit 9a5411a

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
@@ -782,6 +782,33 @@ kbd {
782782
display: block;
783783
}
784784

785+
.js-flavor-selector {
786+
appearance: none;
787+
float: right;
788+
background-image: url(./js-flavor-cjs.svg);
789+
background-size: contain;
790+
background-repeat: no-repeat;
791+
width: 142px;
792+
height: 20px;
793+
}
794+
.js-flavor-selector:checked {
795+
background-image: url(./js-flavor-esm.svg);
796+
}
797+
.js-flavor-selector:not(:checked) ~ .esm,
798+
.js-flavor-selector:checked ~ .cjs {
799+
display: none;
800+
}
801+
.dark-mode .js-flavor-selector {
802+
filter: invert(1);
803+
}
804+
@supports (aspect-ratio: 1 / 1) {
805+
.js-flavor-selector {
806+
height: 1.5em;
807+
width: auto;
808+
aspect-ratio: 2719 / 384;
809+
}
810+
}
811+
785812
@media print {
786813
html {
787814
height: auto;
@@ -832,4 +859,24 @@ kbd {
832859
#apicontent {
833860
overflow: hidden;
834861
}
862+
.js-flavor-selector {
863+
display: none;
864+
}
865+
.js-flavor-selector + * {
866+
margin-bottom: 2rem;
867+
padding-bottom: 2rem;
868+
border-bottom: 1px solid var(--color-text-primary);
869+
}
870+
.js-flavor-selector ~ * {
871+
display: block !important;
872+
background-position: top right;
873+
background-size: 142px 20px;
874+
background-repeat: no-repeat;
875+
}
876+
.js-flavor-selector ~ .cjs {
877+
background-image: url(./js-flavor-cjs.svg);
878+
}
879+
.js-flavor-selector ~ .mjs {
880+
background-image: url(./js-flavor-esm.svg);
881+
}
835882
}

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
@@ -196,14 +196,16 @@ function linkJsTypeDocs(text) {
196196
return parts.join('`');
197197
}
198198

199+
const isJSFlavorSnippet = (node) => node.lang === 'cjs' || node.lang === 'mjs';
200+
199201
// Preprocess headers, stability blockquotes, and YAML blocks.
200202
function preprocessElements({ filename }) {
201203
return (tree) => {
202204
const STABILITY_RE = /(.*:)\s*(\d)([\s\S]*)/;
203205
let headingIndex = -1;
204206
let heading = null;
205207

206-
visit(tree, null, (node, index) => {
208+
visit(tree, null, (node, index, parent) => {
207209
if (node.type === 'heading') {
208210
headingIndex = index;
209211
heading = node;
@@ -213,15 +215,44 @@ function preprocessElements({ filename }) {
213215
`No language set in ${filename}, ` +
214216
`line ${node.position.start.line}`);
215217
}
216-
const language = (node.lang || '').split(' ')[0];
217-
const highlighted = getLanguage(language) ?
218-
highlight(language, node.value).value :
219-
node.value;
218+
const className = isJSFlavorSnippet(node) ?
219+
`language-js ${node.lang}` :
220+
`language-${node.lang}`;
221+
const highlighted =
222+
`<code class='${className}'>` +
223+
(getLanguage(node.lang || '') ?
224+
highlight(node.lang, node.value) : node).value +
225+
'</code>';
220226
node.type = 'html';
221-
node.value = '<pre>' +
222-
`<code class = 'language-${node.lang}'>` +
223-
highlighted +
224-
'</code></pre>';
227+
228+
if (isJSFlavorSnippet(node)) {
229+
const previousNode = parent.children[index - 1] || {};
230+
const nextNode = parent.children[index + 1] || {};
231+
232+
if (!isJSFlavorSnippet(previousNode) &&
233+
isJSFlavorSnippet(nextNode) &&
234+
nextNode.lang !== node.lang) {
235+
// Saving the highlight code as value to be added in the next node.
236+
node.value = highlighted;
237+
} else if (isJSFlavorSnippet(previousNode)) {
238+
node.value = '<pre>' +
239+
'<input class="js-flavor-selector" type="checkbox"' +
240+
// If CJS comes in second, ESM should display by default.
241+
(node.lang === 'cjs' ? ' checked' : '') +
242+
' aria-label="Show modern ES modules syntax">' +
243+
previousNode.value +
244+
highlighted +
245+
'</pre>';
246+
node.lang = null;
247+
previousNode.value = '';
248+
previousNode.lang = null;
249+
} else {
250+
// Isolated JS snippet, no need to add the checkbox.
251+
node.value = `<pre>${highlighted}</pre>`;
252+
}
253+
} else {
254+
node.value = `<pre>${highlighted}</pre>`;
255+
}
225256
} else if (node.type === 'html' && common.isYAMLBlock(node.value)) {
226257
node.value = parseYAML(node.value);
227258

0 commit comments

Comments
 (0)