Skip to content

Commit

Permalink
chore: tidy up CSS stuff
Browse files Browse the repository at this point in the history
  • Loading branch information
Rich-Harris committed Feb 14, 2024
1 parent 643edc3 commit 34b35b6
Show file tree
Hide file tree
Showing 10 changed files with 111 additions and 110 deletions.
6 changes: 3 additions & 3 deletions packages/svelte/src/compiler/phases/1-parse/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export class Parser {
throw new TypeError('Template must be a string');
}

this.template = template.trimRight();
this.template = template.trimEnd();

let match_lang;

Expand Down Expand Up @@ -147,9 +147,9 @@ export class Parser {

/**
* @param {string} str
* @param {boolean} [required]
* @param {boolean} required
*/
eat(str, required) {
eat(str, required = false) {
if (this.match(str)) {
this.index += str.length;
return true;
Expand Down
101 changes: 54 additions & 47 deletions packages/svelte/src/compiler/phases/2-analyze/css/Selector.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { get_possible_values } from './gather_possible_values.js';
import { regex_starts_with_whitespace, regex_ends_with_whitespace } from '../../patterns.js';
import { error } from '../../../errors.js';
import { Stylesheet } from './Stylesheet.js';

const NO_MATCH = 'NO_MATCH';
const POSSIBLE_MATCH = 'POSSIBLE_MATCH';
Expand All @@ -22,7 +23,7 @@ export default class Selector {
/** @type {import('#compiler').Css.Selector} */
node;

/** @type {import('./Stylesheet.js').default} */
/** @type {import('./Stylesheet.js').Stylesheet} */
stylesheet;

/** @type {Block[]} */
Expand All @@ -31,39 +32,28 @@ export default class Selector {
/** @type {Block[]} */
local_blocks;

/** @type {boolean} */
used;
used = false;

/**
* @param {import('#compiler').Css.Selector} node
* @param {import('./Stylesheet.js').default} stylesheet
* @param {import('./Stylesheet.js').Stylesheet} stylesheet
*/
constructor(node, stylesheet) {
this.node = node;
this.stylesheet = stylesheet;
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;
}
this.local_blocks = this.blocks.slice(0, i);
const host_only = this.blocks.length === 1 && this.blocks[0].host;
const root_only = this.blocks.length === 1 && this.blocks[0].root;
this.used = this.local_blocks.length === 0 || host_only || root_only;
const i = this.blocks.findLastIndex((block) => !block.can_ignore());
this.local_blocks = this.blocks.slice(0, i + 1);

// if we have a `:root {...}` or `:global(...) {...}` selector, we need to mark
// this selector as `used` even if the component doesn't contain any nodes
this.used = this.local_blocks.length === 0;
}

/** @param {import('#compiler').RegularElement | import('#compiler').SvelteElement} node */
apply(node) {
/** @type {Array<{ node: import('#compiler').RegularElement | import('#compiler').SvelteElement; block: Block }>} */
const to_encapsulate = [];
apply_selector(this.local_blocks.slice(), node, to_encapsulate);
if (to_encapsulate.length > 0) {
to_encapsulate.forEach(({ node, block }) => {
this.stylesheet.nodes_with_css_class.add(node);
block.should_encapsulate = true;
});
if (apply_selector(this.local_blocks.slice(), node, this.stylesheet)) {
this.used = true;
}
}
Expand Down Expand Up @@ -130,6 +120,13 @@ export default class Selector {

/** @param {import('../../types.js').ComponentAnalysis} analysis */
validate(analysis) {
this.validate_global_placement();
this.validate_global_with_multiple_selectors();
this.validate_global_compound_selector();
this.validate_invalid_combinator_without_selector(analysis);
}

validate_global_placement() {
let start = 0;
let end = this.blocks.length;
for (; start < end; start += 1) {
Expand All @@ -143,9 +140,6 @@ export default class Selector {
error(this.blocks[i].selectors[0], 'invalid-css-global-placement');
}
}
this.validate_global_with_multiple_selectors();
this.validate_global_compound_selector();
this.validate_invalid_combinator_without_selector(analysis);
}

validate_global_with_multiple_selectors() {
Expand Down Expand Up @@ -207,10 +201,10 @@ export default class Selector {
/**
* @param {Block[]} blocks
* @param {import('#compiler').RegularElement | import('#compiler').SvelteElement | null} node
* @param {Array<{ node: import('#compiler').RegularElement | import('#compiler').SvelteElement; block: Block }>} to_encapsulate
* @param {Stylesheet} stylesheet
* @returns {boolean}
*/
function apply_selector(blocks, node, to_encapsulate) {
function apply_selector(blocks, node, stylesheet) {
const block = blocks.pop();
if (!block) return false;
if (!node) {
Expand All @@ -224,43 +218,52 @@ function apply_selector(blocks, node, to_encapsulate) {
return false;
}

if (applies === UNKNOWN_SELECTOR) {
to_encapsulate.push({ node, block });
/**
* Mark both the compound selector and the node it selects as encapsulated,
* for transformation in a later step
* @param {Block} block
* @param {import('#compiler').RegularElement | import('#compiler').SvelteElement} node
*/
function mark(block, node) {
block.should_encapsulate = true;
stylesheet.nodes_with_css_class.add(node);
return true;
}

if (applies === UNKNOWN_SELECTOR) {
return mark(block, node);
}

if (block.combinator) {
if (block.combinator.type === 'Combinator' && block.combinator.name === ' ') {
for (const ancestor_block of blocks) {
if (ancestor_block.global) {
continue;
}
if (ancestor_block.host) {
to_encapsulate.push({ node, block });
return true;
return mark(block, node);
}
/** @type {import('#compiler').RegularElement | import('#compiler').SvelteElement | null} */
let parent = node;
let matched = false;
while ((parent = get_element_parent(parent))) {
if (block_might_apply_to_node(ancestor_block, parent) !== NO_MATCH) {
to_encapsulate.push({ node: parent, block: ancestor_block });
mark(ancestor_block, parent);
matched = true;
}
}
if (to_encapsulate.length) {
to_encapsulate.push({ node, block });
return true;
if (matched) {
return mark(block, node);
}
}
if (blocks.every((block) => block.global)) {
to_encapsulate.push({ node, block });
return true;
return mark(block, node);
}
return false;
} else if (block.combinator.name === '>') {
const has_global_parent = blocks.every((block) => block.global);
if (has_global_parent || apply_selector(blocks, get_element_parent(node), to_encapsulate)) {
to_encapsulate.push({ node, block });
return true;
if (has_global_parent || apply_selector(blocks, get_element_parent(node), stylesheet)) {
return mark(block, node);
}
return false;
} else if (block.combinator.name === '+' || block.combinator.name === '~') {
Expand All @@ -274,23 +277,22 @@ function apply_selector(blocks, node, to_encapsulate) {
if (siblings.size === 0 && get_element_parent(node) !== null) {
return false;
}
to_encapsulate.push({ node, block });
return true;
return mark(block, node);
}
for (const possible_sibling of siblings.keys()) {
if (apply_selector(blocks.slice(), possible_sibling, to_encapsulate)) {
to_encapsulate.push({ node, block });
if (apply_selector(blocks.slice(), possible_sibling, stylesheet)) {
mark(block, node);
has_match = true;
}
}
return has_match;
}

// TODO other combinators
to_encapsulate.push({ node, block });
return true;
return mark(block, node);
}
to_encapsulate.push({ node, block });
return true;

return mark(block, node);
}

const regex_backslash_and_following_character = /\\(.)/g;
Expand Down Expand Up @@ -815,6 +817,11 @@ class Block {
this.selectors.push(selector);
this.end = selector.end;
}

can_ignore() {
return this.global || this.host || this.root;
}

get global() {
return (
this.selectors.length >= 1 &&
Expand Down
Loading

0 comments on commit 34b35b6

Please sign in to comment.