mirror of
https://github.com/morluto/rea
synced 2026-10-27 06:33:32 -04:00
fix(javascript): retain implicit property conversion and disposal effects
This commit is contained in:
@@ -156,9 +156,10 @@ const classPropertyDescriptors = (
|
||||
propertyName: string | null,
|
||||
kind: ClassPropertyLookup["kind"],
|
||||
initializedBefore?: t.ClassProperty,
|
||||
accessor: "get" | "set" = "get",
|
||||
) => {
|
||||
const isStatic = kind === "static";
|
||||
const selectedGetters: t.ClassMethod[] = [];
|
||||
const selectedAccessors: t.ClassMethod[] = [];
|
||||
const fields: t.ClassProperty[] = [];
|
||||
const indexedMembers: {
|
||||
readonly member: t.ClassMethod | t.ClassProperty;
|
||||
@@ -191,19 +192,19 @@ const classPropertyDescriptors = (
|
||||
propertyName === null
|
||||
? []
|
||||
: indexedMembers.filter(({ key }) => key === propertyName);
|
||||
const uncertainGetters = indexedMembers.filter(
|
||||
const uncertainAccessors = indexedMembers.filter(
|
||||
(entry): entry is typeof entry & { member: t.ClassMethod } => {
|
||||
const { member, key } = entry;
|
||||
return (
|
||||
t.isClassMethod(member) &&
|
||||
member.kind === "get" &&
|
||||
member.kind === accessor &&
|
||||
(propertyName === null || (member.computed && key === null))
|
||||
);
|
||||
},
|
||||
);
|
||||
const getters = matchingMembers.filter(
|
||||
(entry): entry is typeof entry & { member: t.ClassMethod } =>
|
||||
t.isClassMethod(entry.member) && entry.member.kind === "get",
|
||||
t.isClassMethod(entry.member) && entry.member.kind === accessor,
|
||||
);
|
||||
const getter = getters.at(-1);
|
||||
const getterIndex = getter?.index ?? -1;
|
||||
@@ -223,20 +224,20 @@ const classPropertyDescriptors = (
|
||||
fields.push(member);
|
||||
}
|
||||
if (getters.length > 0 && !laterDataMember && getter !== undefined)
|
||||
selectedGetters.push(getter.member);
|
||||
for (const { member, index } of uncertainGetters)
|
||||
selectedAccessors.push(getter.member);
|
||||
for (const { member, index } of uncertainAccessors)
|
||||
if (
|
||||
!matchingMembers.some(
|
||||
({ member: matching, index: matchingIndex }) =>
|
||||
(t.isClassProperty(matching) ||
|
||||
(t.isClassMethod(matching) &&
|
||||
(matching.kind === "method" || matching.kind === "get"))) &&
|
||||
(matching.kind === "method" || matching.kind === accessor))) &&
|
||||
matchingIndex > index,
|
||||
)
|
||||
)
|
||||
selectedGetters.push(member);
|
||||
selectedAccessors.push(member);
|
||||
return {
|
||||
getters: selectedGetters,
|
||||
accessors: selectedAccessors,
|
||||
fields,
|
||||
inherits: matchingMembers.length === 0,
|
||||
};
|
||||
@@ -254,6 +255,18 @@ export const semanticClassPropertyReferences = (
|
||||
);
|
||||
};
|
||||
|
||||
/** Class descriptor selection shares field shadowing and inheritance with reference lookup. */
|
||||
export const semanticClassAccessorReferences = (
|
||||
lookup: ClassPropertyLookup,
|
||||
key: PropertyPath[number],
|
||||
state: JavaScriptSemanticAnalysisState,
|
||||
accessor: "get" | "set",
|
||||
): readonly JavaScriptSemanticObjectReference[] =>
|
||||
new ClassReferenceWalk(lookup, [key], state, {
|
||||
query: new SemanticGetterQuery(state),
|
||||
accessor,
|
||||
}).run();
|
||||
|
||||
class ClassReferenceWalk {
|
||||
readonly #references: JavaScriptSemanticObjectReference[] = [];
|
||||
readonly #pending: (t.ClassDeclaration | t.ClassExpression)[];
|
||||
@@ -269,6 +282,7 @@ class ClassReferenceWalk {
|
||||
readonly context: {
|
||||
readonly query: SemanticGetterQuery;
|
||||
readonly escapes?: boolean;
|
||||
readonly accessor?: "get" | "set";
|
||||
},
|
||||
) {
|
||||
const [key, ...path] = selection;
|
||||
@@ -287,7 +301,9 @@ class ClassReferenceWalk {
|
||||
this.state,
|
||||
this.lookup.initializedBefore,
|
||||
);
|
||||
for (const reference of fields.references) this.#references.push(reference);
|
||||
if (this.context.accessor === undefined)
|
||||
for (const reference of fields.references)
|
||||
this.#references.push(reference);
|
||||
this.#fields = fields.definiteNames;
|
||||
return this.#name !== null && this.#fields.has(this.#name);
|
||||
}
|
||||
@@ -298,6 +314,10 @@ class ClassReferenceWalk {
|
||||
): void {
|
||||
const key = semanticStaticPropertyKey(getter.key, getter.computed);
|
||||
if (key !== null && this.#fields.has(key)) return;
|
||||
if (this.context.accessor !== undefined) {
|
||||
this.#references.push({ node: getter, path: [] });
|
||||
return;
|
||||
}
|
||||
this.context.query.schedule(
|
||||
{
|
||||
getter,
|
||||
@@ -315,11 +335,14 @@ class ClassReferenceWalk {
|
||||
this.#name,
|
||||
this.lookup.kind,
|
||||
this.lookup.initializedBefore,
|
||||
this.context.accessor,
|
||||
);
|
||||
for (const field of descriptors.fields)
|
||||
for (const field of this.context.accessor === undefined
|
||||
? descriptors.fields
|
||||
: [])
|
||||
if (field.value != null)
|
||||
this.#references.push({ node: field.value, path: this.#path });
|
||||
for (const getter of this.lookup.fieldsOnly ? [] : descriptors.getters)
|
||||
for (const getter of this.lookup.fieldsOnly ? [] : descriptors.accessors)
|
||||
this.#getter(klass, getter);
|
||||
// Only a definite own descriptor can suppress possible superclass results.
|
||||
if (descriptors.inherits && klass.superClass != null)
|
||||
@@ -617,12 +640,14 @@ export const semanticObjectAccessorReferences = (
|
||||
key: PropertyPath[number],
|
||||
state: JavaScriptSemanticAnalysisState,
|
||||
accessor: "get" | "set",
|
||||
lookup: "prototype" | "own" = "prototype",
|
||||
): readonly JavaScriptSemanticObjectReference[] =>
|
||||
new ObjectReferenceWalk(
|
||||
node,
|
||||
[key],
|
||||
new SemanticGetterQuery(state),
|
||||
accessor,
|
||||
lookup,
|
||||
).run();
|
||||
|
||||
class ObjectReferenceWalk {
|
||||
@@ -640,6 +665,7 @@ class ObjectReferenceWalk {
|
||||
path: PropertyPath,
|
||||
readonly query: SemanticGetterQuery,
|
||||
readonly accessor?: "get" | "set",
|
||||
readonly accessorLookup: "prototype" | "own" = "prototype",
|
||||
) {
|
||||
[this.#key, ...this.#remaining] = path;
|
||||
}
|
||||
@@ -694,6 +720,8 @@ class ObjectReferenceWalk {
|
||||
)
|
||||
return false;
|
||||
const selected = this.#key ?? null;
|
||||
if (this.accessor !== undefined && this.accessorLookup === "own")
|
||||
return true;
|
||||
if (
|
||||
t.isExpression(property.value) &&
|
||||
(selected === null ||
|
||||
|
||||
Reference in New Issue
Block a user