From dd248bd15a44406c8dfff883beefd7276ae7fa7f Mon Sep 17 00:00:00 2001 From: Simon He <13917107469@163.com> Date: Tue, 8 Nov 2022 09:01:12 +0800 Subject: [PATCH] refactor: tidy up compile/css --- src/compiler/compile/css/Selector.ts | 75 ++++----- src/compiler/compile/css/Stylesheet.ts | 210 +++++++++++-------------- 2 files changed, 125 insertions(+), 160 deletions(-) diff --git a/src/compiler/compile/css/Selector.ts b/src/compiler/compile/css/Selector.ts index 07e2dc439e..8569ef8b64 100644 --- a/src/compiler/compile/css/Selector.ts +++ b/src/compiler/compile/css/Selector.ts @@ -42,11 +42,7 @@ export default class Selector { this.blocks = group_selectors(node); // take trailing :global(...) selectors out of consideration - let i = this.blocks.length; - while (i > 0) { - if (!this.blocks[i - 1].global) break; - i -= 1; - } + const i = this.blocks.findIndex(block => !block.global); this.local_blocks = this.blocks.slice(0, i); @@ -74,10 +70,8 @@ export default class Selector { minify(code: MagicString) { let c: number = null; this.blocks.forEach((block, i) => { - if (i > 0) { - if (block.start - c > 1) { - code.overwrite(c, block.start, block.combinator.name || ' '); - } + if (i > 0 && block.start - c > 1) { + code.overwrite(c, block.start, block.combinator.name || ' '); } c = block.end; @@ -105,8 +99,8 @@ export default class Selector { while (i--) { const selector = block.selectors[i]; if (selector.type === 'PseudoElementSelector' || selector.type === 'PseudoClassSelector') { - if (selector.name !== 'root' && selector.name !== 'host') { - if (i === 0) code.prependRight(selector.start, attr); + if (selector.name !== 'root' && selector.name !== 'host' && i === 0) { + code.prependRight(selector.start, attr); } continue; } @@ -159,10 +153,8 @@ export default class Selector { for (const block of this.blocks) { for (const selector of block.selectors) { - if (selector.type === 'PseudoClassSelector' && selector.name === 'global') { - if (regex_is_single_css_selector.test(selector.children[0].value)) { - component.error(selector, compiler_errors.css_invalid_global_selector); - } + if (selector.type === 'PseudoClassSelector' && selector.name === 'global' && regex_is_single_css_selector.test(selector.children[0].value)) { + component.error(selector, compiler_errors.css_invalid_global_selector); } } } @@ -183,7 +175,7 @@ export default class Selector { let count = 0; for (const block of this.blocks) { if (block.should_encapsulate) { - count ++; + count++; } } return count; @@ -206,7 +198,7 @@ function apply_selector(blocks: Block[], node: Element, to_encapsulate: Array<{ return false; case BlockAppliesToNode.UnknownSelectorType: - // bail. TODO figure out what these could be + // bail. TODO figure out what these could be to_encapsulate.push({ node, block }); return true; } @@ -293,11 +285,10 @@ function block_might_apply_to_node(block: Block, node: Element): BlockAppliesToN const selector = block.selectors[i]; const name = typeof selector.name === 'string' && selector.name.replace(regex_backslash_and_following_character, '$1'); - if (selector.type === 'PseudoClassSelector' && (name === 'host' || name === 'root')) { - return BlockAppliesToNode.NotPossible; - } - - if (block.selectors.length === 1 && selector.type === 'PseudoClassSelector' && name === 'global') { + if (( + selector.type === 'PseudoClassSelector' && (name === 'host' || name === 'root')) || + block.selectors.length === 1 && selector.type === 'PseudoClassSelector' && name === 'global' + ) { return BlockAppliesToNode.NotPossible; } @@ -343,9 +334,7 @@ function test_attribute(operator, expected_value, case_insensitive, value) { function attribute_matches(node: CssNode, name: string, expected_value: string, operator: string, case_insensitive: boolean) { const spread = node.attributes.find(attr => attr.type === 'Spread'); - if (spread) return true; - - if (node.bindings.some((binding: CssNode) => binding.name === name)) return true; + if (spread || node.bindings.some((binding: CssNode) => binding.name === name)) return true; const attr = node.attributes.find((attr: CssNode) => attr.name === name); if (!attr) return false; @@ -428,13 +417,10 @@ function attribute_matches(node: CssNode, name: string, expected_value: string, } prev_values.forEach(prev_value => possible_values.add(prev_value)); - if (possible_values.has(UNKNOWN)) return true; - - for (const value of possible_values) { - if (test_attribute(operator, expected_value, case_insensitive, value)) return true; - } - - return false; + return possible_values.has(UNKNOWN) || + [...possible_values].some(value => + test_attribute(operator, expected_value, case_insensitive, value) + ); } function unquote(value: CssNode) { @@ -469,8 +455,8 @@ function get_possible_element_siblings(node: INode, adjacent_only: boolean): Map add_to_map(possible_last_child, result); if (adjacent_only && has_definite_elements(possible_last_child)) { - return result; - } +return result; +} } } @@ -552,24 +538,21 @@ function get_possible_last_child(block: EachBlock | IfBlock | AwaitBlock, adjace } function has_definite_elements(result: Map): boolean { - if (result.size === 0) return false; - for (const exist of result.values()) { - if (exist === NodeExist.Definitely) { - return true; - } - } - return false; + return result.size === 0 + ? false + : [...result.values()].some(exist => exist === NodeExist.Definitely); } function add_to_map(from: Map, to: Map) { - from.forEach((exist, element) => { - to.set(element, higher_existence(exist, to.get(element))); - }); + from.forEach((exist, element) => + to.set(element, higher_existence(exist, to.get(element))) + ); } function higher_existence(exist1: NodeExist | null, exist2: NodeExist | null): NodeExist { - if (exist1 === undefined || exist2 === undefined) return exist1 || exist2; - return exist1 > exist2 ? exist1 : exist2; + return exist1 === undefined || exist2 === undefined + ? exist1 || exist2 + : Math.max(exist1, exist2); } function mark_as_probably(result: Map) { diff --git a/src/compiler/compile/css/Stylesheet.ts b/src/compiler/compile/css/Stylesheet.ts index 9a3cbe9d13..6cf5123fda 100644 --- a/src/compiler/compile/css/Stylesheet.ts +++ b/src/compiler/compile/css/Stylesheet.ts @@ -30,18 +30,14 @@ function minify_declarations( start: number, declarations: Declaration[] ): number { - let c = start; - - declarations.forEach((declaration, i) => { + return declarations.reduce((result, declaration, i) => { const separator = i > 0 ? ';' : ''; - if ((declaration.node.start - c) > separator.length) { - code.overwrite(c, declaration.node.start, separator); + if ((declaration.node.start - result) > separator.length) { + code.overwrite(result, declaration.node.start, separator); } declaration.minify(code); - c = declaration.node.end; - }); - - return c; + return declaration.node.end; + }, start); } class Rule { @@ -72,17 +68,16 @@ class Rule { let started = false; this.selectors.forEach((selector) => { - if (selector.used) { - const separator = started ? ',' : ''; - if ((selector.node.start - c) > separator.length) { - code.overwrite(c, selector.node.start, separator); - } + if (!selector.used) return; + const separator = started ? ',' : ''; + if ((selector.node.start - c) > separator.length) { + code.overwrite(c, selector.node.start, separator); + } - selector.minify(code); - c = selector.node.end; + selector.minify(code); + c = selector.node.end; - started = true; - } + started = true; }); code.remove(c, this.node.block.start); @@ -128,16 +123,14 @@ class Declaration { transform(code: MagicString, keyframes: Map) { const property = this.node.property && remove_css_prefix(this.node.property.toLowerCase()); - if (property === 'animation' || property === 'animation-name') { - this.node.value.children.forEach((block: CssNode) => { - if (block.type === 'Identifier') { - const name = block.name; - if (keyframes.has(name)) { - code.overwrite(block.start, block.end, keyframes.get(name)); - } - } - }); - } + if (property !== 'animation' && property !== 'animation-name') return; + this.node.value.children.forEach((block: CssNode) => { + if (block.type !== 'Identifier') return; + const name = block.name; + if (keyframes.has(name)) { + code.overwrite(block.start, block.end, keyframes.get(name)); + } + }); } minify(code: MagicString) { @@ -174,9 +167,7 @@ class Atrule { apply(node: Element) { if (this.node.name === 'media' || this.node.name === 'supports' || this.node.name === 'layer') { - this.children.forEach(child => { - child.apply(node); - }); + this.children.forEach(child => child.apply(node)); } else if (is_keyframes_node(this.node)) { this.children.forEach((rule: Rule) => { rule.selectors.forEach(selector => { @@ -246,17 +237,16 @@ class Atrule { transform(code: MagicString, id: string, keyframes: Map, max_amount_class_specificity_increased: number) { if (is_keyframes_node(this.node)) { this.node.prelude.children.forEach(({ type, name, start, end }: CssNode) => { - if (type === 'Identifier') { - if (name.startsWith('-global-')) { - code.remove(start, start + 8); - this.children.forEach((rule: Rule) => { - rule.selectors.forEach(selector => { - selector.used = true; - }); + if (type !== 'Identifier') return; + if (name.startsWith('-global-')) { + code.remove(start, start + 8); + this.children.forEach((rule: Rule) => { + rule.selectors.forEach(selector => { + selector.used = true; }); - } else { - code.overwrite(start, end, keyframes.get(name)); - } + }); + } else { + code.overwrite(start, end, keyframes.get(name)); } }); } @@ -267,17 +257,12 @@ class Atrule { } validate(component: Component) { - this.children.forEach(child => { - child.validate(component); - }); + this.children.forEach(child => child.validate(component)); } warn_on_unused_selector(handler: (selector: Selector) => void) { if (this.node.name !== 'media') return; - - this.children.forEach(child => { - child.warn_on_unused_selector(handler); - }); + this.children.forEach(child => child.warn_on_unused_selector(handler)); } get_max_amount_class_specificity_increased() { @@ -322,74 +307,75 @@ export default class Stylesheet { this.ast = ast; this.filename = filename; this.dev = dev; + if (!ast.css || !ast.css.children.length) { + this.has_styles = false; + return; + } - if (ast.css && ast.css.children.length) { - this.id = get_css_hash({ - filename, - name: component_name, - css: ast.css.content.styles, - hash - }); + this.id = get_css_hash({ + filename, + name: component_name, + css: ast.css.content.styles, + hash + }); - this.has_styles = true; - - const stack: Atrule[] = []; - let depth = 0; - let current_atrule: Atrule = null; - - walk(ast.css as any, { - enter: (node: any) => { - 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: CssNode) => { - 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; - } + this.has_styles = true; + + const stack: Atrule[] = []; + let depth = 0; + let current_atrule: Atrule = null; - if (node.type === 'Rule') { - const rule = new Rule(node, this, current_atrule); + walk(ast.css as any, { + enter: (node: any) => { + 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 (current_atrule) { - current_atrule.children.push(rule); - } else if (depth <= 1) { - this.children.push(rule); - } + if (is_keyframes_node(node)) { + node.prelude.children.forEach((expression: CssNode) => { + 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); } - depth += 1; - }, + current_atrule = atrule; + } - leave: (node: any) => { - if (node.type === 'Atrule') { - stack.pop(); - current_atrule = stack[stack.length - 1]; + 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; + }, - depth -= 1; + leave: (node: any) => { + if (node.type === 'Atrule') { + stack.pop(); + current_atrule = stack[stack.length - 1]; } - }); - } else { - this.has_styles = false; - } + + depth -= 1; + } + }); + } apply(node: Element) { @@ -402,15 +388,13 @@ export default class Stylesheet { } reify() { - this.nodes_with_css_class.forEach((node: Element) => { - node.add_css_class(); - }); + this.nodes_with_css_class.forEach((node: Element) => node.add_css_class()); } render(file: string, should_transform_selectors: boolean) { if (!this.has_styles) { - return { code: null, map: null }; - } +return { code: null, map: null }; +} const code = new MagicString(this.source); @@ -450,9 +434,7 @@ export default class Stylesheet { } validate(component: Component) { - this.children.forEach(child => { - child.validate(component); - }); + this.children.forEach(child => child.validate(component)); } warn_on_unused_selectors(component: Component) {