-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathbabel-plugin-native-class.js
70 lines (60 loc) · 2 KB
/
babel-plugin-native-class.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
const ts = require('typescript');
const parser = require('@babel/parser');
module.exports = function () {
return {
name: 'babel-plugin-native-class',
visitor: {
Program(path) {
path.traverse({
ClassDeclaration(classPath) {
const { node } = classPath;
if (hasNativeClassDecorator(node)) {
const tsSource = classPath.hub.file.code;
const transpiledCode = transpileClassToES5(node, tsSource);
if (transpiledCode) {
const babelAst = parser.parse(transpiledCode, {
sourceType: 'module',
plugins: ['typescript', 'decorators-legacy'],
}).program.body;
classPath.replaceWithMultiple(babelAst);
}
}
},
});
},
},
};
};
function hasNativeClassDecorator(node) {
return (
node.decorators &&
node.decorators.some(decorator => {
const expression = decorator.expression;
return expression.name === 'NativeClass' || (expression.callee && expression.callee.name === 'NativeClass');
})
);
}
function removeNativeClassDecorator(code, className) {
const decoratorRegex = new RegExp(`@NativeClass(\\((.|\\n)*?\\))?\\s*class\\s+${className}`, 'gm');
return code.replace(decoratorRegex, `class ${className}`);
}
function transpileClassToES5(node, sourceCode) {
const className = node.id.name;
const classStart = node.start;
const classEnd = node.end;
const classCode = sourceCode.slice(classStart, classEnd);
const cleanedCode = removeNativeClassDecorator(classCode, className);
const transpiled = ts.transpileModule(cleanedCode, {
compilerOptions: {
noEmitHelpers: true,
module: ts.ModuleKind.ESNext,
target: ts.ScriptTarget.ES5,
experimentalDecorators: true,
emitDecoratorMetadata: true,
},
});
return transpiled.outputText.replace(
/(Object\.defineProperty\(.*?{.*?)(enumerable:\s*false)(.*?}\))/gs,
'$1enumerable: true$3'
);
}