hoist-unmodified-var
Ben McCann 2 years ago
parent 2169608d89
commit eec1110b80

@ -535,11 +535,12 @@ export function should_proxy_or_freeze(node) {
}
/**
* Whether a variable can be referenced directly from template string.
* @param {import('#compiler').Binding | undefined} binding
* @param {string} name
* @returns {boolean}
*/
export function is_hoistable_declaration(binding, name) {
export function can_inline_variable(binding, name) {
// TODO: allow object expressions that are not passed to functions or components as props
// and expressions as long as they do not reference non-hoistable variables
return (
@ -549,8 +550,18 @@ export function is_hoistable_declaration(binding, name) {
!binding.mutated &&
!binding.reassigned &&
binding.initial?.type === 'Literal' &&
binding.scope.has_parent() && // i.e. not when context="module"
!binding.scope.declared_in_outer_scope(name) &&
!GlobalBindings.has(name)
);
}
/**
* @param {import('#compiler').Binding | undefined} binding
* @param {string} name
* @returns {boolean}
*/
export function can_hoist_declaration(binding, name) {
return (
can_inline_variable(binding, name) && !!binding && binding.scope.has_parent() // i.e. not when context="module"
);
}

@ -2,9 +2,9 @@ import { is_hoistable_function } from '../../utils.js';
import * as b from '../../../../utils/builders.js';
import { extract_paths } from '../../../../utils/ast.js';
import {
can_hoist_declaration,
create_state_declarators,
get_prop_source,
is_hoistable_declaration,
serialize_get_binding
} from '../utils.js';
@ -29,7 +29,7 @@ export const javascript_visitors_legacy = {
.owner(declarator.id.name)
?.declarations.get(declarator.id.name);
if (is_hoistable_declaration(binding, declarator.id.name)) {
if (can_hoist_declaration(binding, declarator.id.name)) {
state.hoisted.push(b.declaration('const', declarator.id, init));
continue;
}

@ -3,9 +3,9 @@ import { is_hoistable_function, transform_inspect_rune } from '../../utils.js';
import * as b from '../../../../utils/builders.js';
import * as assert from '../../../../utils/assert.js';
import {
can_hoist_declaration,
create_state_declarators,
get_prop_source,
is_hoistable_declaration,
should_proxy_or_freeze
} from '../utils.js';
import { unwrap_ts_expression } from '../../../../utils/ast.js';
@ -164,7 +164,7 @@ export const javascript_visitors_runes = {
if (init != null && declarator.id.type === 'Identifier') {
const binding = state.scope.owner(declarator.id.name)?.declarations.get(declarator.id.name);
if (is_hoistable_declaration(binding, declarator.id.name)) {
if (can_hoist_declaration(binding, declarator.id.name)) {
state.hoisted.push(b.declaration('const', declarator.id, init));
continue;
}

@ -17,9 +17,9 @@ import { is_custom_element_node, is_element_node } from '../../../nodes.js';
import * as b from '../../../../utils/builders.js';
import { error } from '../../../../errors.js';
import {
can_hoist_declaration,
function_visitor,
get_assignment_value,
is_hoistable_declaration,
serialize_get_binding,
serialize_set_binding
} from '../utils.js';
@ -564,19 +564,21 @@ function serialize_element_attribute_update_assignment(element, node_id, attribu
}
};
let hoistable = false;
let can_inline = false;
if (Array.isArray(attribute.value)) {
for (let value of attribute.value) {
if (value.type === 'ExpressionTag' && value.expression.type === 'Identifier') {
const binding = context.state.scope
.owner(value.expression.name)
?.declarations.get(value.expression.name);
hoistable ||= is_hoistable_declaration(binding, value.expression.name);
// TODO: use can_inline_variable instead
// and insert template strings after module variables
can_inline ||= can_hoist_declaration(binding, value.expression.name);
}
}
}
if (attribute.metadata.dynamic && !hoistable) {
if (attribute.metadata.dynamic && !can_inline) {
const id = state.scope.generate(`${node_id.name}_${name}`);
serialize_update_assignment(
state,
@ -588,7 +590,7 @@ function serialize_element_attribute_update_assignment(element, node_id, attribu
);
return true;
} else {
if (hoistable) {
if (can_inline) {
push_template_quasi(context.state, ` ${name}="`);
push_template_expression(context.state, grouped_value);
push_template_quasi(context.state, `"`);

Loading…
Cancel
Save