From f97ac27e2a9ed1139528fa1a4acf7f31a6f28ce8 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Fri, 30 Jun 2017 10:27:09 -0400 Subject: [PATCH] handle :global(...) styles --- src/generators/extractSelectors.ts | 10 +++- src/generators/shared/processCss.ts | 60 +++++++++++-------- test/css/index.js | 2 +- .../_config.js | 7 +++ .../expected.css | 4 ++ .../expected.html | 1 + .../input.html | 9 +++ .../_config.js | 7 +++ .../expected.css | 4 ++ .../expected.html | 1 + .../input.html | 7 +++ .../_config.js | 3 + .../expected.css | 4 ++ .../expected.html | 1 + .../input.html | 11 ++++ 15 files changed, 102 insertions(+), 29 deletions(-) create mode 100644 test/css/samples/omit-scoping-attribute-descendant-global-inner/_config.js create mode 100644 test/css/samples/omit-scoping-attribute-descendant-global-inner/expected.css create mode 100644 test/css/samples/omit-scoping-attribute-descendant-global-inner/expected.html create mode 100644 test/css/samples/omit-scoping-attribute-descendant-global-inner/input.html create mode 100644 test/css/samples/omit-scoping-attribute-descendant-global-outer/_config.js create mode 100644 test/css/samples/omit-scoping-attribute-descendant-global-outer/expected.css create mode 100644 test/css/samples/omit-scoping-attribute-descendant-global-outer/expected.html create mode 100644 test/css/samples/omit-scoping-attribute-descendant-global-outer/input.html create mode 100644 test/css/samples/omit-scoping-attribute-whitespace-multiple/_config.js create mode 100644 test/css/samples/omit-scoping-attribute-whitespace-multiple/expected.css create mode 100644 test/css/samples/omit-scoping-attribute-whitespace-multiple/expected.html create mode 100644 test/css/samples/omit-scoping-attribute-whitespace-multiple/input.html diff --git a/src/generators/extractSelectors.ts b/src/generators/extractSelectors.ts index 50a021ea6b..b0a1aee417 100644 --- a/src/generators/extractSelectors.ts +++ b/src/generators/extractSelectors.ts @@ -26,7 +26,7 @@ export default function extractSelectors(css: Node) :Node[] { function processSelector(selector: Node) { selectors.push({ - used: false, + used: false, // TODO use this! warn on unused selectors apply: (node: Node, stack: Node[]) => { const applies = selectorAppliesTo(selector.children, node, stack.slice()); @@ -52,9 +52,15 @@ function selectorAppliesTo(parts: Node[], node: Node, stack: Node[]) { let j = stack.length; while (i--) { - if (!node) return; const part = parts[i]; + if (part.type === 'PseudoClassSelector' && part.name === 'global') { + // bail + return true; + } + + if (!node) return false; + if (part.type === 'PseudoClassSelector' || part.type === 'PseudoElementSelector') { continue; } diff --git a/src/generators/shared/processCss.ts b/src/generators/shared/processCss.ts index 8ea6021452..b7281e8c8a 100644 --- a/src/generators/shared/processCss.ts +++ b/src/generators/shared/processCss.ts @@ -37,6 +37,29 @@ export default function processCss( parsed.css.children.forEach(walkKeyframes); + function transformBlock(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; + } + } + + code.appendLeft(child.end, attr); + return; + } + } + function transform(rule: Node) { rule.selector.children.forEach((selector: Node) => { if (cascade) { @@ -65,37 +88,22 @@ export default function processCss( let shouldTransform = true; let c = selector.start; + // 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]; + selector.children.forEach((child: Node) => { if (child.type === 'WhiteSpace' || child.type === 'Combinator') { - code.appendLeft(c, attr); - shouldTransform = true; - return; - } - - if (!shouldTransform) return; - - if (child.type === 'PseudoClassSelector') { - // `:global(xyz)` > xyz - 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); - } else { - code.prependRight(c, attr); - } - - shouldTransform = false; - } else if (child.type === 'PseudoElementSelector') { - code.prependRight(c, attr); - shouldTransform = false; + block = []; + blocks.push(block); + } else { + block.push(child); } - - c = child.end; }); - if (shouldTransform) { - code.appendLeft(c, attr); - } + transformBlock(blocks[0]); + if (blocks.length > 1) transformBlock(blocks[blocks.length - 1]); } }); diff --git a/test/css/index.js b/test/css/index.js index 9566667c65..3c4e427746 100644 --- a/test/css/index.js +++ b/test/css/index.js @@ -46,7 +46,7 @@ describe("css", () => { const Component = eval(`(function () { ${actual.code}; return SvelteComponent; }())`); const target = window.document.querySelector("main"); - new Component({ target }); + new Component({ target, data: config.data }); const html = target.innerHTML; fs.writeFileSync(`test/css/samples/${dir}/_actual.html`, html); diff --git a/test/css/samples/omit-scoping-attribute-descendant-global-inner/_config.js b/test/css/samples/omit-scoping-attribute-descendant-global-inner/_config.js new file mode 100644 index 0000000000..0371e65c7e --- /dev/null +++ b/test/css/samples/omit-scoping-attribute-descendant-global-inner/_config.js @@ -0,0 +1,7 @@ +export default { + cascade: false, + + data: { + raw: '

raw

' + } +}; \ No newline at end of file diff --git a/test/css/samples/omit-scoping-attribute-descendant-global-inner/expected.css b/test/css/samples/omit-scoping-attribute-descendant-global-inner/expected.css new file mode 100644 index 0000000000..67a7fbed86 --- /dev/null +++ b/test/css/samples/omit-scoping-attribute-descendant-global-inner/expected.css @@ -0,0 +1,4 @@ + + div[svelte-3744486606] > p { + color: red; + } diff --git a/test/css/samples/omit-scoping-attribute-descendant-global-inner/expected.html b/test/css/samples/omit-scoping-attribute-descendant-global-inner/expected.html new file mode 100644 index 0000000000..4511b72221 --- /dev/null +++ b/test/css/samples/omit-scoping-attribute-descendant-global-inner/expected.html @@ -0,0 +1 @@ +
\ No newline at end of file diff --git a/test/css/samples/omit-scoping-attribute-descendant-global-inner/input.html b/test/css/samples/omit-scoping-attribute-descendant-global-inner/input.html new file mode 100644 index 0000000000..bad6794f25 --- /dev/null +++ b/test/css/samples/omit-scoping-attribute-descendant-global-inner/input.html @@ -0,0 +1,9 @@ +
+ +
+ + \ No newline at end of file diff --git a/test/css/samples/omit-scoping-attribute-descendant-global-outer/_config.js b/test/css/samples/omit-scoping-attribute-descendant-global-outer/_config.js new file mode 100644 index 0000000000..0371e65c7e --- /dev/null +++ b/test/css/samples/omit-scoping-attribute-descendant-global-outer/_config.js @@ -0,0 +1,7 @@ +export default { + cascade: false, + + data: { + raw: '

raw

' + } +}; \ No newline at end of file diff --git a/test/css/samples/omit-scoping-attribute-descendant-global-outer/expected.css b/test/css/samples/omit-scoping-attribute-descendant-global-outer/expected.css new file mode 100644 index 0000000000..46c00c646d --- /dev/null +++ b/test/css/samples/omit-scoping-attribute-descendant-global-outer/expected.css @@ -0,0 +1,4 @@ + + div > p[svelte-794545435] { + color: red; + } diff --git a/test/css/samples/omit-scoping-attribute-descendant-global-outer/expected.html b/test/css/samples/omit-scoping-attribute-descendant-global-outer/expected.html new file mode 100644 index 0000000000..5c3c80ea93 --- /dev/null +++ b/test/css/samples/omit-scoping-attribute-descendant-global-outer/expected.html @@ -0,0 +1 @@ +

this may or may not be styled

\ No newline at end of file diff --git a/test/css/samples/omit-scoping-attribute-descendant-global-outer/input.html b/test/css/samples/omit-scoping-attribute-descendant-global-outer/input.html new file mode 100644 index 0000000000..e5fb3ba144 --- /dev/null +++ b/test/css/samples/omit-scoping-attribute-descendant-global-outer/input.html @@ -0,0 +1,7 @@ +

this may or may not be styled

+ + \ No newline at end of file diff --git a/test/css/samples/omit-scoping-attribute-whitespace-multiple/_config.js b/test/css/samples/omit-scoping-attribute-whitespace-multiple/_config.js new file mode 100644 index 0000000000..b37866f9b6 --- /dev/null +++ b/test/css/samples/omit-scoping-attribute-whitespace-multiple/_config.js @@ -0,0 +1,3 @@ +export default { + cascade: false +}; \ No newline at end of file diff --git a/test/css/samples/omit-scoping-attribute-whitespace-multiple/expected.css b/test/css/samples/omit-scoping-attribute-whitespace-multiple/expected.css new file mode 100644 index 0000000000..590f547006 --- /dev/null +++ b/test/css/samples/omit-scoping-attribute-whitespace-multiple/expected.css @@ -0,0 +1,4 @@ + + div[svelte-4032668709] section p[svelte-4032668709] { + color: red; + } diff --git a/test/css/samples/omit-scoping-attribute-whitespace-multiple/expected.html b/test/css/samples/omit-scoping-attribute-whitespace-multiple/expected.html new file mode 100644 index 0000000000..7a3dea1431 --- /dev/null +++ b/test/css/samples/omit-scoping-attribute-whitespace-multiple/expected.html @@ -0,0 +1 @@ +

this is styled

\ No newline at end of file diff --git a/test/css/samples/omit-scoping-attribute-whitespace-multiple/input.html b/test/css/samples/omit-scoping-attribute-whitespace-multiple/input.html new file mode 100644 index 0000000000..a3e4b4136a --- /dev/null +++ b/test/css/samples/omit-scoping-attribute-whitespace-multiple/input.html @@ -0,0 +1,11 @@ +
+
+

this is styled

+
+
+ + \ No newline at end of file