487 lines
13 KiB
JavaScript
487 lines
13 KiB
JavaScript
"use strict";
|
|
|
|
Object.defineProperty(exports, "__esModule", {
|
|
value: true
|
|
});
|
|
exports.default = void 0;
|
|
|
|
function _helperPluginUtils() {
|
|
const data = require("@babel/helper-plugin-utils");
|
|
|
|
_helperPluginUtils = function () {
|
|
return data;
|
|
};
|
|
|
|
return data;
|
|
}
|
|
|
|
function _helperFunctionName() {
|
|
const data = _interopRequireDefault(require("@babel/helper-function-name"));
|
|
|
|
_helperFunctionName = function () {
|
|
return data;
|
|
};
|
|
|
|
return data;
|
|
}
|
|
|
|
function _pluginSyntaxClassProperties() {
|
|
const data = _interopRequireDefault(require("@babel/plugin-syntax-class-properties"));
|
|
|
|
_pluginSyntaxClassProperties = function () {
|
|
return data;
|
|
};
|
|
|
|
return data;
|
|
}
|
|
|
|
function _core() {
|
|
const data = require("@babel/core");
|
|
|
|
_core = function () {
|
|
return data;
|
|
};
|
|
|
|
return data;
|
|
}
|
|
|
|
function _helperReplaceSupers() {
|
|
const data = require("@babel/helper-replace-supers");
|
|
|
|
_helperReplaceSupers = function () {
|
|
return data;
|
|
};
|
|
|
|
return data;
|
|
}
|
|
|
|
function _helperMemberExpressionToFunctions() {
|
|
const data = _interopRequireDefault(require("@babel/helper-member-expression-to-functions"));
|
|
|
|
_helperMemberExpressionToFunctions = function () {
|
|
return data;
|
|
};
|
|
|
|
return data;
|
|
}
|
|
|
|
function _helperOptimiseCallExpression() {
|
|
const data = _interopRequireDefault(require("@babel/helper-optimise-call-expression"));
|
|
|
|
_helperOptimiseCallExpression = function () {
|
|
return data;
|
|
};
|
|
|
|
return data;
|
|
}
|
|
|
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
|
|
var _default = (0, _helperPluginUtils().declare)((api, options) => {
|
|
api.assertVersion(7);
|
|
const {
|
|
loose
|
|
} = options;
|
|
|
|
const findBareSupers = _core().traverse.visitors.merge([{
|
|
Super(path) {
|
|
const {
|
|
node,
|
|
parentPath
|
|
} = path;
|
|
|
|
if (parentPath.isCallExpression({
|
|
callee: node
|
|
})) {
|
|
this.push(parentPath);
|
|
}
|
|
}
|
|
|
|
}, _helperReplaceSupers().environmentVisitor]);
|
|
|
|
const referenceVisitor = {
|
|
"TSTypeAnnotation|TypeAnnotation"(path) {
|
|
path.skip();
|
|
},
|
|
|
|
ReferencedIdentifier(path) {
|
|
if (this.scope.hasOwnBinding(path.node.name)) {
|
|
this.scope.rename(path.node.name);
|
|
path.skip();
|
|
}
|
|
}
|
|
|
|
};
|
|
|
|
const classFieldDefinitionEvaluationTDZVisitor = _core().traverse.visitors.merge([{
|
|
ReferencedIdentifier(path) {
|
|
if (this.classRef === path.scope.getBinding(path.node.name)) {
|
|
const classNameTDZError = this.file.addHelper("classNameTDZError");
|
|
|
|
const throwNode = _core().types.callExpression(classNameTDZError, [_core().types.stringLiteral(path.node.name)]);
|
|
|
|
path.replaceWith(_core().types.sequenceExpression([throwNode, path.node]));
|
|
path.skip();
|
|
}
|
|
}
|
|
|
|
}, _helperReplaceSupers().environmentVisitor]);
|
|
|
|
const privateNameVisitor = {
|
|
PrivateName(path) {
|
|
const {
|
|
name
|
|
} = this;
|
|
const {
|
|
node,
|
|
parentPath
|
|
} = path;
|
|
if (!parentPath.isMemberExpression({
|
|
property: node
|
|
})) return;
|
|
if (node.id.name !== name) return;
|
|
this.handle(parentPath);
|
|
},
|
|
|
|
Class(path) {
|
|
const {
|
|
name
|
|
} = this;
|
|
const body = path.get("body.body");
|
|
|
|
for (const prop of body) {
|
|
if (!prop.isClassPrivateProperty()) continue;
|
|
if (prop.node.key.id.name !== name) continue;
|
|
path.traverse(privateNameInnerVisitor, this);
|
|
path.skip();
|
|
break;
|
|
}
|
|
}
|
|
|
|
};
|
|
|
|
const privateNameInnerVisitor = _core().traverse.visitors.merge([{
|
|
PrivateName: privateNameVisitor.PrivateName
|
|
}, _helperReplaceSupers().environmentVisitor]);
|
|
|
|
const privateNameHandlerSpec = {
|
|
memoise(member, count) {
|
|
const {
|
|
scope
|
|
} = member;
|
|
const {
|
|
object
|
|
} = member.node;
|
|
const memo = scope.maybeGenerateMemoised(object);
|
|
|
|
if (!memo) {
|
|
return;
|
|
}
|
|
|
|
this.memoiser.set(object, memo, count);
|
|
},
|
|
|
|
receiver(member) {
|
|
const {
|
|
object
|
|
} = member.node;
|
|
|
|
if (this.memoiser.has(object)) {
|
|
return _core().types.cloneNode(this.memoiser.get(object));
|
|
}
|
|
|
|
return _core().types.cloneNode(object);
|
|
},
|
|
|
|
get(member) {
|
|
const {
|
|
map,
|
|
file
|
|
} = this;
|
|
return _core().types.callExpression(file.addHelper("classPrivateFieldGet"), [this.receiver(member), _core().types.cloneNode(map)]);
|
|
},
|
|
|
|
set(member, value) {
|
|
const {
|
|
map,
|
|
file
|
|
} = this;
|
|
return _core().types.callExpression(file.addHelper("classPrivateFieldSet"), [this.receiver(member), _core().types.cloneNode(map), value]);
|
|
},
|
|
|
|
call(member, args) {
|
|
this.memoise(member, 1);
|
|
return (0, _helperOptimiseCallExpression().default)(this.get(member), this.receiver(member), args);
|
|
}
|
|
|
|
};
|
|
const privateNameHandlerLoose = {
|
|
handle(member) {
|
|
const {
|
|
prop,
|
|
file
|
|
} = this;
|
|
const {
|
|
object
|
|
} = member.node;
|
|
member.replaceWith(_core().template.expression`BASE(REF, PROP)[PROP]`({
|
|
BASE: file.addHelper("classPrivateFieldLooseBase"),
|
|
REF: object,
|
|
PROP: prop
|
|
}));
|
|
}
|
|
|
|
};
|
|
|
|
function buildClassPropertySpec(ref, path, state) {
|
|
const {
|
|
scope
|
|
} = path;
|
|
const {
|
|
key,
|
|
value,
|
|
computed
|
|
} = path.node;
|
|
return _core().types.expressionStatement(_core().types.callExpression(state.addHelper("defineProperty"), [ref, computed || _core().types.isLiteral(key) ? key : _core().types.stringLiteral(key.name), value || scope.buildUndefinedNode()]));
|
|
}
|
|
|
|
function buildClassPropertyLoose(ref, path) {
|
|
const {
|
|
scope
|
|
} = path;
|
|
const {
|
|
key,
|
|
value,
|
|
computed
|
|
} = path.node;
|
|
return _core().types.expressionStatement(_core().types.assignmentExpression("=", _core().types.memberExpression(ref, key, computed || _core().types.isLiteral(key)), value || scope.buildUndefinedNode()));
|
|
}
|
|
|
|
function buildClassPrivatePropertySpec(ref, path, initNodes, state) {
|
|
const {
|
|
parentPath,
|
|
scope
|
|
} = path;
|
|
const {
|
|
name
|
|
} = path.node.key.id;
|
|
const map = scope.generateUidIdentifier(name);
|
|
(0, _helperMemberExpressionToFunctions().default)(parentPath, privateNameVisitor, Object.assign({
|
|
name,
|
|
map,
|
|
file: state
|
|
}, privateNameHandlerSpec));
|
|
initNodes.push(_core().template.statement`var MAP = new WeakMap();`({
|
|
MAP: map
|
|
}));
|
|
return () => _core().template.statement`MAP.set(REF, VALUE);`({
|
|
MAP: map,
|
|
REF: ref,
|
|
VALUE: path.node.value || scope.buildUndefinedNode()
|
|
});
|
|
}
|
|
|
|
function buildClassPrivatePropertyLoose(ref, path, initNodes, state) {
|
|
const {
|
|
parentPath,
|
|
scope
|
|
} = path;
|
|
const {
|
|
name
|
|
} = path.node.key.id;
|
|
const prop = scope.generateUidIdentifier(name);
|
|
parentPath.traverse(privateNameVisitor, Object.assign({
|
|
name,
|
|
prop,
|
|
file: state
|
|
}, privateNameHandlerLoose));
|
|
initNodes.push(_core().template.statement`var PROP = HELPER(NAME);`({
|
|
PROP: prop,
|
|
HELPER: state.addHelper("classPrivateFieldLooseKey"),
|
|
NAME: _core().types.stringLiteral(name)
|
|
}));
|
|
return () => _core().template.statement`
|
|
Object.defineProperty(REF, PROP, {
|
|
// configurable is false by default
|
|
// enumerable is false by default
|
|
writable: true,
|
|
value: VALUE
|
|
});
|
|
`({
|
|
REF: ref,
|
|
PROP: prop,
|
|
VALUE: path.node.value || scope.buildUndefinedNode()
|
|
});
|
|
}
|
|
|
|
const buildClassProperty = loose ? buildClassPropertyLoose : buildClassPropertySpec;
|
|
const buildClassPrivateProperty = loose ? buildClassPrivatePropertyLoose : buildClassPrivatePropertySpec;
|
|
return {
|
|
inherits: _pluginSyntaxClassProperties().default,
|
|
visitor: {
|
|
Class(path, state) {
|
|
const isDerived = !!path.node.superClass;
|
|
let constructor;
|
|
const props = [];
|
|
const computedPaths = [];
|
|
const privateNames = new Set();
|
|
const body = path.get("body");
|
|
|
|
for (const path of body.get("body")) {
|
|
const {
|
|
computed,
|
|
decorators
|
|
} = path.node;
|
|
|
|
if (computed) {
|
|
computedPaths.push(path);
|
|
}
|
|
|
|
if (decorators && decorators.length > 0) {
|
|
throw path.buildCodeFrameError("Decorators transform is necessary.");
|
|
}
|
|
|
|
if (path.isClassPrivateProperty()) {
|
|
const {
|
|
static: isStatic,
|
|
key: {
|
|
id: {
|
|
name
|
|
}
|
|
}
|
|
} = path.node;
|
|
|
|
if (isStatic) {
|
|
throw path.buildCodeFrameError("Static class fields are not spec'ed yet.");
|
|
}
|
|
|
|
if (privateNames.has(name)) {
|
|
throw path.buildCodeFrameError("Duplicate private field");
|
|
}
|
|
|
|
privateNames.add(name);
|
|
}
|
|
|
|
if (path.isProperty()) {
|
|
props.push(path);
|
|
} else if (path.isClassMethod({
|
|
kind: "constructor"
|
|
})) {
|
|
constructor = path;
|
|
}
|
|
}
|
|
|
|
if (!props.length) return;
|
|
let ref;
|
|
|
|
if (path.isClassExpression() || !path.node.id) {
|
|
(0, _helperFunctionName().default)(path);
|
|
ref = path.scope.generateUidIdentifier("class");
|
|
} else {
|
|
ref = path.node.id;
|
|
}
|
|
|
|
const computedNodes = [];
|
|
const staticNodes = [];
|
|
const instanceBody = [];
|
|
|
|
for (const computedPath of computedPaths) {
|
|
computedPath.traverse(classFieldDefinitionEvaluationTDZVisitor, {
|
|
classRef: path.scope.getBinding(ref.name),
|
|
file: this.file
|
|
});
|
|
const computedNode = computedPath.node;
|
|
|
|
if (!computedPath.get("key").isConstantExpression()) {
|
|
const ident = path.scope.generateUidIdentifierBasedOnNode(computedNode.key);
|
|
computedNodes.push(_core().types.variableDeclaration("var", [_core().types.variableDeclarator(ident, computedNode.key)]));
|
|
computedNode.key = _core().types.cloneNode(ident);
|
|
}
|
|
}
|
|
|
|
const privateMaps = [];
|
|
const privateMapInits = [];
|
|
|
|
for (const prop of props) {
|
|
if (prop.isPrivate()) {
|
|
const inits = [];
|
|
privateMapInits.push(inits);
|
|
privateMaps.push(buildClassPrivateProperty(_core().types.thisExpression(), prop, inits, state));
|
|
}
|
|
}
|
|
|
|
let p = 0;
|
|
|
|
for (const prop of props) {
|
|
if (prop.node.static) {
|
|
staticNodes.push(buildClassProperty(_core().types.cloneNode(ref), prop, state));
|
|
} else if (prop.isPrivate()) {
|
|
instanceBody.push(privateMaps[p]());
|
|
staticNodes.push(...privateMapInits[p]);
|
|
p++;
|
|
} else {
|
|
instanceBody.push(buildClassProperty(_core().types.thisExpression(), prop, state));
|
|
}
|
|
}
|
|
|
|
if (instanceBody.length) {
|
|
if (!constructor) {
|
|
const newConstructor = _core().types.classMethod("constructor", _core().types.identifier("constructor"), [], _core().types.blockStatement([]));
|
|
|
|
if (isDerived) {
|
|
newConstructor.params = [_core().types.restElement(_core().types.identifier("args"))];
|
|
newConstructor.body.body.push(_core().types.expressionStatement(_core().types.callExpression(_core().types.super(), [_core().types.spreadElement(_core().types.identifier("args"))])));
|
|
}
|
|
|
|
[constructor] = body.unshiftContainer("body", newConstructor);
|
|
}
|
|
|
|
const state = {
|
|
scope: constructor.scope
|
|
};
|
|
|
|
for (const prop of props) {
|
|
if (prop.node.static) continue;
|
|
prop.traverse(referenceVisitor, state);
|
|
}
|
|
|
|
if (isDerived) {
|
|
const bareSupers = [];
|
|
constructor.traverse(findBareSupers, bareSupers);
|
|
|
|
for (const bareSuper of bareSupers) {
|
|
bareSuper.insertAfter(instanceBody);
|
|
}
|
|
} else {
|
|
constructor.get("body").unshiftContainer("body", instanceBody);
|
|
}
|
|
}
|
|
|
|
for (const prop of props) {
|
|
prop.remove();
|
|
}
|
|
|
|
if (computedNodes.length === 0 && staticNodes.length === 0) return;
|
|
|
|
if (path.isClassExpression()) {
|
|
path.scope.push({
|
|
id: ref
|
|
});
|
|
path.replaceWith(_core().types.assignmentExpression("=", _core().types.cloneNode(ref), path.node));
|
|
} else if (!path.node.id) {
|
|
path.node.id = ref;
|
|
}
|
|
|
|
path.insertBefore(computedNodes);
|
|
path.insertAfter(staticNodes);
|
|
},
|
|
|
|
PrivateName(path) {
|
|
throw path.buildCodeFrameError(`Unknown PrivateName "${path}"`);
|
|
}
|
|
|
|
}
|
|
};
|
|
});
|
|
|
|
exports.default = _default; |