Lint and format src/compiler/compile/render_dom/wrappers/Element/Attribute.js

pull/8569/head
Simon Holthausen 3 years ago
parent 9e71a2f9cd
commit 1eb0941f0c

@ -21,7 +21,6 @@ const non_textlike_input_types = new Set([
]); ]);
/** */ /** */
export class BaseAttributeWrapper { export class BaseAttributeWrapper {
/** @type {import('../../../nodes/Attribute.js').default} */ /** @type {import('../../../nodes/Attribute.js').default} */
node; node;
@ -36,14 +35,13 @@ export class BaseAttributeWrapper {
} }
/** @param {import('../../Block.js').default} _block */ /** @param {import('../../Block.js').default} _block */
render(_block) { } render(_block) {}
} }
const regex_minus_sign = /-/; const regex_minus_sign = /-/;
const regex_invalid_variable_identifier_characters = /[^a-zA-Z_$]/g; const regex_invalid_variable_identifier_characters = /[^a-zA-Z_$]/g;
/** @extends BaseAttributeWrapper */ /** @extends BaseAttributeWrapper */
export default class AttributeWrapper extends BaseAttributeWrapper { export default class AttributeWrapper extends BaseAttributeWrapper {
/** @type {import('../../../nodes/Attribute.js').default} */ /** @type {import('../../../nodes/Attribute.js').default} */
node; node;
@ -107,8 +105,7 @@ export default class AttributeWrapper extends BaseAttributeWrapper {
this.property_name = null; this.property_name = null;
this.is_select_value_attribute = false; this.is_select_value_attribute = false;
this.is_input_value = false; this.is_input_value = false;
} } else {
else {
this.name = fix_attribute_casing(this.node.name); this.name = fix_attribute_casing(this.node.name);
this.metadata = this.get_metadata(); this.metadata = this.get_metadata();
this.is_indirectly_bound_value = is_indirectly_bound_value(this); this.is_indirectly_bound_value = is_indirectly_bound_value(this);
@ -137,7 +134,8 @@ export default class AttributeWrapper extends BaseAttributeWrapper {
: name.slice(0, 6) === 'xlink:' : name.slice(0, 6) === 'xlink:'
? '@xlink_attr' ? '@xlink_attr'
: '@attr'; : '@attr';
const is_legacy_input_type = element.renderer.component.compile_options.legacy && const is_legacy_input_type =
element.renderer.component.compile_options.legacy &&
name === 'type' && name === 'type' &&
this.parent.node.name === 'input'; this.parent.node.name === 'input';
const dependencies = this.get_dependencies(); const dependencies = this.get_dependencies();
@ -147,40 +145,37 @@ export default class AttributeWrapper extends BaseAttributeWrapper {
let updater; let updater;
const init = this.get_init(block, value); const init = this.get_init(block, value);
if (is_legacy_input_type) { if (is_legacy_input_type) {
block.chunks.hydrate.push(b `@set_input_type(${element.var}, ${init});`); block.chunks.hydrate.push(b`@set_input_type(${element.var}, ${init});`);
updater = b `@set_input_type(${element.var}, ${should_cache ? this.last : value});`; updater = b`@set_input_type(${element.var}, ${should_cache ? this.last : value});`;
} } else if (this.is_select_value_attribute) {
else if (this.is_select_value_attribute) {
// annoying special case // annoying special case
const is_multiple_select = element.node.get_static_attribute_value('multiple'); const is_multiple_select = element.node.get_static_attribute_value('multiple');
if (is_multiple_select) { if (is_multiple_select) {
updater = b `@select_options(${element.var}, ${value});`; updater = b`@select_options(${element.var}, ${value});`;
} } else {
else { updater = b`@select_option(${element.var}, ${value});`;
updater = b `@select_option(${element.var}, ${value});`;
} }
block.chunks.mount.push(b ` block.chunks.mount.push(b`
${updater} ${updater}
`); `);
} } else if (this.is_src) {
else if (this.is_src) { block.chunks.hydrate.push(
block.chunks.hydrate.push(b `if (!@src_url_equal(${element.var}.src, ${init})) ${method}(${element.var}, "${name}", ${this.last});`); b`if (!@src_url_equal(${element.var}.src, ${init})) ${method}(${element.var}, "${name}", ${this.last});`
updater = b `${method}(${element.var}, "${name}", ${should_cache ? this.last : value});`; );
} updater = b`${method}(${element.var}, "${name}", ${should_cache ? this.last : value});`;
else if (property_name) { } else if (property_name) {
block.chunks.hydrate.push(b `${element.var}.${property_name} = ${init};`); block.chunks.hydrate.push(b`${element.var}.${property_name} = ${init};`);
updater = block.renderer.options.dev updater = block.renderer.options.dev
? b `@prop_dev(${element.var}, "${property_name}", ${should_cache ? this.last : value});` ? b`@prop_dev(${element.var}, "${property_name}", ${should_cache ? this.last : value});`
: b `${element.var}.${property_name} = ${should_cache ? this.last : value};`; : b`${element.var}.${property_name} = ${should_cache ? this.last : value};`;
} } else {
else { block.chunks.hydrate.push(b`${method}(${element.var}, "${name}", ${init});`);
block.chunks.hydrate.push(b `${method}(${element.var}, "${name}", ${init});`); updater = b`${method}(${element.var}, "${name}", ${should_cache ? this.last : value});`;
updater = b `${method}(${element.var}, "${name}", ${should_cache ? this.last : value});`;
} }
if (is_indirectly_bound_value) { if (is_indirectly_bound_value) {
const update_value = b `@set_input_value(${element.var}, ${element.var}.__value);`; const update_value = b`@set_input_value(${element.var}, ${element.var}.__value);`;
block.chunks.hydrate.push(update_value); block.chunks.hydrate.push(update_value);
updater = b ` updater = b`
${updater} ${updater}
${update_value}; ${update_value};
`; `;
@ -188,8 +183,8 @@ export default class AttributeWrapper extends BaseAttributeWrapper {
if (this.node.name === 'value' && dependencies.length > 0) { if (this.node.name === 'value' && dependencies.length > 0) {
if (this.parent.bindings.some((binding) => binding.node.name === 'group')) { if (this.parent.bindings.some((binding) => binding.node.name === 'group')) {
this.parent.dynamic_value_condition = block.get_unique_name('value_has_changed'); this.parent.dynamic_value_condition = block.get_unique_name('value_has_changed');
block.add_variable(this.parent.dynamic_value_condition, x `false`); block.add_variable(this.parent.dynamic_value_condition, x`false`);
updater = b ` updater = b`
${updater} ${updater}
${this.parent.dynamic_value_condition} = true; ${this.parent.dynamic_value_condition} = true;
`; `;
@ -197,7 +192,7 @@ export default class AttributeWrapper extends BaseAttributeWrapper {
} }
if (dependencies.length > 0) { if (dependencies.length > 0) {
const condition = this.get_dom_update_conditions(block, block.renderer.dirty(dependencies)); const condition = this.get_dom_update_conditions(block, block.renderer.dirty(dependencies));
block.chunks.update.push(b ` block.chunks.update.push(b`
if (${condition}) { if (${condition}) {
${updater} ${updater}
}`); }`);
@ -218,10 +213,14 @@ export default class AttributeWrapper extends BaseAttributeWrapper {
get_init(block, value) { get_init(block, value) {
this.last = this.last =
this.should_cache && this.should_cache &&
block.get_unique_name(`${this.parent.var.name}_${this.name.replace(regex_invalid_variable_identifier_characters, '_')}_value`); block.get_unique_name(
if (this.should_cache) `${this.parent.var.name}_${this.name.replace(
block.add_variable(this.last); regex_invalid_variable_identifier_characters,
return this.should_cache ? x `${this.last} = ${value}` : value; '_'
)}_value`
);
if (this.should_cache) block.add_variable(this.last);
return this.should_cache ? x`${this.last} = ${value}` : value;
} }
/** /**
@ -235,17 +234,19 @@ export default class AttributeWrapper extends BaseAttributeWrapper {
let condition = dependency_condition; let condition = dependency_condition;
if (should_cache) { if (should_cache) {
condition = this.is_src condition = this.is_src
? x `${condition} && (!@src_url_equal(${element.var}.src, (${last} = ${value})))` ? x`${condition} && (!@src_url_equal(${element.var}.src, (${last} = ${value})))`
: x `${condition} && (${last} !== (${last} = ${value}))`; : x`${condition} && (${last} !== (${last} = ${value}))`;
} }
if (this.is_input_value) { if (this.is_input_value) {
const type = element.node.get_static_attribute_value('type'); const type = element.node.get_static_attribute_value('type');
if (type !== true && !non_textlike_input_types.has(type)) { if (type !== true && !non_textlike_input_types.has(type)) {
condition = x `${condition} && ${element.var}.${property_name} !== ${should_cache ? last : value}`; condition = x`${condition} && ${element.var}.${property_name} !== ${
should_cache ? last : value
}`;
} }
} }
if (block.has_outros) { if (block.has_outros) {
condition = x `!#current || ${condition}`; condition = x`!#current || ${condition}`;
} }
return condition; return condition;
} }
@ -263,8 +264,7 @@ export default class AttributeWrapper extends BaseAttributeWrapper {
return Array.from(dependencies); return Array.from(dependencies);
} }
get_metadata() { get_metadata() {
if (this.parent.node.namespace) if (this.parent.node.namespace) return null;
return null;
const metadata = attribute_lookup[this.name]; const metadata = attribute_lookup[this.name];
if (metadata && metadata.applies_to && !metadata.applies_to.includes(this.parent.node.name)) if (metadata && metadata.applies_to && !metadata.applies_to.includes(this.parent.node.name))
return null; return null;
@ -275,25 +275,29 @@ export default class AttributeWrapper extends BaseAttributeWrapper {
get_value(block) { get_value(block) {
if (this.node.is_true) { if (this.node.is_true) {
if (this.metadata && boolean_attributes.has(this.metadata.property_name.toLowerCase())) { if (this.metadata && boolean_attributes.has(this.metadata.property_name.toLowerCase())) {
return x `true`; return x`true`;
} }
return x `""`; return x`""`;
} }
if (this.node.chunks.length === 0) if (this.node.chunks.length === 0) return x`""`;
return x `""`;
// TODO some of this code is repeated in Tag.ts — would be good to // TODO some of this code is repeated in Tag.ts — would be good to
// DRY it out if that's possible without introducing crazy indirection // DRY it out if that's possible without introducing crazy indirection
if (this.node.chunks.length === 1) { if (this.node.chunks.length === 1) {
return this.node.chunks[0].type === 'Text' return this.node.chunks[0].type === 'Text'
? string_literal(( /** @type {import('../../../nodes/Text.js').default} */(this.node.chunks[0])).data) ? string_literal(
: ( /** @type {import('../../../nodes/shared/Expression.js').default} */(this.node.chunks[0])).manipulate(block); /** @type {import('../../../nodes/Text.js').default} */ (this.node.chunks[0]).data
} )
let value = this.node.name === 'class' : /** @type {import('../../../nodes/shared/Expression.js').default} */ (
this.node.chunks[0]
).manipulate(block);
}
let value =
this.node.name === 'class'
? this.get_class_name_text(block) ? this.get_class_name_text(block)
: this.render_chunks(block).reduce((lhs, rhs) => x `${lhs} + ${rhs}`); : this.render_chunks(block).reduce((lhs, rhs) => x`${lhs} + ${rhs}`);
// '{foo} {bar}' — treat as string concatenation // '{foo} {bar}' — treat as string concatenation
if (this.node.chunks[0].type !== 'Text') { if (this.node.chunks[0].type !== 'Text') {
value = x `"" + ${value}`; value = x`"" + ${value}`;
} }
return value; return value;
} }
@ -304,9 +308,9 @@ export default class AttributeWrapper extends BaseAttributeWrapper {
const rendered = this.render_chunks(block); const rendered = this.render_chunks(block);
if (scoped_css && rendered.length === 2) { if (scoped_css && rendered.length === 2) {
// we have a situation like class={possiblyUndefined} // we have a situation like class={possiblyUndefined}
rendered[0] = x `@null_to_empty(${rendered[0]})`; rendered[0] = x`@null_to_empty(${rendered[0]})`;
} }
return rendered.reduce((lhs, rhs) => x `${lhs} + ${rhs}`); return rendered.reduce((lhs, rhs) => x`${lhs} + ${rhs}`);
} }
/** @param {import('../../Block.js').default} block */ /** @param {import('../../Block.js').default} block */
@ -319,11 +323,9 @@ export default class AttributeWrapper extends BaseAttributeWrapper {
}); });
} }
stringify() { stringify() {
if (this.node.is_true) if (this.node.is_true) return '';
return '';
const value = this.node.chunks; const value = this.node.chunks;
if (value.length === 0) if (value.length === 0) return '=""';
return '=""';
return `="${value return `="${value
.map((chunk) => { .map((chunk) => {
return chunk.type === 'Text' return chunk.type === 'Text'
@ -392,8 +394,7 @@ const attribute_lookup = {
}; };
Object.keys(attribute_lookup).forEach((name) => { Object.keys(attribute_lookup).forEach((name) => {
const metadata = attribute_lookup[name]; const metadata = attribute_lookup[name];
if (!metadata.property_name) if (!metadata.property_name) metadata.property_name = name;
metadata.property_name = name;
}); });
/** @param {AttributeWrapper} attribute */ /** @param {AttributeWrapper} attribute */
@ -405,12 +406,14 @@ const regex_contains_checked_or_group = /checked|group/;
/** @param {AttributeWrapper} attribute */ /** @param {AttributeWrapper} attribute */
function is_indirectly_bound_value(attribute) { function is_indirectly_bound_value(attribute) {
const element = attribute.parent; const element = attribute.parent;
return (attribute.name === 'value' && return (
attribute.name === 'value' &&
(element.node.name === 'option' || // TODO check it's actually bound (element.node.name === 'option' || // TODO check it's actually bound
(element.node.name === 'input' && (element.node.name === 'input' &&
element.node.bindings.some((binding) => regex_contains_checked_or_group.test(binding.name))))); element.node.bindings.some((binding) =>
regex_contains_checked_or_group.test(binding.name)
)))
);
} }
/** @typedef {{ property_name?: string; applies_to?: string[] }} AttributeMetadata */ /** @typedef {{ property_name?: string; applies_to?: string[] }} AttributeMetadata */

Loading…
Cancel
Save