mirror of https://github.com/sveltejs/svelte
parent
d9aa3ec5ae
commit
5499327a70
@ -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);
|
||||||
|
}
|
@ -0,0 +1,4 @@
|
|||||||
|
|
||||||
|
div[svelte-3386191472] > p > em {
|
||||||
|
color: red;
|
||||||
|
}
|
@ -0,0 +1 @@
|
|||||||
|
<div svelte-3386191472=""></div>
|
@ -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…
Reference in new issue