move CSS analysis into preprocess

pull/689/head
Rich Harris 8 years ago
parent 72f39fd7f9
commit ab40007406

@ -216,13 +216,17 @@ export default class Generator {
}; };
} }
cssAppliesTo(node: Node, stack: Node[]) { applyCss(node: Node, stack: Node[]) {
if (!this.cssId) return;
if (this.cascade) {
if (stack.length === 0) node._needsCssAttribute = true;
return;
}
for (let i = 0; i < this.selectors.length; i += 1) { for (let i = 0; i < this.selectors.length; i += 1) {
const selector = this.selectors[i]; const selector = this.selectors[i];
if (selector.appliesTo(node, stack)) { selector.apply(node, stack);
selector.used = true;
return true;
}
} }
} }

@ -40,6 +40,7 @@ const preprocessors = {
block: Block, block: Block,
state: State, state: State,
node: Node, node: Node,
elementStack: Node[],
stripWhitespace: boolean stripWhitespace: boolean
) => { ) => {
const dependencies = block.findDependencies(node.expression); const dependencies = block.findDependencies(node.expression);
@ -55,6 +56,7 @@ const preprocessors = {
block: Block, block: Block,
state: State, state: State,
node: Node, node: Node,
elementStack: Node[],
stripWhitespace: boolean stripWhitespace: boolean
) => { ) => {
const dependencies = block.findDependencies(node.expression); const dependencies = block.findDependencies(node.expression);
@ -66,7 +68,14 @@ const preprocessors = {
node._state = getChildState(state, { basename, name }); node._state = getChildState(state, { basename, name });
}, },
Text: (generator: DomGenerator, block: Block, state: State, node: Node, stripWhitespace: boolean) => { Text: (
generator: DomGenerator,
block: Block,
state: State,
node: Node,
elementStack: Node[],
stripWhitespace: boolean
) => {
node._state = getChildState(state); node._state = getChildState(state);
if (!/\S/.test(node.data)) { if (!/\S/.test(node.data)) {
@ -83,6 +92,7 @@ const preprocessors = {
block: Block, block: Block,
state: State, state: State,
node: Node, node: Node,
elementStack: Node[],
stripWhitespace: boolean, stripWhitespace: boolean,
nextSibling: Node nextSibling: Node
) => { ) => {
@ -102,7 +112,7 @@ const preprocessors = {
node._state = getChildState(state); node._state = getChildState(state);
blocks.push(node._block); blocks.push(node._block);
preprocessChildren(generator, node._block, node._state, node, stripWhitespace, node); preprocessChildren(generator, node._block, node._state, node, elementStack, stripWhitespace, nextSibling);
if (node._block.dependencies.size > 0) { if (node._block.dependencies.size > 0) {
dynamic = true; dynamic = true;
@ -127,6 +137,7 @@ const preprocessors = {
node.else._block, node.else._block,
node.else._state, node.else._state,
node.else, node.else,
elementStack,
stripWhitespace, stripWhitespace,
nextSibling nextSibling
); );
@ -154,6 +165,7 @@ const preprocessors = {
block: Block, block: Block,
state: State, state: State,
node: Node, node: Node,
elementStack: Node[],
stripWhitespace: boolean, stripWhitespace: boolean,
nextSibling: Node nextSibling: Node
) => { ) => {
@ -202,7 +214,7 @@ const preprocessors = {
}); });
generator.blocks.push(node._block); generator.blocks.push(node._block);
preprocessChildren(generator, node._block, node._state, node, stripWhitespace, nextSibling); preprocessChildren(generator, node._block, node._state, node, elementStack, stripWhitespace, nextSibling);
block.addDependencies(node._block.dependencies); block.addDependencies(node._block.dependencies);
node._block.hasUpdateMethod = node._block.dependencies.size > 0; node._block.hasUpdateMethod = node._block.dependencies.size > 0;
@ -219,6 +231,7 @@ const preprocessors = {
node.else._block, node.else._block,
node.else._state, node.else._state,
node.else, node.else,
elementStack,
stripWhitespace, stripWhitespace,
nextSibling nextSibling
); );
@ -231,6 +244,7 @@ const preprocessors = {
block: Block, block: Block,
state: State, state: State,
node: Node, node: Node,
elementStack: Node[],
stripWhitespace: boolean, stripWhitespace: boolean,
nextSibling: Node nextSibling: Node
) => { ) => {
@ -315,6 +329,8 @@ const preprocessors = {
: state.namespace, : state.namespace,
allUsedContexts: [], allUsedContexts: [],
}); });
generator.applyCss(node, elementStack);
} }
if (node.children.length) { if (node.children.length) {
@ -328,12 +344,12 @@ const preprocessors = {
}); });
generator.blocks.push(node._block); generator.blocks.push(node._block);
preprocessChildren(generator, node._block, node._state, node, stripWhitespace, nextSibling); preprocessChildren(generator, node._block, node._state, node, elementStack, stripWhitespace, nextSibling);
block.addDependencies(node._block.dependencies); block.addDependencies(node._block.dependencies);
node._block.hasUpdateMethod = node._block.dependencies.size > 0; node._block.hasUpdateMethod = node._block.dependencies.size > 0;
} else { } else {
if (node.name === 'pre' || node.name === 'textarea') stripWhitespace = false; if (node.name === 'pre' || node.name === 'textarea') stripWhitespace = false;
preprocessChildren(generator, block, node._state, node, stripWhitespace, nextSibling); preprocessChildren(generator, block, node._state, node, elementStack.concat(node), stripWhitespace, nextSibling);
} }
} }
}, },
@ -344,6 +360,7 @@ function preprocessChildren(
block: Block, block: Block,
state: State, state: State,
node: Node, node: Node,
elementStack: Node[],
stripWhitespace: boolean, stripWhitespace: boolean,
nextSibling: Node nextSibling: Node
) { ) {
@ -373,7 +390,7 @@ function preprocessChildren(
cleaned.forEach((child: Node, i: number) => { cleaned.forEach((child: Node, i: number) => {
const preprocessor = preprocessors[child.type]; const preprocessor = preprocessors[child.type];
if (preprocessor) preprocessor(generator, block, state, child, stripWhitespace, cleaned[i + 1] || nextSibling); if (preprocessor) preprocessor(generator, block, state, child, elementStack, stripWhitespace, cleaned[i + 1] || nextSibling);
if (lastChild) { if (lastChild) {
lastChild.next = child; lastChild.next = child;
@ -432,7 +449,7 @@ export default function preprocess(
}; };
generator.blocks.push(block); generator.blocks.push(block);
preprocessChildren(generator, block, state, node, true, null); preprocessChildren(generator, block, state, node, [], true, null);
block.hasUpdateMethod = block.dependencies.size > 0; block.hasUpdateMethod = block.dependencies.size > 0;
return { block, state }; return { block, state };

@ -81,7 +81,8 @@ export default function visitElement(
} }
// add CSS encapsulation attribute // add CSS encapsulation attribute
if (generator.cssId && (generator.cascade ? state.isTopLevel : generator.cssAppliesTo(node, elementStack))) { // TODO add a helper for this, rather than repeating it
if (node._needsCssAttribute) {
block.builders.hydrate.addLine( block.builders.hydrate.addLine(
`@setAttribute( ${name}, '${generator.cssId}', '' );` `@setAttribute( ${name}, '${generator.cssId}', '' );`
); );

@ -6,6 +6,15 @@ export default function extractSelectors(css: Node) :Node[] {
const selectors = []; const selectors = [];
function processRule(rule: Node) { function processRule(rule: Node) {
if (rule.type === 'Atrule') {
if (rule.name === 'keyframes') return;
if (rule.name == 'media') {
rule.block.children.forEach(processRule);
return;
}
console.log(rule);
throw new Error('nope');
}
if (rule.type !== 'Rule') { if (rule.type !== 'Rule') {
// TODO @media etc // TODO @media etc
throw new Error(`not supported: ${rule.type}`); throw new Error(`not supported: ${rule.type}`);
@ -18,14 +27,37 @@ export default function extractSelectors(css: Node) :Node[] {
function processSelector(selector: Node) { function processSelector(selector: Node) {
selectors.push({ selectors.push({
used: false, used: false,
appliesTo: (node: Node, stack: Node[]) => { apply: (node: Node, stack: Node[]) => {
let i = selector.children.length; const applies = selectorAppliesTo(selector.children, node, stack.slice());
if (applies) {
node._needsCssAttribute = true;
if (selector.children.find(isDescendantSelector)) stack[0]._needsCssAttribute = true;
}
}
});
}
css.children.forEach(processRule);
return selectors;
}
function isDescendantSelector(selector: Node) {
return selector.type === 'WhiteSpace'; // TODO or '>'
}
function selectorAppliesTo(parts: Node[], node: Node, stack: Node[]) {
let i = parts.length;
let j = stack.length; let j = stack.length;
while (i--) { while (i--) {
if (!node) return false; if (!node) return;
const part = parts[i];
const part = selector.children[i]; if (part.type === 'PseudoClassSelector' || part.type === 'PseudoElementSelector') {
continue;
}
if (part.type === 'ClassSelector') { if (part.type === 'ClassSelector') {
if (!classMatches(node, part.name)) return false; if (!classMatches(node, part.name)) return false;
@ -36,22 +68,32 @@ export default function extractSelectors(css: Node) :Node[] {
} }
else if (part.type === 'WhiteSpace') { else if (part.type === 'WhiteSpace') {
node = stack[--j]; parts = parts.slice(0, i);
while (stack.length) {
if (selectorAppliesTo(parts, stack.pop(), stack)) {
return true;
}
} }
else { return false;
throw new Error(`TODO ${part.type}`);
} }
else if (part.type === 'Combinator') {
if (part.name === '>') {
return selectorAppliesTo(parts.slice(0, i), stack.pop(), stack);
} }
console.log(part);
return true; return true;
} }
});
}
css.children.forEach(processRule); else {
throw new Error(`TODO ${part.type}`);
}
}
return selectors; return true;
} }
function classMatches(node: Node, className: string) { function classMatches(node: Node, className: string) {

@ -1,4 +0,0 @@
div[svelte-1941127328] p[svelte-1941127328] {
color: red;
}

@ -1 +0,0 @@
<div svelte-1941127328=""><p svelte-1941127328="">this is styled</p></div>

@ -1,9 +0,0 @@
<div>
<p>this is styled</p>
</div>
<style>
div p {
color: red;
}
</style>

@ -0,0 +1,4 @@
div[svelte-2557028325] > p[svelte-2557028325] {
color: red;
}

@ -0,0 +1 @@
<div><section><p>this is not styled</p></section></div>

@ -0,0 +1,11 @@
<div>
<section>
<p>this is not styled</p>
</section>
</div>
<style>
div > p {
color: red;
}
</style>

@ -0,0 +1,4 @@
div[svelte-4240344240] p[svelte-4240344240] {
color: red;
}

@ -0,0 +1 @@
<div svelte-4240344240=""><section><p svelte-4240344240="">this is styled</p></section></div>

@ -0,0 +1,11 @@
<div>
<section>
<p>this is styled</p>
</section>
</div>
<style>
div p {
color: red;
}
</style>
Loading…
Cancel
Save