Allow version: "legacy", use built-in Identifier generation, simplify private UID code
This commit is contained in:
parent
3e8ba6782e
commit
690846ca9e
@ -194,7 +194,10 @@ module.exports = function (api) {
|
|||||||
assumptions: parserAssumptions,
|
assumptions: parserAssumptions,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
test: ["packages/babel-generator"].map(normalize),
|
test: [
|
||||||
|
"packages/babel-generator",
|
||||||
|
"packages/babel-plugin-proposal-decorators",
|
||||||
|
].map(normalize),
|
||||||
plugins: ["babel-plugin-transform-charcodes"],
|
plugins: ["babel-plugin-transform-charcodes"],
|
||||||
},
|
},
|
||||||
convertESM && {
|
convertESM && {
|
||||||
|
|||||||
@ -37,9 +37,11 @@ export default declare((api, options) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (legacy) {
|
if (version === "legacy" || legacy) {
|
||||||
if (version !== undefined) {
|
if (version !== undefined && legacy) {
|
||||||
throw new Error("'version' can't be used with legacy decorators");
|
throw new Error(
|
||||||
|
'You can either specify `legacy: true` or `version: "legacy"` with decorators, not both.',
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@ -40,20 +40,16 @@ function incrementId(id: number[], idx = id.length - 1): void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates a new element name that is unique to the given class. This can be
|
* Generates a new private name that is unique to the given class. This can be
|
||||||
* used to create extra class fields and methods for the implementation, while
|
* used to create extra class fields and methods for the implementation, while
|
||||||
* keeping the length of those names as small as possible. This is important for
|
* keeping the length of those names as small as possible. This is important for
|
||||||
* minification purposes, since public names cannot be safely renamed/minified.
|
* minification purposes (though private names can generally be minified,
|
||||||
*
|
* transpilations and polyfills cannot yet).
|
||||||
* Names are split into two namespaces, public and private. Static and non-static
|
|
||||||
* names are shared in the same namespace, because this is true for private names
|
|
||||||
* (you cannot have #x and static #x in the same class) and it's not worth the
|
|
||||||
* extra complexity for public names.
|
|
||||||
*/
|
*/
|
||||||
function createPrivateUidGeneratorForClass(
|
function createPrivateUidGeneratorForClass(
|
||||||
classPath: NodePath<t.ClassDeclaration | t.ClassExpression>,
|
classPath: NodePath<t.ClassDeclaration | t.ClassExpression>,
|
||||||
): () => t.PrivateName {
|
): () => t.PrivateName {
|
||||||
const currentPrivateId = [charCodes.uppercaseA];
|
const currentPrivateId = [];
|
||||||
const privateNames = new Set<string>();
|
const privateNames = new Set<string>();
|
||||||
|
|
||||||
classPath.traverse({
|
classPath.traverse({
|
||||||
@ -63,14 +59,11 @@ function createPrivateUidGeneratorForClass(
|
|||||||
});
|
});
|
||||||
|
|
||||||
return (): t.PrivateName => {
|
return (): t.PrivateName => {
|
||||||
let reifiedId = String.fromCharCode(...currentPrivateId);
|
let reifiedId;
|
||||||
|
do {
|
||||||
while (privateNames.has(reifiedId)) {
|
|
||||||
incrementId(currentPrivateId);
|
incrementId(currentPrivateId);
|
||||||
reifiedId = String.fromCharCode(...currentPrivateId);
|
reifiedId = String.fromCharCode(...currentPrivateId);
|
||||||
}
|
} while (privateNames.has(reifiedId));
|
||||||
|
|
||||||
incrementId(currentPrivateId);
|
|
||||||
|
|
||||||
return t.privateName(t.identifier(reifiedId));
|
return t.privateName(t.identifier(reifiedId));
|
||||||
};
|
};
|
||||||
@ -124,16 +117,17 @@ function replaceClassWithVar(
|
|||||||
|
|
||||||
if (path.node.id) {
|
if (path.node.id) {
|
||||||
className = path.node.id.name;
|
className = path.node.id.name;
|
||||||
varId = generateLocalVarId(path, className);
|
varId = path.scope.parent.generateDeclaredUidIdentifier(className);
|
||||||
path.scope.rename(className, varId.name);
|
path.scope.rename(className, varId.name);
|
||||||
} else if (
|
} else if (
|
||||||
path.parentPath.node.type === "VariableDeclarator" &&
|
path.parentPath.node.type === "VariableDeclarator" &&
|
||||||
path.parentPath.node.id.type === "Identifier"
|
path.parentPath.node.id.type === "Identifier"
|
||||||
) {
|
) {
|
||||||
className = path.parentPath.node.id.name;
|
className = path.parentPath.node.id.name;
|
||||||
varId = generateLocalVarId(path, className);
|
varId = path.scope.parent.generateDeclaredUidIdentifier(className);
|
||||||
} else {
|
} else {
|
||||||
varId = generateLocalVarId(path, "decorated_class");
|
varId =
|
||||||
|
path.scope.parent.generateDeclaredUidIdentifier("decorated_class");
|
||||||
}
|
}
|
||||||
|
|
||||||
const newClassExpr = t.classExpression(
|
const newClassExpr = t.classExpression(
|
||||||
@ -283,12 +277,6 @@ function getElementKind(element: NodePath<ClassDecoratableElement>): number {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function generateLocalVarId(path: NodePath, name: string): t.Identifier {
|
|
||||||
const varId = path.scope.generateUidIdentifier(name);
|
|
||||||
path.scope.parent.push({ id: varId });
|
|
||||||
return t.cloneNode(varId);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Information about the decorators applied to an element
|
// Information about the decorators applied to an element
|
||||||
interface DecoratorInfo {
|
interface DecoratorInfo {
|
||||||
// The expressions of the decorators themselves
|
// The expressions of the decorators themselves
|
||||||
@ -514,7 +502,8 @@ function transformClass(
|
|||||||
classLocal: t.Identifier;
|
classLocal: t.Identifier;
|
||||||
|
|
||||||
if (classDecorators) {
|
if (classDecorators) {
|
||||||
classInitLocal = generateLocalVarId(path, "initClass");
|
classInitLocal =
|
||||||
|
path.scope.parent.generateDeclaredUidIdentifier("initClass");
|
||||||
|
|
||||||
const [localId, classPath] = replaceClassWithVar(path);
|
const [localId, classPath] = replaceClassWithVar(path);
|
||||||
path = classPath;
|
path = classPath;
|
||||||
@ -560,7 +549,8 @@ function transformClass(
|
|||||||
|
|
||||||
if (isComputed) {
|
if (isComputed) {
|
||||||
const keyPath = element.get("key");
|
const keyPath = element.get("key");
|
||||||
const localComputedNameId = generateLocalVarId(keyPath, name);
|
const localComputedNameId =
|
||||||
|
keyPath.scope.parent.generateDeclaredUidIdentifier(name);
|
||||||
keyPath.replaceWith(localComputedNameId);
|
keyPath.replaceWith(localComputedNameId);
|
||||||
|
|
||||||
elementDecoratorInfo.push({
|
elementDecoratorInfo.push({
|
||||||
@ -586,7 +576,8 @@ function transformClass(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const newId = generateClassPrivateUid();
|
const newId = generateClassPrivateUid();
|
||||||
const newFieldInitId = generateLocalVarId(element, `init_${name}`);
|
const newFieldInitId =
|
||||||
|
element.scope.parent.generateDeclaredUidIdentifier(`init_${name}`);
|
||||||
const newValue = t.callExpression(
|
const newValue = t.callExpression(
|
||||||
t.cloneNode(newFieldInitId),
|
t.cloneNode(newFieldInitId),
|
||||||
params,
|
params,
|
||||||
@ -598,8 +589,12 @@ function transformClass(
|
|||||||
if (isPrivate) {
|
if (isPrivate) {
|
||||||
privateMethods = extractProxyAccessorsFor(newId);
|
privateMethods = extractProxyAccessorsFor(newId);
|
||||||
|
|
||||||
const getId = generateLocalVarId(newPath, `get_${name}`);
|
const getId = newPath.scope.parent.generateDeclaredUidIdentifier(
|
||||||
const setId = generateLocalVarId(newPath, `set_${name}`);
|
`get_${name}`,
|
||||||
|
);
|
||||||
|
const setId = newPath.scope.parent.generateDeclaredUidIdentifier(
|
||||||
|
`set_${name}`,
|
||||||
|
);
|
||||||
|
|
||||||
addCallAccessorsFor(newPath, key as t.PrivateName, getId, setId);
|
addCallAccessorsFor(newPath, key as t.PrivateName, getId, setId);
|
||||||
|
|
||||||
@ -609,7 +604,9 @@ function transformClass(
|
|||||||
locals = newFieldInitId;
|
locals = newFieldInitId;
|
||||||
}
|
}
|
||||||
} else if (kind === FIELD) {
|
} else if (kind === FIELD) {
|
||||||
const initId = generateLocalVarId(element, `init_${name}`);
|
const initId = element.scope.parent.generateDeclaredUidIdentifier(
|
||||||
|
`init_${name}`,
|
||||||
|
);
|
||||||
const valuePath = (
|
const valuePath = (
|
||||||
element as NodePath<t.ClassProperty | t.ClassPrivateProperty>
|
element as NodePath<t.ClassProperty | t.ClassPrivateProperty>
|
||||||
).get("value");
|
).get("value");
|
||||||
@ -627,7 +624,9 @@ function transformClass(
|
|||||||
privateMethods = extractProxyAccessorsFor(key as t.PrivateName);
|
privateMethods = extractProxyAccessorsFor(key as t.PrivateName);
|
||||||
}
|
}
|
||||||
} else if (isPrivate) {
|
} else if (isPrivate) {
|
||||||
locals = generateLocalVarId(element, `call_${name}`);
|
locals = element.scope.parent.generateDeclaredUidIdentifier(
|
||||||
|
`call_${name}`,
|
||||||
|
) as t.Identifier;
|
||||||
|
|
||||||
const replaceSupers = new ReplaceSupers({
|
const replaceSupers = new ReplaceSupers({
|
||||||
constantSuper,
|
constantSuper,
|
||||||
@ -730,7 +729,8 @@ function transformClass(
|
|||||||
const newDecorators: t.Identifier[] = [];
|
const newDecorators: t.Identifier[] = [];
|
||||||
|
|
||||||
for (const decorator of decorators) {
|
for (const decorator of decorators) {
|
||||||
const localComputedNameId = generateLocalVarId(path, "dec");
|
const localComputedNameId =
|
||||||
|
path.scope.parent.generateDeclaredUidIdentifier("dec");
|
||||||
assignments.push(
|
assignments.push(
|
||||||
t.assignmentExpression("=", localComputedNameId, decorator),
|
t.assignmentExpression("=", localComputedNameId, decorator),
|
||||||
);
|
);
|
||||||
@ -761,7 +761,8 @@ function transformClass(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (requiresProtoInit) {
|
if (requiresProtoInit) {
|
||||||
protoInitLocal = generateLocalVarId(path, "initProto");
|
protoInitLocal =
|
||||||
|
path.scope.parent.generateDeclaredUidIdentifier("initProto");
|
||||||
locals.push(protoInitLocal);
|
locals.push(protoInitLocal);
|
||||||
|
|
||||||
const protoInitCall = t.callExpression(t.cloneNode(protoInitLocal), [
|
const protoInitCall = t.callExpression(t.cloneNode(protoInitLocal), [
|
||||||
@ -789,7 +790,8 @@ function transformClass(
|
|||||||
|
|
||||||
found = true;
|
found = true;
|
||||||
|
|
||||||
const prop = generateLocalVarId(path, "super");
|
const prop =
|
||||||
|
path.scope.parent.generateDeclaredUidIdentifier("super");
|
||||||
parentPath.replaceWith(
|
parentPath.replaceWith(
|
||||||
t.sequenceExpression([
|
t.sequenceExpression([
|
||||||
t.assignmentExpression("=", t.cloneNode(prop), parentPath.node),
|
t.assignmentExpression("=", t.cloneNode(prop), parentPath.node),
|
||||||
@ -829,7 +831,8 @@ function transformClass(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (requiresStaticInit) {
|
if (requiresStaticInit) {
|
||||||
staticInitLocal = generateLocalVarId(path, "initStatic");
|
staticInitLocal =
|
||||||
|
path.scope.parent.generateDeclaredUidIdentifier("initStatic");
|
||||||
locals.push(staticInitLocal);
|
locals.push(staticInitLocal);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user