diff --git a/.changeset/pink-chairs-matter.md b/.changeset/pink-chairs-matter.md
new file mode 100644
index 0000000000..6a8a6e75f3
--- /dev/null
+++ b/.changeset/pink-chairs-matter.md
@@ -0,0 +1,5 @@
+---
+'svelte': patch
+---
+
+fix: preserve namespaces in CSS type selectors
diff --git a/packages/svelte/src/compiler/phases/1-parse/read/style.js b/packages/svelte/src/compiler/phases/1-parse/read/style.js
index 02e6d8d064..a07d7f6fea 100644
--- a/packages/svelte/src/compiler/phases/1-parse/read/style.js
+++ b/packages/svelte/src/compiler/phases/1-parse/read/style.js
@@ -204,15 +204,18 @@ function read_selector(parser, inside_pseudo_class = false) {
});
} else if (parser.eat('*')) {
let name = '*';
+ /** @type {string | undefined} */
+ let namespace;
if (parser.eat('|')) {
- // * is the namespace (which we ignore)
- name = read_identifier(parser);
+ namespace = name;
+ name = parser.eat('*') ? '*' : read_identifier(parser);
}
relative_selector.selectors.push({
type: 'TypeSelector',
name,
+ ...(namespace !== undefined && { namespace }),
start,
end: parser.index
});
@@ -314,15 +317,18 @@ function read_selector(parser, inside_pseudo_class = false) {
});
} else if (!parser.match_regex(REGEX_COMBINATOR)) {
let name = read_identifier(parser);
+ /** @type {string | undefined} */
+ let namespace;
if (parser.eat('|')) {
- // we ignore the namespace when trying to find matching element classes
- name = read_identifier(parser);
+ namespace = name;
+ name = parser.eat('*') ? '*' : read_identifier(parser);
}
relative_selector.selectors.push({
type: 'TypeSelector',
name,
+ ...(namespace !== undefined && { namespace }),
start,
end: parser.index
});
diff --git a/packages/svelte/src/compiler/phases/3-transform/css/index.js b/packages/svelte/src/compiler/phases/3-transform/css/index.js
index 537ab60a0e..bfeb426493 100644
--- a/packages/svelte/src/compiler/phases/3-transform/css/index.js
+++ b/packages/svelte/src/compiler/phases/3-transform/css/index.js
@@ -355,7 +355,11 @@ const visitors = {
continue;
}
- if (selector.type === 'TypeSelector' && selector.name === '*') {
+ if (
+ selector.type === 'TypeSelector' &&
+ selector.name === '*' &&
+ selector.namespace === undefined
+ ) {
context.state.code.update(selector.start, selector.end, modifier);
} else {
context.state.code.appendLeft(selector.end, modifier);
diff --git a/packages/svelte/src/compiler/print/index.js b/packages/svelte/src/compiler/print/index.js
index a3e10085de..4a78854e1e 100644
--- a/packages/svelte/src/compiler/print/index.js
+++ b/packages/svelte/src/compiler/print/index.js
@@ -520,6 +520,10 @@ function css_visitors(comments, js_comments) {
},
TypeSelector(node, context) {
+ if (node.namespace !== undefined) {
+ context.write(node.namespace === '*' ? '*' : escape_identifier(node.namespace));
+ context.write('|');
+ }
context.write(node.name === '*' ? node.name : escape_identifier(node.name));
}
};
diff --git a/packages/svelte/src/compiler/types/css.d.ts b/packages/svelte/src/compiler/types/css.d.ts
index b0a763b6a1..96b2bc3a7d 100644
--- a/packages/svelte/src/compiler/types/css.d.ts
+++ b/packages/svelte/src/compiler/types/css.d.ts
@@ -121,6 +121,7 @@ export namespace _CSS {
export interface TypeSelector extends BaseNode {
type: 'TypeSelector';
name: string;
+ namespace?: string;
}
export interface IdSelector extends BaseNode {
diff --git a/packages/svelte/tests/css/samples/namespaced-type-selector/expected.css b/packages/svelte/tests/css/samples/namespaced-type-selector/expected.css
new file mode 100644
index 0000000000..7672a34dcf
--- /dev/null
+++ b/packages/svelte/tests/css/samples/namespaced-type-selector/expected.css
@@ -0,0 +1,17 @@
+ @namespace svg url(http://www.w3.org/2000/svg);
+
+ svg|circle.svelte-xyz {
+ fill: red;
+ }
+
+ *|circle.svelte-xyz {
+ stroke: blue;
+ }
+
+ svg|*.svelte-xyz {
+ color: green;
+ }
+
+ *|*.svelte-xyz {
+ opacity: 0.5;
+ }
diff --git a/packages/svelte/tests/css/samples/namespaced-type-selector/input.svelte b/packages/svelte/tests/css/samples/namespaced-type-selector/input.svelte
new file mode 100644
index 0000000000..17586eab6f
--- /dev/null
+++ b/packages/svelte/tests/css/samples/namespaced-type-selector/input.svelte
@@ -0,0 +1,21 @@
+
+
+
diff --git a/packages/svelte/tests/print/samples/css-namespaced-type-selector/input.svelte b/packages/svelte/tests/print/samples/css-namespaced-type-selector/input.svelte
new file mode 100644
index 0000000000..5e170ceb2a
--- /dev/null
+++ b/packages/svelte/tests/print/samples/css-namespaced-type-selector/input.svelte
@@ -0,0 +1,10 @@
+
diff --git a/packages/svelte/tests/print/samples/css-namespaced-type-selector/output.svelte b/packages/svelte/tests/print/samples/css-namespaced-type-selector/output.svelte
new file mode 100644
index 0000000000..3723659b14
--- /dev/null
+++ b/packages/svelte/tests/print/samples/css-namespaced-type-selector/output.svelte
@@ -0,0 +1,12 @@
+
+
+
diff --git a/packages/svelte/types/index.d.ts b/packages/svelte/types/index.d.ts
index b89f61959f..aab3f4c0b4 100644
--- a/packages/svelte/types/index.d.ts
+++ b/packages/svelte/types/index.d.ts
@@ -1774,6 +1774,7 @@ declare module 'svelte/compiler' {
export interface TypeSelector extends BaseNode {
type: 'TypeSelector';
name: string;
+ namespace?: string;
}
export interface IdSelector extends BaseNode {