From 61ca4258985a37963eae85cdf0e9ea4450987467 Mon Sep 17 00:00:00 2001 From: Simon Holthausen Date: Fri, 12 May 2023 15:52:29 +0200 Subject: [PATCH] Lint and format src/compiler/compile/css/Stylesheet.js --- src/compiler/compile/css/Stylesheet.js | 945 ++++++++++++------------- 1 file changed, 467 insertions(+), 478 deletions(-) diff --git a/src/compiler/compile/css/Stylesheet.js b/src/compiler/compile/css/Stylesheet.js index 79251276a6..6faa9290c3 100644 --- a/src/compiler/compile/css/Stylesheet.js +++ b/src/compiler/compile/css/Stylesheet.js @@ -13,7 +13,7 @@ const regex_css_browser_prefix = /^-((webkit)|(moz)|(o)|(ms))-/; * @returns {string} */ function remove_css_prefix(name) { - return name.replace(regex_css_browser_prefix, ''); + return name.replace(regex_css_browser_prefix, ''); } /** @param {import('./private.js').CssNode} node */ @@ -23,7 +23,8 @@ const is_keyframes_node = (node) => remove_css_prefix(node.name) === 'keyframes' * @param {import('./private.js').CssNode} * @returns {true} */ -const at_rule_has_declaration = ({ block }) => block && block.children && block.children.find((node) => node.type === 'Declaration'); +const at_rule_has_declaration = ({ block }) => + block && block.children && block.children.find((node) => node.type === 'Declaration'); /** * @param {import('magic-string').default} code @@ -32,492 +33,480 @@ const at_rule_has_declaration = ({ block }) => block && block.children && block. * @returns {number} */ function minify_declarations(code, start, declarations) { - let c = start; - declarations.forEach((declaration, i) => { - const separator = i > 0 ? ';' : ''; - if (declaration.node.start - c > separator.length) { - code.update(c, declaration.node.start, separator); - } - declaration.minify(code); - c = declaration.node.end; - }); - return c; + let c = start; + declarations.forEach((declaration, i) => { + const separator = i > 0 ? ';' : ''; + if (declaration.node.start - c > separator.length) { + code.update(c, declaration.node.start, separator); + } + declaration.minify(code); + c = declaration.node.end; + }); + return c; } class Rule { - - /** @type {import('./Selector.js').default[]} */ - selectors; - - /** @type {Declaration[]} */ - declarations; - - /** @type {import('./private.js').CssNode} */ - node; - - /** @type {Atrule} */ - parent; - - /** - * @param {import('./private.js').CssNode} node - * @param {any} stylesheet - * @param {Atrule} [parent] - */ - constructor(node, stylesheet, parent) { - this.node = node; - this.parent = parent; - this.selectors = node.prelude.children.map((node) => new Selector(node, stylesheet)); - this.declarations = node.block.children.map((node) => new Declaration(node)); - } - - /** @param {import('../nodes/Element.js').default} node */ - apply(node) { - this.selectors.forEach((selector) => selector.apply(node)); // TODO move the logic in here? - } - - /** @param {boolean} dev */ - is_used(dev) { - if (this.parent && this.parent.node.type === 'Atrule' && is_keyframes_node(this.parent.node)) - return true; - if (this.declarations.length === 0) - return dev; - return this.selectors.some((s) => s.used); - } - - /** - * @param {import('magic-string').default} code - * @param {boolean} _dev - */ - minify(code, _dev) { - let c = this.node.start; - let started = false; - this.selectors.forEach((selector) => { - if (selector.used) { - const separator = started ? ',' : ''; - if (selector.node.start - c > separator.length) { - code.update(c, selector.node.start, separator); - } - selector.minify(code); - c = selector.node.end; - started = true; - } - }); - code.remove(c, this.node.block.start); - c = this.node.block.start + 1; - c = minify_declarations(code, c, this.declarations); - code.remove(c, this.node.block.end - 1); - } - - /** - * @param {import('magic-string').default} code - * @param {string} id - * @param {Map} keyframes - * @param {number} max_amount_class_specificity_increased - */ - transform(code, id, keyframes, max_amount_class_specificity_increased) { - if (this.parent && this.parent.node.type === 'Atrule' && is_keyframes_node(this.parent.node)) - return true; - const attr = `.${id}`; - this.selectors.forEach((selector) => selector.transform(code, attr, max_amount_class_specificity_increased)); - this.declarations.forEach((declaration) => declaration.transform(code, keyframes)); - } - - /** @param {import('../Component.js').default} component */ - validate(component) { - this.selectors.forEach((selector) => { - selector.validate(component); - }); - } - - /** @param {(selector: import('./Selector.js').default) => void} handler */ - warn_on_unused_selector(handler) { - this.selectors.forEach((selector) => { - if (!selector.used) - handler(selector); - }); - } - get_max_amount_class_specificity_increased() { - return Math.max(...this.selectors.map((selector) => selector.get_amount_class_specificity_increased())); - } + /** @type {import('./Selector.js').default[]} */ + selectors; + + /** @type {Declaration[]} */ + declarations; + + /** @type {import('./private.js').CssNode} */ + node; + + /** @type {Atrule} */ + parent; + + /** + * @param {import('./private.js').CssNode} node + * @param {any} stylesheet + * @param {Atrule} [parent] + */ + constructor(node, stylesheet, parent) { + this.node = node; + this.parent = parent; + this.selectors = node.prelude.children.map((node) => new Selector(node, stylesheet)); + this.declarations = node.block.children.map((node) => new Declaration(node)); + } + + /** @param {import('../nodes/Element.js').default} node */ + apply(node) { + this.selectors.forEach((selector) => selector.apply(node)); // TODO move the logic in here? + } + + /** @param {boolean} dev */ + is_used(dev) { + if (this.parent && this.parent.node.type === 'Atrule' && is_keyframes_node(this.parent.node)) + return true; + if (this.declarations.length === 0) return dev; + return this.selectors.some((s) => s.used); + } + + /** + * @param {import('magic-string').default} code + * @param {boolean} _dev + */ + minify(code, _dev) { + let c = this.node.start; + let started = false; + this.selectors.forEach((selector) => { + if (selector.used) { + const separator = started ? ',' : ''; + if (selector.node.start - c > separator.length) { + code.update(c, selector.node.start, separator); + } + selector.minify(code); + c = selector.node.end; + started = true; + } + }); + code.remove(c, this.node.block.start); + c = this.node.block.start + 1; + c = minify_declarations(code, c, this.declarations); + code.remove(c, this.node.block.end - 1); + } + + /** + * @param {import('magic-string').default} code + * @param {string} id + * @param {Map} keyframes + * @param {number} max_amount_class_specificity_increased + */ + transform(code, id, keyframes, max_amount_class_specificity_increased) { + if (this.parent && this.parent.node.type === 'Atrule' && is_keyframes_node(this.parent.node)) + return true; + const attr = `.${id}`; + this.selectors.forEach((selector) => + selector.transform(code, attr, max_amount_class_specificity_increased) + ); + this.declarations.forEach((declaration) => declaration.transform(code, keyframes)); + } + + /** @param {import('../Component.js').default} component */ + validate(component) { + this.selectors.forEach((selector) => { + selector.validate(component); + }); + } + + /** @param {(selector: import('./Selector.js').default) => void} handler */ + warn_on_unused_selector(handler) { + this.selectors.forEach((selector) => { + if (!selector.used) handler(selector); + }); + } + get_max_amount_class_specificity_increased() { + return Math.max( + ...this.selectors.map((selector) => selector.get_amount_class_specificity_increased()) + ); + } } class Declaration { - - /** @type {import('./private.js').CssNode} */ - node; - - /** @param {import('./private.js').CssNode} node */ - constructor(node) { - this.node = node; - } - - /** - * @param {import('magic-string').default} code - * @param {Map} keyframes - */ - transform(code, keyframes) { - const property = this.node.property && remove_css_prefix(this.node.property.toLowerCase()); - if (property === 'animation' || property === 'animation-name') { - this.node.value.children.forEach((block) => { - if (block.type === 'Identifier') { - const name = block.name; - if (keyframes.has(name)) { - code.update(block.start, block.end, keyframes.get(name)); - } - } - }); - } - } - - /** @param {import('magic-string').default} code */ - minify(code) { - if (!this.node.property) - return; // @apply, and possibly other weird cases? - const c = this.node.start + this.node.property.length; - const first = this.node.value.children ? this.node.value.children[0] : this.node.value; - // Don't minify whitespace in custom properties, since some browsers (Chromium < 99) - // treat --foo: ; and --foo:; differently - if (first.type === 'Raw' && regex_only_whitespaces.test(first.value)) - return; - let start = first.start; - while (regex_whitespace.test(code.original[start])) - start += 1; - if (start - c > 1) { - code.update(c, start, ':'); - } - } + /** @type {import('./private.js').CssNode} */ + node; + + /** @param {import('./private.js').CssNode} node */ + constructor(node) { + this.node = node; + } + + /** + * @param {import('magic-string').default} code + * @param {Map} keyframes + */ + transform(code, keyframes) { + const property = this.node.property && remove_css_prefix(this.node.property.toLowerCase()); + if (property === 'animation' || property === 'animation-name') { + this.node.value.children.forEach((block) => { + if (block.type === 'Identifier') { + const name = block.name; + if (keyframes.has(name)) { + code.update(block.start, block.end, keyframes.get(name)); + } + } + }); + } + } + + /** @param {import('magic-string').default} code */ + minify(code) { + if (!this.node.property) return; // @apply, and possibly other weird cases? + const c = this.node.start + this.node.property.length; + const first = this.node.value.children ? this.node.value.children[0] : this.node.value; + // Don't minify whitespace in custom properties, since some browsers (Chromium < 99) + // treat --foo: ; and --foo:; differently + if (first.type === 'Raw' && regex_only_whitespaces.test(first.value)) return; + let start = first.start; + while (regex_whitespace.test(code.original[start])) start += 1; + if (start - c > 1) { + code.update(c, start, ':'); + } + } } class Atrule { - - /** @type {import('./private.js').CssNode} */ - node; - - /** @type {Array} */ - children; - - /** @type {Declaration[]} */ - declarations; - - /** @param {import('./private.js').CssNode} node */ - constructor(node) { - this.node = node; - this.children = []; - this.declarations = []; - } - - /** @param {import('../nodes/Element.js').default} node */ - apply(node) { - if (this.node.name === 'container' || - this.node.name === 'media' || - this.node.name === 'supports' || - this.node.name === 'layer') { - this.children.forEach((child) => { - child.apply(node); - }); - } - else if (is_keyframes_node(this.node)) { - this.children.forEach((rule) => { - rule.selectors.forEach((selector) => { - selector.used = true; - }); - }); - } - } - - /** @param {boolean} _dev */ - is_used(_dev) { - return true; // TODO - } - - /** - * @param {import('magic-string').default} code - * @param {boolean} dev - */ - minify(code, dev) { - if (this.node.name === 'media') { - const expression_char = code.original[this.node.prelude.start]; - let c = this.node.start + (expression_char === '(' ? 6 : 7); - if (this.node.prelude.start > c) - code.remove(c, this.node.prelude.start); - this.node.prelude.children.forEach((query) => { - // TODO minify queries - c = query.end; - }); - code.remove(c, this.node.block.start); - } - else if (this.node.name === 'supports') { - let c = this.node.start + 9; - if (this.node.prelude.start - c > 1) - code.update(c, this.node.prelude.start, ' '); - this.node.prelude.children.forEach((query) => { - // TODO minify queries - c = query.end; - }); - code.remove(c, this.node.block.start); - } - else { - let c = this.node.start + this.node.name.length + 1; - if (this.node.prelude) { - if (this.node.prelude.start - c > 1) - code.update(c, this.node.prelude.start, ' '); - c = this.node.prelude.end; - } - if (this.node.block && this.node.block.start - c > 0) { - code.remove(c, this.node.block.start); - } - } - // TODO other atrules - if (this.node.block) { - let c = this.node.block.start + 1; - if (this.declarations.length) { - c = minify_declarations(code, c, this.declarations); - // if the atrule has children, leave the last declaration semicolon alone - if (this.children.length) - c++; - } - this.children.forEach((child) => { - if (child.is_used(dev)) { - code.remove(c, child.node.start); - child.minify(code, dev); - c = child.node.end; - } - }); - code.remove(c, this.node.block.end - 1); - } - } - - /** - * @param {import('magic-string').default} code - * @param {string} id - * @param {Map} keyframes - * @param {number} max_amount_class_specificity_increased - */ - transform(code, id, keyframes, max_amount_class_specificity_increased) { - if (is_keyframes_node(this.node)) { - this.node.prelude.children.forEach(({ type, name, start, end }) => { - if (type === 'Identifier') { - if (name.startsWith('-global-')) { - code.remove(start, start + 8); - this.children.forEach((rule) => { - rule.selectors.forEach((selector) => { - selector.used = true; - }); - }); - } - else { - code.update(start, end, keyframes.get(name)); - } - } - }); - } - this.children.forEach((child) => { - child.transform(code, id, keyframes, max_amount_class_specificity_increased); - }); - } - - /** @param {import('../Component.js').default} component */ - validate(component) { - this.children.forEach((child) => { - child.validate(component); - }); - } - - /** @param {(selector: import('./Selector.js').default) => void} handler */ - warn_on_unused_selector(handler) { - if (this.node.name !== 'media') - return; - this.children.forEach((child) => { - child.warn_on_unused_selector(handler); - }); - } - get_max_amount_class_specificity_increased() { - return Math.max(...this.children.map((rule) => rule.get_max_amount_class_specificity_increased())); - } + /** @type {import('./private.js').CssNode} */ + node; + + /** @type {Array} */ + children; + + /** @type {Declaration[]} */ + declarations; + + /** @param {import('./private.js').CssNode} node */ + constructor(node) { + this.node = node; + this.children = []; + this.declarations = []; + } + + /** @param {import('../nodes/Element.js').default} node */ + apply(node) { + if ( + this.node.name === 'container' || + this.node.name === 'media' || + this.node.name === 'supports' || + this.node.name === 'layer' + ) { + this.children.forEach((child) => { + child.apply(node); + }); + } else if (is_keyframes_node(this.node)) { + this.children.forEach((rule) => { + rule.selectors.forEach((selector) => { + selector.used = true; + }); + }); + } + } + + /** @param {boolean} _dev */ + is_used(_dev) { + return true; // TODO + } + + /** + * @param {import('magic-string').default} code + * @param {boolean} dev + */ + minify(code, dev) { + if (this.node.name === 'media') { + const expression_char = code.original[this.node.prelude.start]; + let c = this.node.start + (expression_char === '(' ? 6 : 7); + if (this.node.prelude.start > c) code.remove(c, this.node.prelude.start); + this.node.prelude.children.forEach((query) => { + // TODO minify queries + c = query.end; + }); + code.remove(c, this.node.block.start); + } else if (this.node.name === 'supports') { + let c = this.node.start + 9; + if (this.node.prelude.start - c > 1) code.update(c, this.node.prelude.start, ' '); + this.node.prelude.children.forEach((query) => { + // TODO minify queries + c = query.end; + }); + code.remove(c, this.node.block.start); + } else { + let c = this.node.start + this.node.name.length + 1; + if (this.node.prelude) { + if (this.node.prelude.start - c > 1) code.update(c, this.node.prelude.start, ' '); + c = this.node.prelude.end; + } + if (this.node.block && this.node.block.start - c > 0) { + code.remove(c, this.node.block.start); + } + } + // TODO other atrules + if (this.node.block) { + let c = this.node.block.start + 1; + if (this.declarations.length) { + c = minify_declarations(code, c, this.declarations); + // if the atrule has children, leave the last declaration semicolon alone + if (this.children.length) c++; + } + this.children.forEach((child) => { + if (child.is_used(dev)) { + code.remove(c, child.node.start); + child.minify(code, dev); + c = child.node.end; + } + }); + code.remove(c, this.node.block.end - 1); + } + } + + /** + * @param {import('magic-string').default} code + * @param {string} id + * @param {Map} keyframes + * @param {number} max_amount_class_specificity_increased + */ + transform(code, id, keyframes, max_amount_class_specificity_increased) { + if (is_keyframes_node(this.node)) { + this.node.prelude.children.forEach(({ type, name, start, end }) => { + if (type === 'Identifier') { + if (name.startsWith('-global-')) { + code.remove(start, start + 8); + this.children.forEach((rule) => { + rule.selectors.forEach((selector) => { + selector.used = true; + }); + }); + } else { + code.update(start, end, keyframes.get(name)); + } + } + }); + } + this.children.forEach((child) => { + child.transform(code, id, keyframes, max_amount_class_specificity_increased); + }); + } + + /** @param {import('../Component.js').default} component */ + validate(component) { + this.children.forEach((child) => { + child.validate(component); + }); + } + + /** @param {(selector: import('./Selector.js').default) => void} handler */ + warn_on_unused_selector(handler) { + if (this.node.name !== 'media') return; + this.children.forEach((child) => { + child.warn_on_unused_selector(handler); + }); + } + get_max_amount_class_specificity_increased() { + return Math.max( + ...this.children.map((rule) => rule.get_max_amount_class_specificity_increased()) + ); + } } /** @param {any} */ const get_default_css_hash = ({ css, hash }) => { - return `svelte-${hash(css)}`; + return `svelte-${hash(css)}`; }; export default class Stylesheet { - - /** @type {string} */ - source; - - /** @type {import('../../interfaces.js').Ast} */ - ast; - - /** @type {string} */ - filename; - - /** @type {boolean} */ - dev; - - /** @type {boolean} */ - has_styles; - - /** @type {string} */ - id; - - /** @type {Array} */ - children = []; - - /** @type {Map} */ - keyframes = new Map(); - - /** @type {Set} */ - nodes_with_css_class = new Set(); - /** - * @param {{ - * source: string; - * ast: import('../../interfaces.js').Ast; - * filename: string | undefined; - * component_name: string | undefined; - * dev: boolean; - * get_css_hash: import('../../interfaces.js').CssHashGetter; - * }} - */ - constructor({ source, ast, component_name, filename, dev, get_css_hash = get_default_css_hash }) { - this.source = source; - this.ast = ast; - this.filename = filename; - this.dev = dev; - if (ast.css && ast.css.children.length) { - this.id = get_css_hash({ - filename, - name: component_name, - css: ast.css.content.styles, - hash - }); - this.has_styles = true; - - /** @type {Atrule[]} */ - const stack = []; - let depth = 0; - - /** @type {Atrule} */ - let current_atrule = null; - walk(/** @type {any} */ (ast.css), { - enter: (node) => { - if (node.type === 'Atrule') { - const atrule = new Atrule(node); - stack.push(atrule); - if (current_atrule) { - current_atrule.children.push(atrule); - } - else if (depth <= 1) { - this.children.push(atrule); - } - if (is_keyframes_node(node)) { - node.prelude.children.forEach((expression) => { - if (expression.type === 'Identifier' && !expression.name.startsWith('-global-')) { - this.keyframes.set(expression.name, `${this.id}-${expression.name}`); - } - }); - } - else if (at_rule_has_declaration(node)) { - const at_rule_declarations = node.block.children - .filter((node) => node.type === 'Declaration') - .map((node) => new Declaration(node)); - push_array(atrule.declarations, at_rule_declarations); - } - current_atrule = atrule; - } - if (node.type === 'Rule') { - const rule = new Rule(node, this, current_atrule); - if (current_atrule) { - current_atrule.children.push(rule); - } - else if (depth <= 1) { - this.children.push(rule); - } - } - depth += 1; - }, - leave: (node) => { - if (node.type === 'Atrule') { - stack.pop(); - current_atrule = stack[stack.length - 1]; - } - depth -= 1; - } - }); - } - else { - this.has_styles = false; - } - } - - /** @param {import('../nodes/Element.js').default} node */ - apply(node) { - if (!this.has_styles) - return; - for (let i = 0; i < this.children.length; i += 1) { - const child = this.children[i]; - child.apply(node); - } - } - reify() { - this.nodes_with_css_class.forEach((node) => { - node.add_css_class(); - }); - } - - /** @param {string} file */ - render(file) { - if (!this.has_styles) { - return { code: null, map: null }; - } - const code = new MagicString(this.source); - walk(/** @type {any} */ (this.ast.css), { - enter: (node) => { - code.addSourcemapLocation(node.start); - code.addSourcemapLocation(node.end); - } - }); - const max = Math.max(...this.children.map((rule) => rule.get_max_amount_class_specificity_increased())); - this.children.forEach((child) => { - child.transform(code, this.id, this.keyframes, max); - }); - let c = 0; - this.children.forEach((child) => { - if (child.is_used(this.dev)) { - code.remove(c, child.node.start); - child.minify(code, this.dev); - c = child.node.end; - } - }); - code.remove(c, this.source.length); - return { - code: code.toString(), - map: code.generateMap({ - includeContent: true, - source: this.filename, - file - }) - }; - } - - /** @param {import('../Component.js').default} component */ - validate(component) { - this.children.forEach((child) => { - child.validate(component); - }); - } - - /** @param {import('../Component.js').default} component */ - warn_on_unused_selectors(component) { - const ignores = !this.ast.css - ? [] - : extract_ignores_above_position(this.ast.css.start, this.ast.html.children); - component.push_ignores(ignores); - this.children.forEach((child) => { - child.warn_on_unused_selector((selector) => { - component.warn(selector.node, compiler_warnings.css_unused_selector(this.source.slice(selector.node.start, selector.node.end))); - }); - }); - component.pop_ignores(); - } + /** @type {string} */ + source; + + /** @type {import('../../interfaces.js').Ast} */ + ast; + + /** @type {string} */ + filename; + + /** @type {boolean} */ + dev; + + /** @type {boolean} */ + has_styles; + + /** @type {string} */ + id; + + /** @type {Array} */ + children = []; + + /** @type {Map} */ + keyframes = new Map(); + + /** @type {Set} */ + nodes_with_css_class = new Set(); + /** + * @param {{ + * source: string; + * ast: import('../../interfaces.js').Ast; + * filename: string | undefined; + * component_name: string | undefined; + * dev: boolean; + * get_css_hash: import('../../interfaces.js').CssHashGetter; + * }} + */ + constructor({ source, ast, component_name, filename, dev, get_css_hash = get_default_css_hash }) { + this.source = source; + this.ast = ast; + this.filename = filename; + this.dev = dev; + if (ast.css && ast.css.children.length) { + this.id = get_css_hash({ + filename, + name: component_name, + css: ast.css.content.styles, + hash + }); + this.has_styles = true; + + /** @type {Atrule[]} */ + const stack = []; + let depth = 0; + + /** @type {Atrule} */ + let current_atrule = null; + walk(/** @type {any} */ (ast.css), { + enter: (node) => { + if (node.type === 'Atrule') { + const atrule = new Atrule(node); + stack.push(atrule); + if (current_atrule) { + current_atrule.children.push(atrule); + } else if (depth <= 1) { + this.children.push(atrule); + } + if (is_keyframes_node(node)) { + node.prelude.children.forEach((expression) => { + if (expression.type === 'Identifier' && !expression.name.startsWith('-global-')) { + this.keyframes.set(expression.name, `${this.id}-${expression.name}`); + } + }); + } else if (at_rule_has_declaration(node)) { + const at_rule_declarations = node.block.children + .filter((node) => node.type === 'Declaration') + .map((node) => new Declaration(node)); + push_array(atrule.declarations, at_rule_declarations); + } + current_atrule = atrule; + } + if (node.type === 'Rule') { + const rule = new Rule(node, this, current_atrule); + if (current_atrule) { + current_atrule.children.push(rule); + } else if (depth <= 1) { + this.children.push(rule); + } + } + depth += 1; + }, + leave: (node) => { + if (node.type === 'Atrule') { + stack.pop(); + current_atrule = stack[stack.length - 1]; + } + depth -= 1; + } + }); + } else { + this.has_styles = false; + } + } + + /** @param {import('../nodes/Element.js').default} node */ + apply(node) { + if (!this.has_styles) return; + for (let i = 0; i < this.children.length; i += 1) { + const child = this.children[i]; + child.apply(node); + } + } + reify() { + this.nodes_with_css_class.forEach((node) => { + node.add_css_class(); + }); + } + + /** @param {string} file */ + render(file) { + if (!this.has_styles) { + return { code: null, map: null }; + } + const code = new MagicString(this.source); + walk(/** @type {any} */ (this.ast.css), { + enter: (node) => { + code.addSourcemapLocation(node.start); + code.addSourcemapLocation(node.end); + } + }); + const max = Math.max( + ...this.children.map((rule) => rule.get_max_amount_class_specificity_increased()) + ); + this.children.forEach((child) => { + child.transform(code, this.id, this.keyframes, max); + }); + let c = 0; + this.children.forEach((child) => { + if (child.is_used(this.dev)) { + code.remove(c, child.node.start); + child.minify(code, this.dev); + c = child.node.end; + } + }); + code.remove(c, this.source.length); + return { + code: code.toString(), + map: code.generateMap({ + includeContent: true, + source: this.filename, + file + }) + }; + } + + /** @param {import('../Component.js').default} component */ + validate(component) { + this.children.forEach((child) => { + child.validate(component); + }); + } + + /** @param {import('../Component.js').default} component */ + warn_on_unused_selectors(component) { + const ignores = !this.ast.css + ? [] + : extract_ignores_above_position(this.ast.css.start, this.ast.html.children); + component.push_ignores(ignores); + this.children.forEach((child) => { + child.warn_on_unused_selector((selector) => { + component.warn( + selector.node, + compiler_warnings.css_unused_selector( + this.source.slice(selector.node.start, selector.node.end) + ) + ); + }); + }); + component.pop_ignores(); + } } - - - -