-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdemo-loader.webpack.cjs
107 lines (93 loc) · 2.83 KB
/
demo-loader.webpack.cjs
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
const path = require('path');
const babel = require('@babel/core');
const parser = require('@babel/parser');
const traverse = require('@babel/traverse');
module.exports = function demoLoader(source) {
const callback = this.async();
const parsed = parser.parse(source, {
sourceType: 'module',
plugins: ['typescript', 'jsx'],
});
const IJSImport = {};
traverse.default(parsed, {
enter(node) {
if (node.type === 'ImportDeclaration') {
if (node.node.source.value !== 'image-js') {
throw new Error(
'demos must not import from anything else than image-js',
);
}
for (let specifier of node.node.specifiers) {
IJSImport[specifier.local.name] = specifier.imported.name;
}
}
},
});
const body = parsed.program.body;
const defaultExport = body.find(
(node) => node.type === 'ExportDefaultDeclaration',
);
if (!defaultExport) {
throw new Error('demos must export a default function');
}
const declarationBody = defaultExport.declaration.body;
let processBody = source.slice(
declarationBody.body[0].start,
declarationBody.body[declarationBody.body.length - 1].end,
);
for (let key of Object.keys(IJSImport)) {
processBody = processBody.replaceAll(
new RegExp(`(^|[^a-zA-Z0-9])(${key})([^a-zA-Z0-9]|$)`, 'g'),
(...m) => {
return `${m[1]}IJS.${IJSImport[key]}${m[3]}`;
},
);
}
const isMask = this.resourcePath.endsWith('.mask.demo.tsx');
const editorCode = `import * as IJS from 'image-js';
/**
* Process the image
* @param { IJS.${isMask ? 'Mask } mask' : 'Image } image'} the input image
* @returns { IJS.Image | IJS.Mask } the processed image or mask
*/
export function process(${isMask ? 'mask' : 'image'}) {
${processBody}
}
`;
let imageDemoImportPath = path
.relative(
this.context,
path.join('src', 'demo', 'components', 'ImageDemo.tsx'),
)
.replaceAll(path.sep, path.posix.sep);
const depth = imageDemoImportPath.split('/').length - 1;
if (depth === 0) {
imageDemoImportPath = `./${imageDemoImportPath}`;
}
const modifiedSource = `
import React from 'react';
import ImageDemo from '${imageDemoImportPath}';
function process(image, IJS) {
${processBody}
}
const name = '${this.resourcePath}';
const code = \`${source}\`;
const defaultEditorCode= \`${editorCode}\`;
export default function Demo(props) {
return (
<ImageDemo code={code} defaultEditorCode={defaultEditorCode} processImage={process} name={name} isMask={${
isMask ? 'true' : 'false'
}} {...props} />
);
}
`;
babel
.transformAsync(modifiedSource, {
filename: this.resourcePath,
presets: ['@babel/preset-typescript'],
})
.then((result) => {
callback(null, result.code);
})
.catch((e) => callback(e));
};