refactoring, and more :global(...) fixes

pull/689/head
Rich Harris 7 years ago
parent d9aa3ec5ae
commit 5499327a70

@ -12,12 +12,9 @@ export default function extractSelectors(css: Node) :Node[] {
rule.block.children.forEach(processRule);
return;
}
console.log(rule);
throw new Error('nope');
}
if (rule.type !== 'Rule') {
// TODO @media etc
throw new Error(`not supported: ${rule.type}`);
// TODO
throw new Error(`Not implemented: @${rule.name}. Please raise an issue at https://github.com/sveltejs/svelte/issues — thanks!`);
}
const selectors = rule.selector.children;
@ -110,12 +107,13 @@ function selectorAppliesTo(parts: Node[], node: Node, stack: Node[]) {
return selectorAppliesTo(parts.slice(0, i), stack.pop(), stack);
}
console.log(part);
// TODO other combinators
return true;
}
else {
throw new Error(`TODO ${part.type}`);
// bail. TODO figure out what these could be
return true;
}
}

@ -1,4 +1,5 @@
import MagicString from 'magic-string';
import { groupSelectors, isGlobalSelector } from '../../utils/css';
import { Parsed, Node } from '../../interfaces';
const commentsPattern = /\/\*[\s\S]*?\*\//g;
@ -37,23 +38,11 @@ export default function processCss(
parsed.css.children.forEach(walkKeyframes);
function transformBlock(block: Node[]) {
function encapsulateBlock(block: Node[]) {
let i = block.length;
while (i--) {
const child = block[i];
if (child.type === 'PseudoElementSelector') continue;
if (child.type === 'PseudoClassSelector') {
if (child.name === 'global') {
const first = child.children[0];
const last = child.children[child.children.length - 1];
code.remove(child.start, first.start).remove(last.end, child.end);
return;
} else {
continue;
}
}
if (child.type === 'PseudoElementSelector' || child.type === 'PseudoClassSelector') continue;
code.appendLeft(child.end, attr);
return;
@ -91,19 +80,20 @@ export default function processCss(
// separate .foo > .bar > .baz into three separate blocks, so
// that we can transform only the first and last
let block: Node[] = [];
const blocks: Node[][] = [block];
const blocks: Node[][] = groupSelectors(selector);
selector.children.forEach((child: Node) => {
if (child.type === 'WhiteSpace' || child.type === 'Combinator') {
block = [];
blocks.push(block);
} else {
block.push(child);
blocks.forEach((block: Node[], i) => {
if (i === 0 || i === blocks.length - 1) {
encapsulateBlock(blocks[i]);
}
});
transformBlock(blocks[0]);
if (blocks.length > 1) transformBlock(blocks[blocks.length - 1]);
if (isGlobalSelector(block)) {
const selector = block[0];
const first = selector.children[0];
const last = selector.children[selector.children.length - 1];
code.remove(selector.start, first.start).remove(last.end, selector.end);
}
});
}
});

@ -0,0 +1,21 @@
import { Node } from '../interfaces';
export function isGlobalSelector(block: Node[]) {
return block.length === 1 && block[0].type === 'PseudoClassSelector' && block[0].name === 'global';
}
export function groupSelectors(selector: Node) {
let block: Node[] = [];
const blocks: Node[][] = [block];
selector.children.forEach((child: Node) => {
if (child.type === 'WhiteSpace' || child.type === 'Combinator') {
block = [];
blocks.push(block);
} else {
block.push(child);
}
});
return blocks;
}

@ -0,0 +1,58 @@
import { groupSelectors, isGlobalSelector } from '../../utils/css';
import { Validator } from '../index';
import { Node } from '../../interfaces';
export default function validateCss(validator: Validator, css: Node) {
function validateRule(rule: Node) {
if (rule.type === 'Atrule') {
if (rule.name === 'keyframes') return;
if (rule.name == 'media') {
rule.block.children.forEach(validateRule);
return;
}
// TODO
throw new Error(`Not implemented: @${rule.name}. Please raise an issue at https://github.com/sveltejs/svelte/issues — thanks!`);
}
const selectors = rule.selector.children;
selectors.forEach(validateSelector);
}
function validateSelector(selector: Node) {
const blocks: Node[][] = groupSelectors(selector);
blocks.forEach((block, i) => {
if (block.find((part: Node) => part.type === 'PseudoClassSelector' && part.name === 'global')) {
// check that :global(...) is by itself
if (block.length !== 1) {
validator.error(`:global(...) cannot be mixed with non-global selectors`, block[0].start);
}
// check that :global(...) isn't sandwiched by other selectors
// if (i > 0 && i < blocks.length - 1) {
// validator.error(`:global(...) can be at the start or end of a selector sequence, but not in the middle`, block[0].start);
// }
}
});
let start = 0;
let end = blocks.length;
for (; start < end; start += 1) {
if (!isGlobalSelector(blocks[start])) break;
}
for (; end > start; end -= 1) {
if (!isGlobalSelector(blocks[end - 1])) break;
}
for (let i = start; i < end; i += 1) {
if (isGlobalSelector(blocks[i])) {
validator.error(`:global(...) can be at the start or end of a selector sequence, but not in the middle`, blocks[i][0].start);
}
}
}
css.children.forEach(validateRule);
}

@ -1,4 +1,5 @@
import validateJs from './js/index';
import validateCss from './css/index';
import validateHtml from './html/index';
import { getLocator, Location } from 'locate-character';
import getCodeFrame from '../utils/getCodeFrame';
@ -101,6 +102,10 @@ export default function validate(
validateJs(validator, parsed.js);
}
if (parsed.css) {
validateCss(validator, parsed.css);
}
if (parsed.html) {
validateHtml(validator, parsed.html);
}

@ -0,0 +1,9 @@
<div>
<!-- html injected somehow -->
</div>
<style>
div > :global(p) > :global(em) {
color: red;
}
</style>

@ -0,0 +1,7 @@
export default {
cascade: false,
data: {
raw: '<p>raw</p>'
}
};

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

@ -0,0 +1 @@
<p svelte-3390623146="">this may or may not be styled</p>

@ -0,0 +1,7 @@
<p>this may or may not be styled</p>
<style>
:global(div) > :global(section) > p {
color: red;
}
</style>

@ -0,0 +1,7 @@
export default {
cascade: false,
data: {
raw: '<p>raw</p>'
}
};

@ -0,0 +1,8 @@
[{
"message": ":global(...) can be at the start or end of a selector sequence, but not in the middle",
"loc": {
"line": 2,
"column": 6
},
"pos": 14
}]

@ -0,0 +1,5 @@
<style>
.foo :global(.bar) .baz {
color: red;
}
</style>

@ -0,0 +1,8 @@
[{
"message": ":global(...) cannot be mixed with non-global selectors",
"loc": {
"line": 2,
"column": 1
},
"pos": 9
}]

@ -0,0 +1,5 @@
<style>
:global(.foo).bar {
color: red;
}
</style>
Loading…
Cancel
Save