Skip to content

Commit 805327c

Browse files
committed
fix: use is_inlinable_expression
1 parent f21a6b0 commit 805327c

File tree

3 files changed

+41
-43
lines changed

3 files changed

+41
-43
lines changed

packages/svelte/src/compiler/phases/3-transform/client/utils.js

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/** @import { ArrowFunctionExpression, Expression, FunctionDeclaration, FunctionExpression, Identifier, Pattern, PrivateIdentifier, Statement } from 'estree' */
2-
/** @import { Binding, SvelteNode } from '#compiler' */
2+
/** @import { AST, Binding, SvelteNode } from '#compiler' */
33
/** @import { ClientTransformState, ComponentClientTransformState, ComponentContext } from './types.js' */
44
/** @import { Analysis } from '../../types.js' */
55
/** @import { Scope } from '../../scope.js' */
@@ -326,3 +326,27 @@ export function can_inline_variable(binding) {
326326
binding.initial?.type === 'Literal'
327327
);
328328
}
329+
330+
/**
331+
* @param {(AST.Text | AST.ExpressionTag)[]} nodes
332+
* @param {import('./types.js').ComponentClientTransformState} state
333+
*/
334+
export function is_inlinable_expression(nodes, state) {
335+
let has_expression_tag = false;
336+
for (let value of nodes) {
337+
if (value.type === 'ExpressionTag') {
338+
if (value.expression.type === 'Identifier') {
339+
const binding = state.scope
340+
.owner(value.expression.name)
341+
?.declarations.get(value.expression.name);
342+
if (!can_inline_variable(binding)) {
343+
return false;
344+
}
345+
} else {
346+
return false;
347+
}
348+
has_expression_tag = true;
349+
}
350+
}
351+
return has_expression_tag;
352+
}

packages/svelte/src/compiler/phases/3-transform/client/visitors/RegularElement.js

Lines changed: 6 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,12 @@ import {
1919
import * as b from '../../../../utils/builders.js';
2020
import { is_custom_element_node } from '../../../nodes.js';
2121
import { clean_nodes, determine_namespace_for_children } from '../../utils.js';
22-
import { build_getter, can_inline_variable, create_derived } from '../utils.js';
22+
import {
23+
build_getter,
24+
can_inline_variable,
25+
create_derived,
26+
is_inlinable_expression
27+
} from '../utils.js';
2328
import {
2429
get_attribute_name,
2530
build_attribute_value,
@@ -605,30 +610,6 @@ function build_element_attribute_update_assignment(element, node_id, attribute,
605610
}
606611
}
607612

608-
/**
609-
* @param {(AST.Text | AST.ExpressionTag)[]} nodes
610-
* @param {import('../types.js').ComponentClientTransformState} state
611-
*/
612-
function is_inlinable_expression(nodes, state) {
613-
let has_expression_tag = false;
614-
for (let value of nodes) {
615-
if (value.type === 'ExpressionTag') {
616-
if (value.expression.type === 'Identifier') {
617-
const binding = state.scope
618-
.owner(value.expression.name)
619-
?.declarations.get(value.expression.name);
620-
if (!can_inline_variable(binding)) {
621-
return false;
622-
}
623-
} else {
624-
return false;
625-
}
626-
has_expression_tag = true;
627-
}
628-
}
629-
return has_expression_tag;
630-
}
631-
632613
/**
633614
* Like `build_element_attribute_update_assignment` but without any special attribute treatment.
634615
* @param {Identifier} node_id

packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/fragment.js

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
/** @import { ComponentContext } from '../../types' */
44
import { is_event_attribute, is_text_attribute } from '../../../../../utils/ast.js';
55
import * as b from '../../../../../utils/builders.js';
6-
import { can_inline_variable } from '../../utils.js';
6+
import { can_inline_variable, is_inlinable_expression } from '../../utils.js';
77
import { build_template_literal, build_update } from './utils.js';
88

99
/**
@@ -98,7 +98,7 @@ export function process_children(nodes, initial, is_element, { visit, state }) {
9898

9999
let child_state = state;
100100

101-
if (is_static_element(node, state.scope)) {
101+
if (is_static_element(node, state)) {
102102
skipped += 1;
103103
} else if (node.type === 'EachBlock' && nodes.length === 1 && is_element) {
104104
node.metadata.is_controlled = true;
@@ -125,9 +125,9 @@ export function process_children(nodes, initial, is_element, { visit, state }) {
125125

126126
/**
127127
* @param {SvelteNode} node
128-
* @param {ComponentContext["state"]["scope"]} scope
128+
* @param {ComponentContext["state"]} state
129129
*/
130-
function is_static_element(node, scope) {
130+
function is_static_element(node, state) {
131131
if (node.type !== 'RegularElement') return false;
132132
if (node.fragment.metadata.dynamic) return false;
133133

@@ -141,19 +141,12 @@ function is_static_element(node, scope) {
141141
}
142142

143143
if (attribute.value !== true && !is_text_attribute(attribute)) {
144-
// in this situation we are already inlining the binding in the template
145-
// so even if it's not a text attribute we can consider the element static
146-
if (
147-
typeof attribute.value !== 'boolean' &&
148-
!Array.isArray(attribute.value) &&
149-
attribute.value.expression.type === 'Identifier'
150-
) {
151-
const binding = scope.get(attribute.value.expression.name);
152-
if (binding) {
153-
return can_inline_variable(binding);
154-
}
155-
}
156-
return false;
144+
// if it's not a text attribute but it's an inlinable expression
145+
// we will inline it in the template so we can still consider it static
146+
return is_inlinable_expression(
147+
Array.isArray(attribute.value) ? attribute.value : [attribute.value],
148+
state
149+
);
157150
}
158151

159152
if (attribute.name === 'autofocus' || attribute.name === 'muted') {

0 commit comments

Comments
 (0)