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

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

@ -6,332 +6,334 @@ import { namespaces } from '../../../../utils/namespaces.js';
import { boolean_attributes } from '../../../../../shared/boolean_attributes.js'; import { boolean_attributes } from '../../../../../shared/boolean_attributes.js';
import { regex_double_quotes } from '../../../../utils/patterns.js'; import { regex_double_quotes } from '../../../../utils/patterns.js';
const non_textlike_input_types = new Set([ const non_textlike_input_types = new Set([
'button', 'button',
'checkbox', 'checkbox',
'color', 'color',
'date', 'date',
'datetime-local', 'datetime-local',
'file', 'file',
'hidden', 'hidden',
'image', 'image',
'radio', 'radio',
'range', 'range',
'reset', 'reset',
'submit' 'submit'
]); ]);
/** */ /** */
export class BaseAttributeWrapper { export class BaseAttributeWrapper {
/** @type {import('../../../nodes/Attribute.js').default} */
node;
/** @type {import('../../../nodes/Attribute.js').default} */ /** @type {import('./index.js').default} */
node; parent;
constructor(parent, block, node) {
this.node = node;
this.parent = parent;
if (node.dependencies.size > 0) {
block.add_dependencies(node.dependencies);
}
}
/** @type {import('./index.js').default} */ /** @param {import('../../Block.js').default} _block */
parent; render(_block) {}
constructor(parent, block, node) {
this.node = node;
this.parent = parent;
if (node.dependencies.size > 0) {
block.add_dependencies(node.dependencies);
}
}
/** @param {import('../../Block.js').default} _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} */
node;
/** @type {import('../../../nodes/Attribute.js').default} */ /** @type {import('./index.js').default} */
node; parent;
/** @type {import('./index.js').default} */
parent;
/** @type {any} */ /** @type {any} */
metadata; metadata;
/** @type {string} */ /** @type {string} */
name; name;
/** @type {string} */ /** @type {string} */
property_name; property_name;
/** @type {boolean} */ /** @type {boolean} */
is_indirectly_bound_value; is_indirectly_bound_value;
/** @type {boolean} */ /** @type {boolean} */
is_src; is_src;
/** @type {boolean} */ /** @type {boolean} */
is_select_value_attribute; is_select_value_attribute;
/** @type {boolean} */ /** @type {boolean} */
is_input_value; is_input_value;
/** @type {boolean} */ /** @type {boolean} */
should_cache; should_cache;
/** @type {import('estree').Identifier} */ /** @type {import('estree').Identifier} */
last; last;
constructor(parent, block, node) { constructor(parent, block, node) {
super(parent, block, node); super(parent, block, node);
if (node.dependencies.size > 0) { if (node.dependencies.size > 0) {
// special case — <option value={foo}> — see below // special case — <option value={foo}> — see below
if (this.parent.node.name === 'option' && node.name === 'value') { if (this.parent.node.name === 'option' && node.name === 'value') {
let select = this.parent; let select = this.parent;
while (select && (select.node.type !== 'Element' || select.node.name !== 'select')) { while (select && (select.node.type !== 'Element' || select.node.name !== 'select')) {
// @ts-ignore todo: doublecheck this, but looks to be correct // @ts-ignore todo: doublecheck this, but looks to be correct
select = select.parent; select = select.parent;
} }
if (select && select.select_binding_dependencies) { if (select && select.select_binding_dependencies) {
select.select_binding_dependencies.forEach((prop) => { select.select_binding_dependencies.forEach((prop) => {
this.node.dependencies.forEach((dependency) => { this.node.dependencies.forEach((dependency) => {
this.parent.renderer.component.indirect_dependencies.get(prop).add(dependency); this.parent.renderer.component.indirect_dependencies.get(prop).add(dependency);
}); });
}); });
} }
} }
if (node.name === 'value') { if (node.name === 'value') {
handle_select_value_binding(this, node.dependencies); handle_select_value_binding(this, node.dependencies);
this.parent.has_dynamic_value = true; this.parent.has_dynamic_value = true;
} }
} }
if (this.parent.node.namespace == namespaces.foreign) { if (this.parent.node.namespace == namespaces.foreign) {
// leave attribute case alone for elements in the "foreign" namespace // leave attribute case alone for elements in the "foreign" namespace
this.name = this.node.name; this.name = this.node.name;
this.metadata = this.get_metadata(); this.metadata = this.get_metadata();
this.is_indirectly_bound_value = false; this.is_indirectly_bound_value = false;
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); this.property_name = this.is_indirectly_bound_value
this.property_name = this.is_indirectly_bound_value ? '__value'
? '__value' : this.metadata && this.metadata.property_name;
: this.metadata && this.metadata.property_name; this.is_select_value_attribute = this.name === 'value' && this.parent.node.name === 'select';
this.is_select_value_attribute = this.name === 'value' && this.parent.node.name === 'select'; this.is_input_value = this.name === 'value' && this.parent.node.name === 'input';
this.is_input_value = this.name === 'value' && this.parent.node.name === 'input'; }
} // TODO retire this exception in favour of https://github.com/sveltejs/svelte/issues/3750
// TODO retire this exception in favour of https://github.com/sveltejs/svelte/issues/3750 this.is_src =
this.is_src = this.name === 'src' &&
this.name === 'src' && (!this.parent.node.namespace || this.parent.node.namespace === namespaces.html);
(!this.parent.node.namespace || this.parent.node.namespace === namespaces.html); this.should_cache = should_cache(this);
this.should_cache = should_cache(this); }
}
/** @param {import('../../Block.js').default} block */ /** @param {import('../../Block.js').default} block */
render(block) { render(block) {
const element = this.parent; const element = this.parent;
const { name, property_name, should_cache, is_indirectly_bound_value } = this; const { name, property_name, should_cache, is_indirectly_bound_value } = this;
// xlink is a special case... we could maybe extend this to generic // xlink is a special case... we could maybe extend this to generic
// namespaced attributes but I'm not sure that's applicable in // namespaced attributes but I'm not sure that's applicable in
// HTML5? // HTML5?
const method = regex_minus_sign.test(element.node.name) const method = regex_minus_sign.test(element.node.name)
? '@set_custom_element_data' ? '@set_custom_element_data'
: 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 =
name === 'type' && element.renderer.component.compile_options.legacy &&
this.parent.node.name === 'input'; name === 'type' &&
const dependencies = this.get_dependencies(); this.parent.node.name === 'input';
const value = this.get_value(block); const dependencies = this.get_dependencies();
const value = this.get_value(block);
/** @type {Node[]} */ /** @type {Node[]} */
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 {
} updater = b`@select_option(${element.var}, ${value});`;
else { }
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};
`; `;
} }
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;
`; `;
} }
} }
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}
}`); }`);
} }
// special case autofocus. has to be handled in a bit of a weird way // special case autofocus. has to be handled in a bit of a weird way
if (name === 'autofocus') { if (name === 'autofocus') {
block.autofocus = { block.autofocus = {
element_var: element.var, element_var: element.var,
condition_expression: this.node.is_true ? undefined : value condition_expression: this.node.is_true ? undefined : value
}; };
} }
} }
/** /**
* @param {import('../../Block.js').default} block * @param {import('../../Block.js').default} block
* @param {any} value * @param {any} value
*/ */
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;
}
/** /**
* @param {import('../../Block.js').default} block * @param {import('../../Block.js').default} block
* @param {import('estree').Node} dependency_condition * @param {import('estree').Node} dependency_condition
*/ */
get_dom_update_conditions(block, dependency_condition) { get_dom_update_conditions(block, dependency_condition) {
const { property_name, should_cache, last } = this; const { property_name, should_cache, last } = this;
const element = this.parent; const element = this.parent;
const value = this.get_value(block); const value = this.get_value(block);
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) { }
condition = x `!#current || ${condition}`; }
} if (block.has_outros) {
return condition; condition = x`!#current || ${condition}`;
} }
get_dependencies() { return condition;
const node_dependencies = this.node.get_dependencies(); }
const dependencies = new Set(node_dependencies); get_dependencies() {
node_dependencies.forEach((prop) => { const node_dependencies = this.node.get_dependencies();
const indirect_dependencies = this.parent.renderer.component.indirect_dependencies.get(prop); const dependencies = new Set(node_dependencies);
if (indirect_dependencies) { node_dependencies.forEach((prop) => {
indirect_dependencies.forEach((indirect_dependency) => { const indirect_dependencies = this.parent.renderer.component.indirect_dependencies.get(prop);
dependencies.add(indirect_dependency); if (indirect_dependencies) {
}); indirect_dependencies.forEach((indirect_dependency) => {
} dependencies.add(indirect_dependency);
}); });
return Array.from(dependencies); }
} });
get_metadata() { return Array.from(dependencies);
if (this.parent.node.namespace) }
return null; get_metadata() {
const metadata = attribute_lookup[this.name]; if (this.parent.node.namespace) return null;
if (metadata && metadata.applies_to && !metadata.applies_to.includes(this.parent.node.name)) const metadata = attribute_lookup[this.name];
return null; if (metadata && metadata.applies_to && !metadata.applies_to.includes(this.parent.node.name))
return metadata; return null;
} return metadata;
}
/** @param {import('../../Block.js').default} block */ /** @param {import('../../Block.js').default} block */
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(
? string_literal(( /** @type {import('../../../nodes/Text.js').default} */(this.node.chunks[0])).data) /** @type {import('../../../nodes/Text.js').default} */ (this.node.chunks[0]).data
: ( /** @type {import('../../../nodes/shared/Expression.js').default} */(this.node.chunks[0])).manipulate(block); )
} : /** @type {import('../../../nodes/shared/Expression.js').default} */ (
let value = this.node.name === 'class' this.node.chunks[0]
? this.get_class_name_text(block) ).manipulate(block);
: this.render_chunks(block).reduce((lhs, rhs) => x `${lhs} + ${rhs}`); }
// '{foo} {bar}' — treat as string concatenation let value =
if (this.node.chunks[0].type !== 'Text') { this.node.name === 'class'
value = x `"" + ${value}`; ? this.get_class_name_text(block)
} : this.render_chunks(block).reduce((lhs, rhs) => x`${lhs} + ${rhs}`);
return value; // '{foo} {bar}' — treat as string concatenation
} if (this.node.chunks[0].type !== 'Text') {
value = x`"" + ${value}`;
}
return value;
}
/** @param {import('../../Block.js').default} block */ /** @param {import('../../Block.js').default} block */
get_class_name_text(block) { get_class_name_text(block) {
const scoped_css = this.node.chunks.some((chunk) => chunk.synthetic); const scoped_css = this.node.chunks.some((chunk) => chunk.synthetic);
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 */
render_chunks(block) { render_chunks(block) {
return this.node.chunks.map((chunk) => { return this.node.chunks.map((chunk) => {
if (chunk.type === 'Text') { if (chunk.type === 'Text') {
return string_literal(chunk.data); return string_literal(chunk.data);
} }
return chunk.manipulate(block); return chunk.manipulate(block);
}); });
} }
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) return '=""';
if (value.length === 0) return `="${value
return '=""'; .map((chunk) => {
return `="${value return chunk.type === 'Text'
.map((chunk) => { ? chunk.data.replace(regex_double_quotes, '\\"')
return chunk.type === 'Text' : `\${${chunk.manipulate()}}`;
? chunk.data.replace(regex_double_quotes, '\\"') })
: `\${${chunk.manipulate()}}`; .join('')}"`;
}) }
.join('')}"`;
}
} }
/** /**
* @type {{ [key in BooleanAttributes]: AttributeMetadata } & { * @type {{ [key in BooleanAttributes]: AttributeMetadata } & {
@ -339,78 +341,79 @@ export default class AttributeWrapper extends BaseAttributeWrapper {
* }} * }}
*/ */
const attribute_lookup = { const attribute_lookup = {
allowfullscreen: { property_name: 'allowFullscreen', applies_to: ['iframe'] }, allowfullscreen: { property_name: 'allowFullscreen', applies_to: ['iframe'] },
allowpaymentrequest: { property_name: 'allowPaymentRequest', applies_to: ['iframe'] }, allowpaymentrequest: { property_name: 'allowPaymentRequest', applies_to: ['iframe'] },
async: { applies_to: ['script'] }, async: { applies_to: ['script'] },
autofocus: { applies_to: ['button', 'input', 'keygen', 'select', 'textarea'] }, autofocus: { applies_to: ['button', 'input', 'keygen', 'select', 'textarea'] },
autoplay: { applies_to: ['audio', 'video'] }, autoplay: { applies_to: ['audio', 'video'] },
checked: { applies_to: ['input'] }, checked: { applies_to: ['input'] },
controls: { applies_to: ['audio', 'video'] }, controls: { applies_to: ['audio', 'video'] },
default: { applies_to: ['track'] }, default: { applies_to: ['track'] },
defer: { applies_to: ['script'] }, defer: { applies_to: ['script'] },
disabled: { disabled: {
applies_to: [ applies_to: [
'button', 'button',
'fieldset', 'fieldset',
'input', 'input',
'keygen', 'keygen',
'optgroup', 'optgroup',
'option', 'option',
'select', 'select',
'textarea' 'textarea'
] ]
}, },
formnovalidate: { property_name: 'formNoValidate', applies_to: ['button', 'input'] }, formnovalidate: { property_name: 'formNoValidate', applies_to: ['button', 'input'] },
hidden: {}, hidden: {},
indeterminate: { applies_to: ['input'] }, indeterminate: { applies_to: ['input'] },
inert: {}, inert: {},
ismap: { property_name: 'isMap', applies_to: ['img'] }, ismap: { property_name: 'isMap', applies_to: ['img'] },
loop: { applies_to: ['audio', 'bgsound', 'video'] }, loop: { applies_to: ['audio', 'bgsound', 'video'] },
multiple: { applies_to: ['input', 'select'] }, multiple: { applies_to: ['input', 'select'] },
muted: { applies_to: ['audio', 'video'] }, muted: { applies_to: ['audio', 'video'] },
nomodule: { property_name: 'noModule', applies_to: ['script'] }, nomodule: { property_name: 'noModule', applies_to: ['script'] },
novalidate: { property_name: 'noValidate', applies_to: ['form'] }, novalidate: { property_name: 'noValidate', applies_to: ['form'] },
open: { applies_to: ['details', 'dialog'] }, open: { applies_to: ['details', 'dialog'] },
playsinline: { property_name: 'playsInline', applies_to: ['video'] }, playsinline: { property_name: 'playsInline', applies_to: ['video'] },
readonly: { property_name: 'readOnly', applies_to: ['input', 'textarea'] }, readonly: { property_name: 'readOnly', applies_to: ['input', 'textarea'] },
required: { applies_to: ['input', 'select', 'textarea'] }, required: { applies_to: ['input', 'select', 'textarea'] },
reversed: { applies_to: ['ol'] }, reversed: { applies_to: ['ol'] },
selected: { applies_to: ['option'] }, selected: { applies_to: ['option'] },
value: { value: {
applies_to: [ applies_to: [
'button', 'button',
'option', 'option',
'input', 'input',
'li', 'li',
'meter', 'meter',
'progress', 'progress',
'param', 'param',
'select', 'select',
'textarea' 'textarea'
] ]
} }
}; };
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 */
function should_cache(attribute) { function should_cache(attribute) {
return attribute.is_src || attribute.node.should_cache(); return attribute.is_src || attribute.node.should_cache();
} }
const regex_contains_checked_or_group = /checked|group/; 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 (
(element.node.name === 'option' || // TODO check it's actually bound attribute.name === 'value' &&
(element.node.name === 'input' && (element.node.name === 'option' || // TODO check it's actually bound
element.node.bindings.some((binding) => regex_contains_checked_or_group.test(binding.name))))); (element.node.name === 'input' &&
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