forked from zakodium-oss/react-plot-docs
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdemo-loader.webpack.js
123 lines (113 loc) · 3.63 KB
/
demo-loader.webpack.js
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
const path = require('path');
const pkg = require('./package.json');
const changeCase = require('change-case');
const babel = require('@babel/core');
const parser = require('@babel/parser');
module.exports = function demoLoader(source) {
const callback = this.async();
const parsed = parser.parse(source, {
sourceType: 'module',
plugins: ['typescript', 'jsx'],
});
const parsedAll = parsed.program.body;
const defaultExport = parsedAll.find(
(node) => node.type === 'ExportDefaultDeclaration',
);
const parsedBeforeDefaultExport = parsedAll.slice(0, parsedAll.length - 1);
const parsedImports = parsedBeforeDefaultExport.filter(
(statement) => statement.type === 'ImportDeclaration',
);
const defaultDeclaration = defaultExport.declaration;
if (
!defaultDeclaration ||
defaultDeclaration.type !== 'FunctionDeclaration'
) {
throw new Error(
`
example should have a default export of function declaration.
Example:
// import statements
import React from 'react';
import Plot from 'react-plot';
// Default export of function declaration
export default function Example(){};
`,
);
}
const codeSandboxDependencies = parsedImports.reduce((prev, current) => {
const source = current.source.value;
if (source.startsWith('.')) {
console.warn(
`in ${this.resourcePath}, import statements with relative path will not work in code sandbox`,
);
} else {
prev[source] = pkg.dependencies[source];
}
return prev;
}, {});
const functionComponentSource = source.slice(
defaultDeclaration.start,
defaultDeclaration.end,
);
const beforeDefaultExportSource = source.slice(0, defaultExport.start);
const afterDefaultExportSource = source.slice(defaultExport.end);
const name = changeCase.paramCase(
defaultDeclaration.id?.name || 'ReactPlotDemo',
);
const codeSandboxImportPath = path
.relative(this.context, path.join('src', 'components', 'CodeSandboxer.tsx'))
.replaceAll(path.sep, path.posix.sep);
const modifiedSource = `
${beforeDefaultExportSource}
import { useState as __useState__ } from 'react';
import CodeBlock from '@theme/CodeBlock';
import CodeSandboxer from '${codeSandboxImportPath}';
const exampleSource = ${JSON.stringify(source)};
const __EXAMPLE__ = ${functionComponentSource}
export default function __EXAMPLE_DEMO__(props) {
const [showCode, setShowCode] = __useState__(false);
return (
<>
<div className="demo-example-wrapper">
<__EXAMPLE__ />
<div className="demo-example-buttons">
<button
onClick={() => setShowCode((show) => !show)}
type="button"
style={{
backgroundColor: showCode ? '#dbeafe' : undefined,
}}
>
Code
</button>
{props.noCodesandbox ? null : (
<CodeSandboxer
name="${name}"
source={exampleSource}
dependencies={${JSON.stringify(codeSandboxDependencies)}}
>
{() => {
return <button type="submit">Open sandbox</button>;
}}
</CodeSandboxer>
)}
</div>
</div>
{showCode && (
<CodeBlock className="language-jsx">{exampleSource}</CodeBlock>
)}
</>
);
}
${afterDefaultExportSource}
`;
babel
.transformAsync(modifiedSource, {
filename: this.resourcePath,
presets: ['@babel/preset-typescript'],
})
.then((result) => {
callback(null, result.code);
})
.catch((e) => callback(e));
};