Ensure private UID generation takes into account all referenced private names
This commit is contained in:
parent
3f7644823d
commit
ab6d74a9cc
@ -17,10 +17,6 @@ type ClassElement =
|
|||||||
| t.TSIndexSignature
|
| t.TSIndexSignature
|
||||||
| t.StaticBlock;
|
| t.StaticBlock;
|
||||||
|
|
||||||
type classUidGenerator = <B extends boolean>(
|
|
||||||
isPrivate: B,
|
|
||||||
) => B extends true ? t.PrivateName : t.Identifier;
|
|
||||||
|
|
||||||
function incrementId(id: number[], idx = id.length - 1): void {
|
function incrementId(id: number[], idx = id.length - 1): void {
|
||||||
// If index is -1, id needs an additional character, unshift A
|
// If index is -1, id needs an additional character, unshift A
|
||||||
if (idx === -1) {
|
if (idx === -1) {
|
||||||
@ -54,64 +50,29 @@ function incrementId(id: number[], idx = id.length - 1): void {
|
|||||||
* (you cannot have #x and static #x in the same class) and it's not worth the
|
* (you cannot have #x and static #x in the same class) and it's not worth the
|
||||||
* extra complexity for public names.
|
* extra complexity for public names.
|
||||||
*/
|
*/
|
||||||
function createUidGeneratorForClass(
|
function createPrivateUidGeneratorForClass(
|
||||||
body: NodePath<ClassElement>[],
|
classPath: NodePath<t.ClassDeclaration | t.ClassExpression>,
|
||||||
): (isPrivate: boolean) => t.Identifier | t.PrivateName {
|
): () => t.PrivateName {
|
||||||
let currentPublicId: number[], currentPrivateId: number[];
|
const currentPrivateId = [charCodes.uppercaseA];
|
||||||
|
|
||||||
const publicNames = new Set<string>();
|
|
||||||
const privateNames = new Set<string>();
|
const privateNames = new Set<string>();
|
||||||
|
|
||||||
for (const element of body) {
|
classPath.traverse({
|
||||||
if (
|
PrivateName(path) {
|
||||||
element.node.type === "TSIndexSignature" ||
|
privateNames.add(path.node.id.name);
|
||||||
element.node.type === "StaticBlock"
|
},
|
||||||
) {
|
});
|
||||||
continue;
|
|
||||||
|
return (): t.PrivateName => {
|
||||||
|
let reifiedId = String.fromCharCode(...currentPrivateId);
|
||||||
|
|
||||||
|
while (privateNames.has(reifiedId)) {
|
||||||
|
incrementId(currentPrivateId);
|
||||||
|
reifiedId = String.fromCharCode(...currentPrivateId);
|
||||||
}
|
}
|
||||||
|
|
||||||
const { key } = element.node;
|
incrementId(currentPrivateId);
|
||||||
|
|
||||||
if (key.type === "PrivateName") {
|
|
||||||
privateNames.add(key.id.name);
|
|
||||||
} else if (key.type === "Identifier") {
|
|
||||||
publicNames.add(key.name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (isPrivate: boolean): t.Identifier | t.PrivateName => {
|
|
||||||
let currentId: number[], names: Set<String>;
|
|
||||||
|
|
||||||
if (isPrivate) {
|
|
||||||
if (!currentPrivateId) {
|
|
||||||
currentPrivateId = [charCodes.uppercaseA];
|
|
||||||
}
|
|
||||||
|
|
||||||
currentId = currentPrivateId;
|
|
||||||
names = privateNames;
|
|
||||||
} else {
|
|
||||||
if (!currentPublicId) {
|
|
||||||
currentPublicId = [charCodes.uppercaseA];
|
|
||||||
}
|
|
||||||
|
|
||||||
currentId = currentPublicId;
|
|
||||||
names = publicNames;
|
|
||||||
}
|
|
||||||
|
|
||||||
let reifiedId = String.fromCharCode(...currentId);
|
|
||||||
|
|
||||||
while (names.has(reifiedId)) {
|
|
||||||
incrementId(currentId);
|
|
||||||
reifiedId = String.fromCharCode(...currentId);
|
|
||||||
}
|
|
||||||
|
|
||||||
incrementId(currentId);
|
|
||||||
|
|
||||||
if (isPrivate) {
|
|
||||||
return t.privateName(t.identifier(reifiedId));
|
return t.privateName(t.identifier(reifiedId));
|
||||||
} else {
|
|
||||||
return t.identifier(reifiedId);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -121,20 +82,18 @@ function createUidGeneratorForClass(
|
|||||||
* saves iterating the class elements an additional time and allocating the space
|
* saves iterating the class elements an additional time and allocating the space
|
||||||
* for the Sets of element names.
|
* for the Sets of element names.
|
||||||
*/
|
*/
|
||||||
function createLazyUidGeneratorForClass(
|
function createLazyPrivateUidGeneratorForClass(
|
||||||
body: NodePath<ClassElement>[],
|
classPath: NodePath<t.ClassDeclaration | t.ClassExpression>,
|
||||||
): classUidGenerator {
|
): () => t.PrivateName {
|
||||||
let generator: (isPrivate: boolean) => t.Identifier | t.PrivateName;
|
let generator: () => t.PrivateName;
|
||||||
|
|
||||||
const lazyGenerator = (isPrivate: boolean): t.Identifier | t.PrivateName => {
|
return (): t.PrivateName => {
|
||||||
if (!generator) {
|
if (!generator) {
|
||||||
generator = createUidGeneratorForClass(body);
|
generator = createPrivateUidGeneratorForClass(classPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
return generator(isPrivate);
|
return generator();
|
||||||
};
|
};
|
||||||
|
|
||||||
return lazyGenerator as unknown as classUidGenerator;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -510,7 +469,7 @@ function transformClass(
|
|||||||
const classDecorators = path.node.decorators;
|
const classDecorators = path.node.decorators;
|
||||||
let hasElementDecorators = false;
|
let hasElementDecorators = false;
|
||||||
|
|
||||||
const generateClassUid = createLazyUidGeneratorForClass(body);
|
const generateClassPrivateUid = createLazyPrivateUidGeneratorForClass(path);
|
||||||
|
|
||||||
// Iterate over the class to see if we need to decorate it, and also to
|
// Iterate over the class to see if we need to decorate it, and also to
|
||||||
// transform simple auto accessors which are not decorated
|
// transform simple auto accessors which are not decorated
|
||||||
@ -524,7 +483,7 @@ function transformClass(
|
|||||||
} else if (element.node.type === "ClassAccessorProperty") {
|
} else if (element.node.type === "ClassAccessorProperty") {
|
||||||
const { key, value, static: isStatic } = element.node;
|
const { key, value, static: isStatic } = element.node;
|
||||||
|
|
||||||
const newId = generateClassUid(true);
|
const newId = generateClassPrivateUid();
|
||||||
|
|
||||||
const valueNode = value ? t.cloneNode(value) : undefined;
|
const valueNode = value ? t.cloneNode(value) : undefined;
|
||||||
|
|
||||||
@ -626,7 +585,7 @@ function transformClass(
|
|||||||
params.push(t.cloneNode(value));
|
params.push(t.cloneNode(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
const newId = generateClassUid(true);
|
const newId = generateClassPrivateUid();
|
||||||
const newFieldInitId = generateLocalVarId(element, `init_${name}`);
|
const newFieldInitId = generateLocalVarId(element, `init_${name}`);
|
||||||
const newValue = t.callExpression(
|
const newValue = t.callExpression(
|
||||||
t.cloneNode(newFieldInitId),
|
t.cloneNode(newFieldInitId),
|
||||||
|
|||||||
@ -0,0 +1,10 @@
|
|||||||
|
class A {
|
||||||
|
#A = 1;
|
||||||
|
static B = class B extends A {
|
||||||
|
accessor a = 2;
|
||||||
|
|
||||||
|
getA() {
|
||||||
|
return this.#A;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,19 @@
|
|||||||
|
class A {
|
||||||
|
#A = 1;
|
||||||
|
static B = class B extends A {
|
||||||
|
#B = 2;
|
||||||
|
|
||||||
|
get a() {
|
||||||
|
return this.#B;
|
||||||
|
}
|
||||||
|
|
||||||
|
set a(v) {
|
||||||
|
this.#B = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
getA() {
|
||||||
|
return this.#A;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user