From 100057ac34677e2e62f0981880d18f2161490470 Mon Sep 17 00:00:00 2001 From: Nguyen Tran Date: Fri, 11 Aug 2023 23:21:43 -0400 Subject: [PATCH 1/7] Add tests for new @import syntax --- .../expected.css | 1 + .../input.svelte | 52 +++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 packages/svelte/test/css/samples/supports-import-layer-supports-media/expected.css create mode 100644 packages/svelte/test/css/samples/supports-import-layer-supports-media/input.svelte diff --git a/packages/svelte/test/css/samples/supports-import-layer-supports-media/expected.css b/packages/svelte/test/css/samples/supports-import-layer-supports-media/expected.css new file mode 100644 index 000000000000..b654f6d809f2 --- /dev/null +++ b/packages/svelte/test/css/samples/supports-import-layer-supports-media/expected.css @@ -0,0 +1 @@ +@import "theme.css";@import url(themes.css);@import url("http://themes.css");@import "theme.css" layer;@import url(theme.css) layer;@import url("http://themes.css") layer;@import "theme.css" layer(abcd);@import url(theme.css) layer(abcd);@import url("http://themes.css") layer(abcd);@import "theme.css" layer(abcd.efgh.ijkl);@import url(theme.css) layer(abcd.efgh.ijkl);@import url("http://themes.css") layer(abcd.efgh.ijkl);@import "theme.css" screen and (orientation: portrait);@import url(theme.css) screen and (orientation: portrait);@import url("http://themes.css") screen and (orientation: portrait);@import "theme.css" layer (min-width: 500px);@import url(theme.css) layer (min-width: 500px);@import url("http://themes.css") layer (min-width: 500px);@import "theme.css" layer(abcd) screen and (orientation: portrait);@import url(theme.css) layer(abcd) screen and (orientation: portrait);@import url("http://themes.css") layer(abcd) screen and (orientation: portrait);@import "theme.css" layer(abcd.efgh.ijkl) (min-width: 500px);@import url(theme.css) layer(abcd.efgh.ijkl) (min-width: 500px);@import url("http://themes.css") layer(abcd.efgh.ijkl) (min-width: 500px);@import "theme.css" supports((display: flex));@import url(themes.css) supports((selector(h2 > p)) and (font-tech(color-COLRv1)));@import url("http://themes.css") supports(not (display: grid) and (display: flex));@import "theme.css" layer supports((selector(h2 > p)) and (font-tech(color-COLRv1)));@import url(theme.css) layer supports(not (display: grid) and (display: flex));@import url("http://themes.css") layer supports((display: flex));@import "theme.css" layer(abcd) supports(not (display: grid) and (display: flex));@import url(theme.css) layer(abcd) supports((display: flex));@import url("http://themes.css") layer(abcd) supports((selector(h2 > p)) and (font-tech(color-COLRv1)));@import "theme.css" layer(abcd.efgh.ijkl) supports((display: flex));@import url(theme.css) layer(abcd.efgh.ijkl) supports((selector(h2 > p)) and (font-tech(color-COLRv1)));@import url("http://themes.css") layer(abcd.efgh.ijkl) supports(not (display: grid) and (display: flex));@import "theme.css" supports((selector(h2 > p)) and (font-tech(color-COLRv1))) screen and (orientation: portrait);@import url(theme.css) supports(not (display: grid) and (display: flex)) screen and (orientation: portrait);@import url("http://themes.css") supports((display: flex)) screen and (orientation: portrait);@import "theme.css" layer supports(not (display: grid) and (display: flex) (min-width: 500px));@import url(theme.css) layer supports((display : flex)) (min-width: 500px);@import url("http://themes.css") supports((selector(h2 > p)) and (font-tech(color-COLRv1))) layer (min-width: 500px);@import "theme.css" layer(abcd) supports(not (display: grid) and (display: flex)) screen and (orientation: portrait);@import url(theme.css) layer(abcd) supports((display : flex)) screen and (orientation: portrait);@import url("http://themes.css") layer(abcd) supports((selector(h2 > p)) and (font-tech(color-COLRv1))) screen and (orientation: portrait);@import "theme.css" layer(abcd.efgh.ijkl) supports(not (display: grid) and (display: flex)) (min-width: 500px);@import url(theme.css) layer(abcd.efgh.ijkl) supports((display : flex)) (min-width: 500px);@import url("http://themes.css") layer(abcd.efgh.ijkl) supports((selector(h2 > p)) and (font-tech(color-COLRv1))) (min-width: 500px); \ No newline at end of file diff --git a/packages/svelte/test/css/samples/supports-import-layer-supports-media/input.svelte b/packages/svelte/test/css/samples/supports-import-layer-supports-media/input.svelte new file mode 100644 index 000000000000..b67b9a05d431 --- /dev/null +++ b/packages/svelte/test/css/samples/supports-import-layer-supports-media/input.svelte @@ -0,0 +1,52 @@ + \ No newline at end of file From 4feb02836a22151dfc3c1a74d6075b37d5f628d3 Mon Sep 17 00:00:00 2001 From: Nguyen Tran Date: Fri, 11 Aug 2023 23:22:06 -0400 Subject: [PATCH 2/7] Implement the new @import syntax --- .../src/compiler/compile/css/Stylesheet.js | 3 +- .../parse/read/css-tree-cq/css_tree_parse.js | 59 ++++++++++++++++++- .../parse/read/css-tree-cq/node/index.js | 2 + .../parse/read/css-tree-cq/node/layer_name.js | 42 +++++++++++++ .../css-tree-cq/node/supports_condition.js | 22 +++++++ 5 files changed, 126 insertions(+), 2 deletions(-) create mode 100644 packages/svelte/src/compiler/parse/read/css-tree-cq/node/layer_name.js create mode 100644 packages/svelte/src/compiler/parse/read/css-tree-cq/node/supports_condition.js diff --git a/packages/svelte/src/compiler/compile/css/Stylesheet.js b/packages/svelte/src/compiler/compile/css/Stylesheet.js index d6bf41c13672..4a42f1a8f410 100644 --- a/packages/svelte/src/compiler/compile/css/Stylesheet.js +++ b/packages/svelte/src/compiler/compile/css/Stylesheet.js @@ -207,7 +207,8 @@ class Atrule { this.node.name === 'container' || this.node.name === 'media' || this.node.name === 'supports' || - this.node.name === 'layer' + this.node.name === 'layer' || + this.node.name === 'import' ) { this.children.forEach((child) => { child.apply(node); diff --git a/packages/svelte/src/compiler/parse/read/css-tree-cq/css_tree_parse.js b/packages/svelte/src/compiler/parse/read/css-tree-cq/css_tree_parse.js index bacb4cc33433..f3c9bbd394ac 100644 --- a/packages/svelte/src/compiler/parse/read/css-tree-cq/css_tree_parse.js +++ b/packages/svelte/src/compiler/parse/read/css-tree-cq/css_tree_parse.js @@ -1,5 +1,6 @@ // @ts-nocheck import { fork } from 'css-tree'; +import { String, Url, Function, RightParenthesis, Ident, Semicolon } from 'css-tree/tokenizer'; import * as node from './node/index.js'; @@ -20,7 +21,63 @@ const cqSyntax = fork({ return this.Block(isStyleBlock); } } - } + }, + // TODO: Wait until css-tree supports layer() or supports() for import and remove this + import: { + parse: { + prelude() { + const children = this.createList(); + + this.skipSC(); + + switch (this.tokenType) { + case String: + children.push(this.String()); + break; + + case Url: + case Function: + children.push(this.Url()); + break; + } + + this.skipSC(); + + if (this.tokenType == Function && this.cmpStr(this.tokenStart, this.tokenEnd, 'layer(')) { + children.push(this.Function(() => { + const children = this.createList(); + this.skipSC(); + children.push(this.LayerName()); + this.skipSC(); + return children; + }, this.scope.AtrulePrelude)); + } else if (this.tokenType == Ident && this.cmpStr(this.tokenStart, this.tokenEnd, 'layer')) { + children.push(this.Identifier()); + } + + this.skipSC(); + + if (this.tokenType == Function && this.cmpStr(this.tokenStart, this.tokenEnd, 'supports(')) { + children.push(this.Function(() => { + const children = this.createList(); + this.skipSC(); + children.push(this.SupportsCondition()); + this.skipSC(); + return children; + }, this.scope.AtrulePrelude)); + } + + this.skipSC(); + + if (this.tokenType !== Semicolon) { + children.push(this.MediaQueryList()); + } + + return children; + }, + block: null + } + }, }, node }); diff --git a/packages/svelte/src/compiler/parse/read/css-tree-cq/node/index.js b/packages/svelte/src/compiler/parse/read/css-tree-cq/node/index.js index b00ccba6a72e..5fb168b0d8c0 100644 --- a/packages/svelte/src/compiler/parse/read/css-tree-cq/node/index.js +++ b/packages/svelte/src/compiler/parse/read/css-tree-cq/node/index.js @@ -1,7 +1,9 @@ export * as Comparison from './comparison.js'; export * as ContainerFeatureStyle from './container_feature_style.js'; export * as ContainerQuery from './container_query.js'; +export * as LayerName from './layer_name.js'; export * as MediaQuery from './media_query.js'; export * as QueryFeature from './query_feature.js'; export * as QueryFeatureRange from './query_feature_range.js'; export * as QueryCSSFunction from './query_css_function.js'; +export * as SupportsCondition from './supports_condition.js'; diff --git a/packages/svelte/src/compiler/parse/read/css-tree-cq/node/layer_name.js b/packages/svelte/src/compiler/parse/read/css-tree-cq/node/layer_name.js new file mode 100644 index 000000000000..15ef84c49a05 --- /dev/null +++ b/packages/svelte/src/compiler/parse/read/css-tree-cq/node/layer_name.js @@ -0,0 +1,42 @@ +// @ts-nocheck +import { Delim } from 'css-tree/tokenizer'; + +const FULLSTOP = 0x002E; // U+002E FULL STOP (.) + +export const name = 'LayerName'; +export const structure = { + name: 'Identifier', + sublayer: ['LayerName', null], +}; + +// TODO: Wait for css-tree to support a layer name AST and remove this file +export function parse() { + const start = this.tokenStart; + const name = this.Identifier(); + + const char_idx = this.tokenStart; + const char_code = this.charCodeAt(char_idx); + + let sublayer; + if (char_code === FULLSTOP) { + this.next(); + sublayer = parse.call(this); + } else { + sublayer = null; + } + + return { + type: 'LayerName', + name, + sublayer, + loc: this.getLocation(start, this.tokenStart), + } +} + +export function generate(node) { + this.token(Ident, node.name); + this.token(Delim, "."); + if (node.sublayer !== null) { + generate.call(this, node.sublayer); + } +} diff --git a/packages/svelte/src/compiler/parse/read/css-tree-cq/node/supports_condition.js b/packages/svelte/src/compiler/parse/read/css-tree-cq/node/supports_condition.js new file mode 100644 index 000000000000..b0e50423f3d6 --- /dev/null +++ b/packages/svelte/src/compiler/parse/read/css-tree-cq/node/supports_condition.js @@ -0,0 +1,22 @@ +// @ts-nocheck +export const name = 'SupportsCondition'; +export const structure = { + children: [[]], +}; + +// TODO: Wait until css-tree has better @supports condition AST and remove this file +export function parse() { + const start = this.tokenStart; + const support_condition = this.atrule.supports.prelude.call(this); + + return { + type: 'SupportsCondition', + children: support_condition, + loc: this.getLocation(start, this.tokenStart) + }; +} + +export function generate(node) { + this.children(node); +} + From df98c48422d2788312a5b08f00ff1a7035db54d0 Mon Sep 17 00:00:00 2001 From: Nguyen Tran Date: Fri, 11 Aug 2023 23:30:52 -0400 Subject: [PATCH 3/7] Add changeset --- .changeset/odd-poems-admire.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/odd-poems-admire.md diff --git a/.changeset/odd-poems-admire.md b/.changeset/odd-poems-admire.md new file mode 100644 index 000000000000..7536dc0cde3f --- /dev/null +++ b/.changeset/odd-poems-admire.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +@import CSS at-rule now supports layer() and supports() syntax From 86a9e7459b5a8870722ecb1ca57e9f2871c88787 Mon Sep 17 00:00:00 2001 From: Nguyen Tran Date: Fri, 11 Aug 2023 23:35:06 -0400 Subject: [PATCH 4/7] Prettier --- .../parse/read/css-tree-cq/css_tree_parse.js | 48 +++++++++++-------- .../parse/read/css-tree-cq/node/layer_name.js | 16 +++---- .../css-tree-cq/node/supports_condition.js | 3 +- 3 files changed, 38 insertions(+), 29 deletions(-) diff --git a/packages/svelte/src/compiler/parse/read/css-tree-cq/css_tree_parse.js b/packages/svelte/src/compiler/parse/read/css-tree-cq/css_tree_parse.js index f3c9bbd394ac..ff821d85331b 100644 --- a/packages/svelte/src/compiler/parse/read/css-tree-cq/css_tree_parse.js +++ b/packages/svelte/src/compiler/parse/read/css-tree-cq/css_tree_parse.js @@ -1,6 +1,6 @@ // @ts-nocheck import { fork } from 'css-tree'; -import { String, Url, Function, RightParenthesis, Ident, Semicolon } from 'css-tree/tokenizer'; +import { String, Url, Function, Ident, Semicolon } from 'css-tree/tokenizer'; import * as node from './node/index.js'; @@ -44,31 +44,41 @@ const cqSyntax = fork({ this.skipSC(); if (this.tokenType == Function && this.cmpStr(this.tokenStart, this.tokenEnd, 'layer(')) { - children.push(this.Function(() => { - const children = this.createList(); - this.skipSC(); - children.push(this.LayerName()); - this.skipSC(); - return children; - }, this.scope.AtrulePrelude)); - } else if (this.tokenType == Ident && this.cmpStr(this.tokenStart, this.tokenEnd, 'layer')) { + children.push( + this.Function(() => { + const children = this.createList(); + this.skipSC(); + children.push(this.LayerName()); + this.skipSC(); + return children; + }, this.scope.AtrulePrelude) + ); + } else if ( + this.tokenType == Ident && + this.cmpStr(this.tokenStart, this.tokenEnd, 'layer') + ) { children.push(this.Identifier()); } this.skipSC(); - if (this.tokenType == Function && this.cmpStr(this.tokenStart, this.tokenEnd, 'supports(')) { - children.push(this.Function(() => { - const children = this.createList(); - this.skipSC(); - children.push(this.SupportsCondition()); - this.skipSC(); - return children; - }, this.scope.AtrulePrelude)); + if ( + this.tokenType == Function && + this.cmpStr(this.tokenStart, this.tokenEnd, 'supports(') + ) { + children.push( + this.Function(() => { + const children = this.createList(); + this.skipSC(); + children.push(this.SupportsCondition()); + this.skipSC(); + return children; + }, this.scope.AtrulePrelude) + ); } this.skipSC(); - + if (this.tokenType !== Semicolon) { children.push(this.MediaQueryList()); } @@ -77,7 +87,7 @@ const cqSyntax = fork({ }, block: null } - }, + } }, node }); diff --git a/packages/svelte/src/compiler/parse/read/css-tree-cq/node/layer_name.js b/packages/svelte/src/compiler/parse/read/css-tree-cq/node/layer_name.js index 15ef84c49a05..d1c7b78974d2 100644 --- a/packages/svelte/src/compiler/parse/read/css-tree-cq/node/layer_name.js +++ b/packages/svelte/src/compiler/parse/read/css-tree-cq/node/layer_name.js @@ -1,12 +1,12 @@ // @ts-nocheck import { Delim } from 'css-tree/tokenizer'; -const FULLSTOP = 0x002E; // U+002E FULL STOP (.) +const FULLSTOP = 0x002e; // U+002E FULL STOP (.) export const name = 'LayerName'; export const structure = { name: 'Identifier', - sublayer: ['LayerName', null], + sublayer: ['LayerName', null] }; // TODO: Wait for css-tree to support a layer name AST and remove this file @@ -18,8 +18,8 @@ export function parse() { const char_code = this.charCodeAt(char_idx); let sublayer; - if (char_code === FULLSTOP) { - this.next(); + if (char_code === FULLSTOP) { + this.next(); sublayer = parse.call(this); } else { sublayer = null; @@ -29,14 +29,14 @@ export function parse() { type: 'LayerName', name, sublayer, - loc: this.getLocation(start, this.tokenStart), - } + loc: this.getLocation(start, this.tokenStart) + }; } export function generate(node) { this.token(Ident, node.name); - this.token(Delim, "."); + this.token(Delim, '.'); if (node.sublayer !== null) { - generate.call(this, node.sublayer); + generate.call(this, node.sublayer); } } diff --git a/packages/svelte/src/compiler/parse/read/css-tree-cq/node/supports_condition.js b/packages/svelte/src/compiler/parse/read/css-tree-cq/node/supports_condition.js index b0e50423f3d6..afbcc954597e 100644 --- a/packages/svelte/src/compiler/parse/read/css-tree-cq/node/supports_condition.js +++ b/packages/svelte/src/compiler/parse/read/css-tree-cq/node/supports_condition.js @@ -1,7 +1,7 @@ // @ts-nocheck export const name = 'SupportsCondition'; export const structure = { - children: [[]], + children: [[]] }; // TODO: Wait until css-tree has better @supports condition AST and remove this file @@ -19,4 +19,3 @@ export function parse() { export function generate(node) { this.children(node); } - From 372a2fa5b3248f72ee527ed2dcfd911999e053c4 Mon Sep 17 00:00:00 2001 From: Nguyen Tran Date: Fri, 11 Aug 2023 23:41:05 -0400 Subject: [PATCH 5/7] Missing variable --- .../src/compiler/parse/read/css-tree-cq/node/layer_name.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/svelte/src/compiler/parse/read/css-tree-cq/node/layer_name.js b/packages/svelte/src/compiler/parse/read/css-tree-cq/node/layer_name.js index d1c7b78974d2..6aa74f30b8f6 100644 --- a/packages/svelte/src/compiler/parse/read/css-tree-cq/node/layer_name.js +++ b/packages/svelte/src/compiler/parse/read/css-tree-cq/node/layer_name.js @@ -1,5 +1,5 @@ // @ts-nocheck -import { Delim } from 'css-tree/tokenizer'; +import { Delim, Ident } from 'css-tree/tokenizer'; const FULLSTOP = 0x002e; // U+002E FULL STOP (.) From 1b18b91c69a7499033319b0d31d5e658c421eb56 Mon Sep 17 00:00:00 2001 From: Nguyen Tran Date: Sat, 12 Aug 2023 11:35:22 -0400 Subject: [PATCH 6/7] Triple equals vs double equals --- .../src/compiler/parse/read/css-tree-cq/css_tree_parse.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/svelte/src/compiler/parse/read/css-tree-cq/css_tree_parse.js b/packages/svelte/src/compiler/parse/read/css-tree-cq/css_tree_parse.js index ff821d85331b..ff827b0d037f 100644 --- a/packages/svelte/src/compiler/parse/read/css-tree-cq/css_tree_parse.js +++ b/packages/svelte/src/compiler/parse/read/css-tree-cq/css_tree_parse.js @@ -43,7 +43,7 @@ const cqSyntax = fork({ this.skipSC(); - if (this.tokenType == Function && this.cmpStr(this.tokenStart, this.tokenEnd, 'layer(')) { + if (this.tokenType === Function && this.cmpStr(this.tokenStart, this.tokenEnd, 'layer(')) { children.push( this.Function(() => { const children = this.createList(); @@ -54,7 +54,7 @@ const cqSyntax = fork({ }, this.scope.AtrulePrelude) ); } else if ( - this.tokenType == Ident && + this.tokenType === Ident && this.cmpStr(this.tokenStart, this.tokenEnd, 'layer') ) { children.push(this.Identifier()); @@ -63,7 +63,7 @@ const cqSyntax = fork({ this.skipSC(); if ( - this.tokenType == Function && + this.tokenType === Function && this.cmpStr(this.tokenStart, this.tokenEnd, 'supports(') ) { children.push( From 15bef57aecc3006b6aa88425a6f3b72b304b61cd Mon Sep 17 00:00:00 2001 From: Nguyen Tran Date: Sat, 12 Aug 2023 11:40:50 -0400 Subject: [PATCH 7/7] Prettier --- .../src/compiler/parse/read/css-tree-cq/css_tree_parse.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/svelte/src/compiler/parse/read/css-tree-cq/css_tree_parse.js b/packages/svelte/src/compiler/parse/read/css-tree-cq/css_tree_parse.js index ff827b0d037f..be2bcded6a7a 100644 --- a/packages/svelte/src/compiler/parse/read/css-tree-cq/css_tree_parse.js +++ b/packages/svelte/src/compiler/parse/read/css-tree-cq/css_tree_parse.js @@ -43,7 +43,10 @@ const cqSyntax = fork({ this.skipSC(); - if (this.tokenType === Function && this.cmpStr(this.tokenStart, this.tokenEnd, 'layer(')) { + if ( + this.tokenType === Function && + this.cmpStr(this.tokenStart, this.tokenEnd, 'layer(') + ) { children.push( this.Function(() => { const children = this.createList();