Skip to content

Commit a90f230

Browse files
authored
feat: examples infrastructure
Close #24
1 parent 93d14e2 commit a90f230

File tree

8 files changed

+224
-14
lines changed

8 files changed

+224
-14
lines changed

.markdownlint.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,6 @@
2323
"br_spaces": 0
2424
},
2525
"single-h1": false,
26-
"no-inline-html": false
26+
"no-inline-html": false,
27+
"ul-style": false
2728
}

.vscode/launch.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@
1515
],
1616
"skipFiles": [
1717
"<node_internals>/**"
18-
]
18+
],
19+
"console": "integratedTerminal"
1920
},
2021
{
2122
"type": "pwa-node",

README.md

Lines changed: 75 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,13 @@ This repository contains the code and contents of https://crossplatform.dev.
66

77
It is built using [Docusaurus 2](https://docusaurus.io/) and deployed on Netlify.
88

9+
Table of contents:
10+
11+
* [Installation](#installation)
12+
* [Local development](#local-development)
13+
* [Writing code examples](#writing-code-examples)
14+
* [Adding a new technology](#adding-a-new-technology)
15+
916
## Installation
1017

1118
To install it locally, you will need to:
@@ -47,6 +54,58 @@ npm start
4754
Most changes, like markdown modifications, `sidebars.js`, etc. are
4855
reflected live without having to restart the server.
4956

57+
## Writing code examples
58+
59+
The website also has a couple remark plugins that make it easier to have examples side by side.
60+
They live under the [`/src/transformers`][transformers] folder:
61+
62+
- `import-code` allows you to reference a code file an "import" it automatically when building
63+
the website. This is useful to separate the code from the text. You can use it as follows:
64+
65+
````md
66+
Look at this JavaScript code:
67+
68+
```js (./path/to/code.js)
69+
```
70+
````
71+
72+
The contents of `./path/to/code.js` will be loaded and place inside the codeblock using the
73+
indicated language. There is no need to have any content in the codeblock.
74+
75+
- `partial-content` allows you to include the contents of a markdown file into another file. That
76+
way you can have a markdown file per technology:
77+
78+
```md
79+
# This is an example
80+
81+
{@import ./path/to/example.pmd}
82+
```
83+
84+
Although the extension is `.pmd` (Partial MarkDown), the contents are the same as a regular
85+
markdown file. The reason to change the extension is to avoid building it with Docusaurus.
86+
When using it in combination with [Docusaurus tabs] and writting MDX, you can end up with
87+
something like the following:
88+
89+
```jsx
90+
import Tabs from '@theme/Tabs';
91+
import TabItem from '@theme/TabItem';
92+
93+
<Tabs>
94+
<TabItem value="electron" label="Electron" default>
95+
{@import ./electron.pmd}
96+
</TabItem>
97+
<TabItem value="pwa" label="PWA">
98+
{@import ./pwa.pmd}
99+
</TabItem>
100+
<TabItem value="wv2" label="WebView2">
101+
{@import ./wv2.pmd}
102+
</TabItem>
103+
</Tabs>;
104+
```
105+
106+
`partial-content` files can also make use of `import-code`.
107+
108+
50109
## Adding a new technology
51110
52111
To create a new technology overview, run the following command:
@@ -57,10 +116,10 @@ npm run add-technology
57116
58117
You will be prompted the technology name and once provided:
59118
60-
* a new folder will be created under `/docs/` with its name
61-
* the folder will have a few markdown files for you to complete
62-
* `sidebars.js` will be updated to include the new technology
63-
* a new file will be created under `/data/technologies/TECHNOLOGY.js`
119+
- a new folder will be created under `/docs/` with its name
120+
- the folder will have a few markdown files for you to complete
121+
- `sidebars.js` will be updated to include the new technology
122+
- a new file will be created under `/data/technologies/TECHNOLOGY.js`
64123
for you to complete
65124
66125
![video of "npm run add-technology" running](./static/img/add-technology.webp)
@@ -175,9 +234,10 @@ and it will generate a table using the property names of the 1st
175234
object as the column names, adding a new line per item in the Array:
176235
177236
```markdown
178-
| Version | Date |
179-
| --- | --- |
180-
| vX.Y.Z | 2021/10/01 |
237+
| Version | Date |
238+
| ------- | ---------- |
239+
| vX.Y.Z | 2021/10/01 |
240+
181241
...
182242
```
183243
@@ -191,10 +251,15 @@ and the output will be:
191251
192252
```markdown
193253
| Version |
194-
| --- |
195-
| vX.Y.Z |
254+
| ------- |
255+
| vX.Y.Z |
256+
196257
...
197258
```
198259
260+
<!-- Reference links -->
261+
262+
[Docusaurus tabs]: https://docusaurus.io/docs/markdown-features/tabs
199263
[git]: https://git-scm.com/downloads
200-
[node.js]: https://nodejs.org/en/download/
264+
[node.js]: https://nodejs.org/en/download/
265+
[transformers]: https://github.com/crossplatform-dev/crossplatform.dev/tree/main/src/transformers

docusaurus.config.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
const interpolateData = require('./src/transformers/interpolate-data');
2+
const importCode = require('./src/transformers/import-code');
3+
const partialContent = require('./src/transformers/partial-content');
24

35
/** @type {import('@docusaurus/types').DocusaurusConfig} */
46
module.exports = {
@@ -101,7 +103,7 @@ module.exports = {
101103
// Please change this to your repo.
102104
editUrl:
103105
'https://github.com/crossplatform-dev/crossplatform.dev/edit/main/',
104-
remarkPlugins: [interpolateData],
106+
remarkPlugins: [importCode, partialContent, interpolateData],
105107
},
106108
// blog: {
107109
// showReadingTime: true,

package-lock.json

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
"markdownlint-cli": "^0.28.1",
5454
"pluralize": "^8.0.0",
5555
"prettier": "^2.3.2",
56-
"semver": "^7.3.5"
56+
"semver": "^7.3.5",
57+
"unist-util-visit-children": "^1.1.4"
5758
}
5859
}

src/transformers/import-code.js

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// Initial code from https://github.com/unlight/remark-sources/blob/8b4ca174d276c2b66ae98c817f87f9ab3fc1b3a5/index.js
2+
// Licensed under MIT
3+
4+
const fs = require('fs').promises;
5+
const { resolve } = require('path');
6+
7+
const visitChildren = require('unist-util-visit-children');
8+
9+
const regExp = new RegExp(/^[^\(]*\(([^\)]+)\)$/);
10+
11+
const replace = async (node, filePath) => {
12+
try {
13+
const content = await fs.readFile(filePath, { encoding: 'utf-8' });
14+
if (content !== undefined) {
15+
node.value = content.trim();
16+
17+
return true;
18+
}
19+
} catch (e) {
20+
node.value = `Failed to read file: ${filePath}`;
21+
22+
return false;
23+
}
24+
};
25+
26+
/**
27+
* Replaces all the codeblock instances on a markdown document that point
28+
* to a file with the contents of that file.
29+
*/
30+
const attacher = () => {
31+
const transformer = async (tree, file) => {
32+
const replacements = [];
33+
34+
const visitor = visitChildren((node) => {
35+
if (node && node.type === 'code' && node.meta) {
36+
const filePath = (regExp.exec(node.meta) || [])[1];
37+
38+
// Regular codeblock with no information between parenthesis
39+
if (!filePath) {
40+
return;
41+
}
42+
43+
const absPath = resolve(file.dirname, filePath);
44+
45+
replacements.push(replace(node, absPath));
46+
}
47+
});
48+
49+
visitor(tree);
50+
51+
await Promise.all(replacements);
52+
};
53+
54+
return transformer;
55+
};
56+
57+
module.exports = attacher;

src/transformers/partial-content.js

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
// Initial code from https://github.com/unlight/remark-sources/blob/8b4ca174d276c2b66ae98c817f87f9ab3fc1b3a5/index.js
2+
// Licensed under MIT
3+
4+
const fs = require('fs').promises;
5+
const { resolve } = require('path');
6+
7+
const unified = require('unified');
8+
const visitChildren = require('unist-util-visit-children');
9+
const toMDAST = require('remark-parse');
10+
const vfile = require('vfile');
11+
const importCode = require('./import-code');
12+
13+
const regExp = /{@import (.*?\.pmd)}/;
14+
const processor = unified().use(toMDAST).use(importCode);
15+
16+
const replace = async (node, filePath) => {
17+
try {
18+
const content = await fs.readFile(filePath, { encoding: 'utf-8' });
19+
if (content !== undefined) {
20+
const file = vfile({
21+
path: filePath,
22+
contents: content,
23+
});
24+
25+
const partialTree = processor.parse(file);
26+
const doc = await processor.run(partialTree, file);
27+
28+
node.children = doc.children;
29+
}
30+
} catch (e) {
31+
node.children[0].value = `Failed to read file: ${filePath}`;
32+
}
33+
};
34+
35+
/**
36+
* This is a unified plugin that Transforms all the instances
37+
* of `{@import ./relative/path.pmd}` with the contents of
38+
* `./relative/path.pmd`, which has to be a regular markdown file.
39+
*
40+
* Additionally, it also uses the plugin import-code in this same
41+
* repository.
42+
*/
43+
const attacher = () => {
44+
45+
const transformer = async (tree, file) => {
46+
const replacements = [];
47+
48+
const visit = visitChildren((node) => {
49+
if (!node || node.type !== 'paragraph') {
50+
return;
51+
}
52+
53+
if (!node.children[0] || node.children[0].type !== 'text') {
54+
return;
55+
}
56+
57+
const filePath = (regExp.exec(node.children[0].value) || [])[1];
58+
59+
// No import statement in the paragraph
60+
if (!filePath) {
61+
return;
62+
}
63+
64+
const absPath = resolve(file.dirname, filePath);
65+
66+
replacements.push(replace(node, absPath))
67+
});
68+
69+
visit(tree);
70+
71+
await Promise.all(replacements);
72+
};
73+
74+
return transformer;
75+
};
76+
77+
module.exports = attacher;

0 commit comments

Comments
 (0)