feat: hoist isEffect when merging references, refactor native tag analyze

This commit is contained in:
Michael Rawlings 2024-04-02 17:28:35 -04:00 committed by Dylan Piercey
parent 198b42bef0
commit 60e097f0ec
2 changed files with 29 additions and 24 deletions

View File

@ -318,21 +318,31 @@ export function finalizeReferences() {
if (mergedReferences.size) {
for (const [target, nodes] of mergedReferences) {
const targetExtra = (target.node.extra ??= {});
let newReferences: ReferencedBindings = targetExtra.referencedBindings;
let { referencedBindings, isEffect } = targetExtra;
for (const node of nodes) {
const extra = node?.extra;
const referencedBindings = extra?.referencedBindings;
if (referencedBindings) {
newReferences = bindingUtil.union(newReferences, referencedBindings);
forEach(referencedBindings, ({ downstreamExpressions }) => {
downstreamExpressions.delete(extra);
downstreamExpressions.add(targetExtra);
});
if (extra) {
const additionalBindings = extra.referencedBindings;
isEffect ||= extra.isEffect;
if (additionalBindings) {
referencedBindings = bindingUtil.union(
referencedBindings,
additionalBindings,
);
forEach(additionalBindings, ({ downstreamExpressions }) => {
downstreamExpressions.delete(extra);
downstreamExpressions.add(targetExtra);
});
}
}
}
newReferences = findReferences(getOrCreateSection(target), newReferences);
targetExtra.referencedBindings = newReferences;
referencedBindings = findReferences(
getOrCreateSection(target),
referencedBindings,
);
targetExtra.referencedBindings = referencedBindings;
targetExtra.isEffect = isEffect;
}
mergedReferences.clear();

View File

@ -26,11 +26,9 @@ import { currentProgramPath, scopeIdentifier } from "../program";
export const kNativeTagBinding = Symbol("native tag binding");
export const kSerializeMarker = Symbol("serialize marker");
const kHasEventHandlers = Symbol("has event handlers");
declare module "@marko/compiler/dist/types" {
export interface NodeExtra {
[kNativeTagBinding]?: Binding;
[kHasEventHandlers]?: boolean;
[kSerializeMarker]?: boolean;
}
}
@ -40,8 +38,8 @@ export default {
enter(tag: t.NodePath<t.MarkoTag>) {
const { node } = tag;
const attrs = tag.get("attributes");
let section = tag.has("var") ? getOrCreateSection(tag) : undefined;
let hasEventHandlers = false;
let hasDynamicAttributes = false;
/**
* The reason this seems like it does more work than it needs to
@ -50,31 +48,30 @@ export default {
*/
for (const attr of attrs) {
if (isSpreadAttr(attr)) {
section ??= getOrCreateSection(tag);
(attr.node.value.extra ??= {}).isEffect = true;
hasEventHandlers = true;
hasDynamicAttributes = true;
mergeReferences(
tag,
attrs.map((attr) => attr.node.value),
);
hasEventHandlers = true;
// TODO: should add isEffect to all attributes in a spread?
break;
} else if (isEventHandler((attr.node as t.MarkoAttribute).name)) {
(attr.node.value.extra ??= {}).isEffect = true;
section ??= getOrCreateSection(tag);
hasEventHandlers = true;
} else if (!evaluate(attr).confident) {
section ??= getOrCreateSection(tag);
hasDynamicAttributes = true;
}
}
if (section !== undefined) {
if (tag.has("var") || hasEventHandlers || hasDynamicAttributes) {
currentProgramPath.node.extra.isInteractive ||= hasEventHandlers;
const section = getOrCreateSection(tag);
const tagName =
node.name.type === "StringLiteral"
? node.name.value
: t.toIdentifier(tag.get("name"));
const tagExtra = (node.extra ??= {});
tagExtra[kHasEventHandlers] = hasEventHandlers;
tagExtra[kSerializeMarker] = tag.has("var") || hasEventHandlers;
tagExtra[kNativeTagBinding] = createBinding(
"#" + tagName,
BindingType.dom,
@ -318,9 +315,7 @@ export default {
if (
nodeRef &&
(extra[kHasEventHandlers] ||
extra[kSerializeMarker] ||
tag.has("var") ||
(extra[kSerializeMarker] ||
tag.node.attributes.some((attr) =>
isStatefulReferences(attr.value.extra?.referencedBindings),
))