UNPKG

8.12 kBJavaScriptView Raw
1"use strict";
2
3Object.defineProperty(exports, "__esModule", {
4 value: true
5});
6exports.default = void 0;
7
8var _core = require("@babel/core");
9
10const buildClassDecorator = (0, _core.template)(`
11 DECORATOR(CLASS_REF = INNER) || CLASS_REF;
12`);
13const buildClassPrototype = (0, _core.template)(`
14 CLASS_REF.prototype;
15`);
16const buildGetDescriptor = (0, _core.template)(`
17 Object.getOwnPropertyDescriptor(TARGET, PROPERTY);
18`);
19const buildGetObjectInitializer = (0, _core.template)(`
20 (TEMP = Object.getOwnPropertyDescriptor(TARGET, PROPERTY), (TEMP = TEMP ? TEMP.value : undefined), {
21 enumerable: true,
22 configurable: true,
23 writable: true,
24 initializer: function(){
25 return TEMP;
26 }
27 })
28`);
29const WARNING_CALLS = new WeakSet();
30
31function applyEnsureOrdering(path) {
32 const decorators = (path.isClass() ? [path].concat(path.get("body.body")) : path.get("properties")).reduce((acc, prop) => acc.concat(prop.node.decorators || []), []);
33 const identDecorators = decorators.filter(decorator => !_core.types.isIdentifier(decorator.expression));
34 if (identDecorators.length === 0) return;
35 return _core.types.sequenceExpression(identDecorators.map(decorator => {
36 const expression = decorator.expression;
37 const id = decorator.expression = path.scope.generateDeclaredUidIdentifier("dec");
38 return _core.types.assignmentExpression("=", id, expression);
39 }).concat([path.node]));
40}
41
42function applyClassDecorators(classPath) {
43 if (!hasClassDecorators(classPath.node)) return;
44 const decorators = classPath.node.decorators || [];
45 classPath.node.decorators = null;
46 const name = classPath.scope.generateDeclaredUidIdentifier("class");
47 return decorators.map(dec => dec.expression).reverse().reduce(function (acc, decorator) {
48 return buildClassDecorator({
49 CLASS_REF: _core.types.cloneNode(name),
50 DECORATOR: _core.types.cloneNode(decorator),
51 INNER: acc
52 }).expression;
53 }, classPath.node);
54}
55
56function hasClassDecorators(classNode) {
57 return !!(classNode.decorators && classNode.decorators.length);
58}
59
60function applyMethodDecorators(path, state) {
61 if (!hasMethodDecorators(path.node.body.body)) return;
62 return applyTargetDecorators(path, state, path.node.body.body);
63}
64
65function hasMethodDecorators(body) {
66 return body.some(node => {
67 var _node$decorators;
68
69 return (_node$decorators = node.decorators) == null ? void 0 : _node$decorators.length;
70 });
71}
72
73function applyObjectDecorators(path, state) {
74 if (!hasMethodDecorators(path.node.properties)) return;
75 return applyTargetDecorators(path, state, path.node.properties);
76}
77
78function applyTargetDecorators(path, state, decoratedProps) {
79 const name = path.scope.generateDeclaredUidIdentifier(path.isClass() ? "class" : "obj");
80 const exprs = decoratedProps.reduce(function (acc, node) {
81 const decorators = node.decorators || [];
82 node.decorators = null;
83 if (decorators.length === 0) return acc;
84
85 if (node.computed) {
86 throw path.buildCodeFrameError("Computed method/property decorators are not yet supported.");
87 }
88
89 const property = _core.types.isLiteral(node.key) ? node.key : _core.types.stringLiteral(node.key.name);
90 const target = path.isClass() && !node.static ? buildClassPrototype({
91 CLASS_REF: name
92 }).expression : name;
93
94 if (_core.types.isClassProperty(node, {
95 static: false
96 })) {
97 const descriptor = path.scope.generateDeclaredUidIdentifier("descriptor");
98 const initializer = node.value ? _core.types.functionExpression(null, [], _core.types.blockStatement([_core.types.returnStatement(node.value)])) : _core.types.nullLiteral();
99 node.value = _core.types.callExpression(state.addHelper("initializerWarningHelper"), [descriptor, _core.types.thisExpression()]);
100 WARNING_CALLS.add(node.value);
101 acc = acc.concat([_core.types.assignmentExpression("=", descriptor, _core.types.callExpression(state.addHelper("applyDecoratedDescriptor"), [_core.types.cloneNode(target), _core.types.cloneNode(property), _core.types.arrayExpression(decorators.map(dec => _core.types.cloneNode(dec.expression))), _core.types.objectExpression([_core.types.objectProperty(_core.types.identifier("configurable"), _core.types.booleanLiteral(true)), _core.types.objectProperty(_core.types.identifier("enumerable"), _core.types.booleanLiteral(true)), _core.types.objectProperty(_core.types.identifier("writable"), _core.types.booleanLiteral(true)), _core.types.objectProperty(_core.types.identifier("initializer"), initializer)])]))]);
102 } else {
103 acc = acc.concat(_core.types.callExpression(state.addHelper("applyDecoratedDescriptor"), [_core.types.cloneNode(target), _core.types.cloneNode(property), _core.types.arrayExpression(decorators.map(dec => _core.types.cloneNode(dec.expression))), _core.types.isObjectProperty(node) || _core.types.isClassProperty(node, {
104 static: true
105 }) ? buildGetObjectInitializer({
106 TEMP: path.scope.generateDeclaredUidIdentifier("init"),
107 TARGET: _core.types.cloneNode(target),
108 PROPERTY: _core.types.cloneNode(property)
109 }).expression : buildGetDescriptor({
110 TARGET: _core.types.cloneNode(target),
111 PROPERTY: _core.types.cloneNode(property)
112 }).expression, _core.types.cloneNode(target)]));
113 }
114
115 return acc;
116 }, []);
117 return _core.types.sequenceExpression([_core.types.assignmentExpression("=", _core.types.cloneNode(name), path.node), _core.types.sequenceExpression(exprs), _core.types.cloneNode(name)]);
118}
119
120function decoratedClassToExpression({
121 node,
122 scope
123}) {
124 if (!hasClassDecorators(node) && !hasMethodDecorators(node.body.body)) {
125 return;
126 }
127
128 const ref = node.id ? _core.types.cloneNode(node.id) : scope.generateUidIdentifier("class");
129 return _core.types.variableDeclaration("let", [_core.types.variableDeclarator(ref, _core.types.toExpression(node))]);
130}
131
132var _default = {
133 ExportDefaultDeclaration(path) {
134 const decl = path.get("declaration");
135 if (!decl.isClassDeclaration()) return;
136 const replacement = decoratedClassToExpression(decl);
137
138 if (replacement) {
139 const [varDeclPath] = path.replaceWithMultiple([replacement, _core.types.exportNamedDeclaration(null, [_core.types.exportSpecifier(_core.types.cloneNode(replacement.declarations[0].id), _core.types.identifier("default"))])]);
140
141 if (!decl.node.id) {
142 path.scope.registerDeclaration(varDeclPath);
143 }
144 }
145 },
146
147 ClassDeclaration(path) {
148 const replacement = decoratedClassToExpression(path);
149
150 if (replacement) {
151 path.replaceWith(replacement);
152 }
153 },
154
155 ClassExpression(path, state) {
156 const decoratedClass = applyEnsureOrdering(path) || applyClassDecorators(path, state) || applyMethodDecorators(path, state);
157 if (decoratedClass) path.replaceWith(decoratedClass);
158 },
159
160 ObjectExpression(path, state) {
161 const decoratedObject = applyEnsureOrdering(path) || applyObjectDecorators(path, state);
162 if (decoratedObject) path.replaceWith(decoratedObject);
163 },
164
165 AssignmentExpression(path, state) {
166 if (!WARNING_CALLS.has(path.node.right)) return;
167 path.replaceWith(_core.types.callExpression(state.addHelper("initializerDefineProperty"), [_core.types.cloneNode(path.get("left.object").node), _core.types.stringLiteral(path.get("left.property").node.name || path.get("left.property").node.value), _core.types.cloneNode(path.get("right.arguments")[0].node), _core.types.cloneNode(path.get("right.arguments")[1].node)]));
168 },
169
170 CallExpression(path, state) {
171 if (path.node.arguments.length !== 3) return;
172 if (!WARNING_CALLS.has(path.node.arguments[2])) return;
173
174 if (path.node.callee.name !== state.addHelper("defineProperty").name) {
175 return;
176 }
177
178 path.replaceWith(_core.types.callExpression(state.addHelper("initializerDefineProperty"), [_core.types.cloneNode(path.get("arguments")[0].node), _core.types.cloneNode(path.get("arguments")[1].node), _core.types.cloneNode(path.get("arguments.2.arguments")[0].node), _core.types.cloneNode(path.get("arguments.2.arguments")[1].node)]));
179 }
180
181};
182exports.default = _default;
\No newline at end of file