chore: css unused selector warnings (#11098)

The character adjustments in the existing warnings are because we remove some tabs from empty lines when initializing the Svelte 5 repo; the warnings were just not checked at that time yet.
pull/11093/head
Simon H 1 year ago committed by GitHub
parent ed9bab9200
commit d2b6159d2e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -36,7 +36,8 @@ export default function read_style(parser, start, attributes) {
content: { content: {
start: content_start, start: content_start,
end: content_end, end: content_end,
styles: parser.template.slice(content_start, content_end) styles: parser.template.slice(content_start, content_end),
comment: null
} }
}; };
} }

@ -283,8 +283,6 @@ export default function tag(parser) {
if (is_top_level_script_or_style) { if (is_top_level_script_or_style) {
parser.eat('>', true); parser.eat('>', true);
if (name === 'script') {
const content = read_script(parser, start, element.attributes);
/** @type {import('#compiler').Comment | null} */ /** @type {import('#compiler').Comment | null} */
let prev_comment = null; let prev_comment = null;
@ -302,6 +300,9 @@ export default function tag(parser) {
break; break;
} }
} }
if (name === 'script') {
const content = read_script(parser, start, element.attributes);
if (prev_comment) { if (prev_comment) {
// We take advantage of the fact that the root will never have leadingComments set, // We take advantage of the fact that the root will never have leadingComments set,
// and set the previous comment to it so that the warning mechanism can later // and set the previous comment to it so that the warning mechanism can later
@ -318,6 +319,7 @@ export default function tag(parser) {
} }
} else { } else {
const content = read_style(parser, start, element.attributes); const content = read_style(parser, start, element.attributes);
content.content.comment = prev_comment;
if (current.css) error(start, 'duplicate-style-element'); if (current.css) error(start, 'duplicate-style-element');
current.css = content; current.css = content;

@ -0,0 +1,34 @@
import { walk } from 'zimmerframe';
import { warn } from '../../../warnings.js';
import { is_keyframes_node } from '../../css.js';
/**
* @param {import('#compiler').Css.StyleSheet} stylesheet
* @param {import('../../types.js').RawWarning[]} warnings
*/
export function warn_unused(stylesheet, warnings) {
walk(stylesheet, { warnings, stylesheet }, visitors);
}
/** @type {import('zimmerframe').Visitors<import('#compiler').Css.Node, { warnings: import('../../types.js').RawWarning[], stylesheet: import('#compiler').Css.StyleSheet }>} */
const visitors = {
Atrule(node, context) {
if (!is_keyframes_node(node)) {
context.next();
}
},
PseudoClassSelector(node, context) {
if (node.name === 'is' || node.name === 'where') {
context.next();
}
},
ComplexSelector(node, context) {
if (!node.metadata.used) {
const content = context.state.stylesheet.content;
const text = content.styles.substring(node.start - content.start, node.end - content.start);
warn(context.state.warnings, node, context.path, 'css-unused-selector', text);
}
context.next();
}
};

@ -23,6 +23,7 @@ import { should_proxy_or_freeze } from '../3-transform/client/utils.js';
import { analyze_css } from './css/css-analyze.js'; import { analyze_css } from './css/css-analyze.js';
import { prune } from './css/css-prune.js'; import { prune } from './css/css-prune.js';
import { hash } from './utils.js'; import { hash } from './utils.js';
import { warn_unused } from './css/css-warn.js';
/** /**
* @param {import('#compiler').Script | null} script * @param {import('#compiler').Script | null} script
@ -548,6 +549,7 @@ export function analyze_component(root, source, options) {
for (const element of analysis.elements) { for (const element of analysis.elements) {
prune(analysis.css.ast, element); prune(analysis.css.ast, element);
} }
warn_unused(analysis.css.ast, analysis.warnings);
outer: for (const element of analysis.elements) { outer: for (const element of analysis.elements) {
if (element.metadata.scoped) { if (element.metadata.scoped) {

@ -1,3 +1,5 @@
import type { Comment } from '#compiler';
export namespace Css { export namespace Css {
export interface BaseNode { export interface BaseNode {
start: number; start: number;
@ -12,6 +14,8 @@ export namespace Css {
start: number; start: number;
end: number; end: number;
styles: string; styles: string;
/** Possible comment atop the style tag */
comment: Comment | null;
}; };
} }

@ -7,7 +7,8 @@ import {
/** @satisfies {Warnings} */ /** @satisfies {Warnings} */
const css = { const css = {
'unused-selector': () => 'Unused CSS selector' /** @param {string} name */
'css-unused-selector': (name) => `Unused CSS selector "${name}"`
}; };
/** @satisfies {Warnings} */ /** @satisfies {Warnings} */
@ -300,6 +301,11 @@ export function warn(array, node, path, code, ...args) {
) )
); );
} }
// Style nodes
if (current.type === 'StyleSheet' && current.content.comment) {
ignores.push(...current.content.comment.ignores);
}
} }
if (ignores.includes(code)) return; if (ignores.includes(code)) return;

@ -0,0 +1,20 @@
import { test } from '../../test';
export default test({
warnings: [
{
code: 'css-unused-selector',
end: {
character: 44,
column: 14,
line: 4
},
message: 'Unused CSS selector "p[type=\'B\' s]"',
start: {
character: 31,
column: 1,
line: 4
}
}
]
});

@ -0,0 +1,20 @@
import { test } from '../../test';
export default test({
warnings: [
{
code: 'css-unused-selector',
end: {
character: 33,
column: 6,
line: 6
},
message: 'Unused CSS selector "x y z"',
start: {
character: 28,
column: 1,
line: 6
}
}
]
});

@ -5,8 +5,8 @@ export default test({
{ {
code: 'css-unused-selector', code: 'css-unused-selector',
message: 'Unused CSS selector ".b ~ .c"', message: 'Unused CSS selector ".b ~ .c"',
start: { character: 199, column: 1, line: 13 }, start: { character: 198, column: 1, line: 13 },
end: { character: 206, column: 8, line: 13 } end: { character: 205, column: 8, line: 13 }
} }
] ]
}); });

@ -2,12 +2,19 @@ import { test } from '../../test';
export default test({ export default test({
warnings: [ warnings: [
// TODO {
// { code: 'css-unused-selector',
// code: 'css-unused-selector', end: {
// message: 'Unused CSS selector ".a ~ .b"', character: 479,
// start: { character: 111, column: 1, line: 10 }, column: 19,
// end: { character: 118, column: 8, line: 10 } line: 22
// }, },
message: 'Unused CSS selector ":global(.x) + .bar"',
start: {
character: 461,
column: 1,
line: 22
}
}
] ]
}); });

@ -2,12 +2,19 @@ import { test } from '../../test';
export default test({ export default test({
warnings: [ warnings: [
// TODO {
// { code: 'css-unused-selector',
// code: 'css-unused-selector', end: {
// message: 'Unused CSS selector ".a ~ .b"', character: 472,
// start: { character: 111, column: 1, line: 10 }, column: 19,
// end: { character: 118, column: 8, line: 10 } line: 22
// }, },
message: 'Unused CSS selector ":global(.x) + .bar"',
start: {
character: 454,
column: 1,
line: 22
}
}
] ]
}); });

@ -5,38 +5,38 @@ export default test({
{ {
code: 'css-unused-selector', code: 'css-unused-selector',
message: 'Unused CSS selector ".a ~ .b"', message: 'Unused CSS selector ".a ~ .b"',
start: { character: 111, column: 1, line: 10 }, start: { character: 110, column: 1, line: 10 },
end: { character: 118, column: 8, line: 10 } end: { character: 117, column: 8, line: 10 }
}, },
{ {
code: 'css-unused-selector', code: 'css-unused-selector',
message: 'Unused CSS selector ".b ~ .c"', message: 'Unused CSS selector ".b ~ .c"',
start: { character: 138, column: 1, line: 11 }, start: { character: 137, column: 1, line: 11 },
end: { character: 145, column: 8, line: 11 } end: { character: 144, column: 8, line: 11 }
}, },
{ {
code: 'css-unused-selector', code: 'css-unused-selector',
message: 'Unused CSS selector ".c ~ .f"', message: 'Unused CSS selector ".c ~ .f"',
start: { character: 165, column: 1, line: 12 }, start: { character: 164, column: 1, line: 12 },
end: { character: 172, column: 8, line: 12 } end: { character: 171, column: 8, line: 12 }
}, },
{ {
code: 'css-unused-selector', code: 'css-unused-selector',
message: 'Unused CSS selector ".f ~ .g"', message: 'Unused CSS selector ".f ~ .g"',
start: { character: 192, column: 1, line: 13 }, start: { character: 191, column: 1, line: 13 },
end: { character: 199, column: 8, line: 13 } end: { character: 198, column: 8, line: 13 }
}, },
{ {
code: 'css-unused-selector', code: 'css-unused-selector',
message: 'Unused CSS selector ".b ~ .f"', message: 'Unused CSS selector ".b ~ .f"',
start: { character: 219, column: 1, line: 14 }, start: { character: 218, column: 1, line: 14 },
end: { character: 226, column: 8, line: 14 } end: { character: 225, column: 8, line: 14 }
}, },
{ {
code: 'css-unused-selector', code: 'css-unused-selector',
message: 'Unused CSS selector ".b ~ .g"', message: 'Unused CSS selector ".b ~ .g"',
start: { character: 246, column: 1, line: 15 }, start: { character: 245, column: 1, line: 15 },
end: { character: 253, column: 8, line: 15 } end: { character: 252, column: 8, line: 15 }
} }
] ]
}); });

@ -2,12 +2,19 @@ import { test } from '../../test';
export default test({ export default test({
warnings: [ warnings: [
// TODO {
// { code: 'css-unused-selector',
// code: 'css-unused-selector', end: {
// message: 'Unused CSS selector ".a ~ .b"', character: 496,
// start: { character: 111, column: 1, line: 10 }, column: 10,
// end: { character: 118, column: 8, line: 10 } line: 26
// }, },
message: 'Unused CSS selector ".x + .bar"',
start: {
character: 487,
column: 1,
line: 26
}
}
] ]
}); });

@ -6,12 +6,12 @@ export default test({
code: 'css-unused-selector', code: 'css-unused-selector',
message: 'Unused CSS selector ":host > span"', message: 'Unused CSS selector ":host > span"',
start: { start: {
character: 147, character: 145,
column: 1, column: 1,
line: 18 line: 18
}, },
end: { end: {
character: 159, character: 157,
column: 13, column: 13,
line: 18 line: 18
} }

@ -0,0 +1,20 @@
import { test } from '../../test';
export default test({
warnings: [
{
code: 'css-unused-selector',
end: {
character: 38,
column: 11,
line: 6
},
message: 'Unused CSS selector "z"',
start: {
character: 37,
column: 10,
line: 6
}
}
]
});

@ -0,0 +1,104 @@
import { test } from '../../test';
export default test({
warnings: [
{
code: 'css-unused-selector',
end: {
character: 239,
column: 13,
line: 20
},
message: 'Unused CSS selector ".unused"',
start: {
character: 232,
column: 6,
line: 20
}
},
{
code: 'css-unused-selector',
end: {
character: 302,
column: 10,
line: 27
},
message: 'Unused CSS selector ".unused"',
start: {
character: 295,
column: 3,
line: 27
}
},
{
code: 'css-unused-selector',
end: {
character: 328,
column: 6,
line: 30
},
message: 'Unused CSS selector ".c"',
start: {
character: 326,
column: 4,
line: 30
}
},
{
code: 'css-unused-selector',
end: {
character: 381,
column: 10,
line: 37
},
message: 'Unused CSS selector ".unused"',
start: {
character: 374,
column: 3,
line: 37
}
},
{
code: 'css-unused-selector',
end: {
character: 471,
column: 7,
line: 47
},
message: 'Unused CSS selector "& &"',
start: {
character: 468,
column: 4,
line: 47
}
},
{
code: 'css-unused-selector',
end: {
character: 634,
column: 5,
line: 66
},
message: 'Unused CSS selector "&.b"',
start: {
character: 631,
column: 2,
line: 66
}
},
{
code: 'css-unused-selector',
end: {
character: 666,
column: 9,
line: 70
},
message: 'Unused CSS selector ".unused"',
start: {
character: 659,
column: 2,
line: 70
}
}
]
});

@ -5,62 +5,62 @@ export default test({
{ {
code: 'css-unused-selector', code: 'css-unused-selector',
message: 'Unused CSS selector ".a + .c"', message: 'Unused CSS selector ".a + .c"',
start: { character: 479, column: 1, line: 23 }, start: { character: 478, column: 1, line: 23 },
end: { character: 486, column: 8, line: 23 } end: { character: 485, column: 8, line: 23 }
}, },
{ {
code: 'css-unused-selector', code: 'css-unused-selector',
message: 'Unused CSS selector ".a + .g"', message: 'Unused CSS selector ".a + .g"',
start: { character: 506, column: 1, line: 24 }, start: { character: 505, column: 1, line: 24 },
end: { character: 513, column: 8, line: 24 } end: { character: 512, column: 8, line: 24 }
}, },
{ {
code: 'css-unused-selector', code: 'css-unused-selector',
message: 'Unused CSS selector ".b + .e"', message: 'Unused CSS selector ".b + .e"',
start: { character: 533, column: 1, line: 25 }, start: { character: 532, column: 1, line: 25 },
end: { character: 540, column: 8, line: 25 } end: { character: 539, column: 8, line: 25 }
}, },
{ {
code: 'css-unused-selector', code: 'css-unused-selector',
message: 'Unused CSS selector ".c + .g"', message: 'Unused CSS selector ".c + .g"',
start: { character: 560, column: 1, line: 26 }, start: { character: 559, column: 1, line: 26 },
end: { character: 567, column: 8, line: 26 } end: { character: 566, column: 8, line: 26 }
}, },
{ {
code: 'css-unused-selector', code: 'css-unused-selector',
message: 'Unused CSS selector ".c + .k"', message: 'Unused CSS selector ".c + .k"',
start: { character: 587, column: 1, line: 27 }, start: { character: 586, column: 1, line: 27 },
end: { character: 594, column: 8, line: 27 } end: { character: 593, column: 8, line: 27 }
}, },
{ {
code: 'css-unused-selector', code: 'css-unused-selector',
message: 'Unused CSS selector ".d + .d"', message: 'Unused CSS selector ".d + .d"',
start: { character: 614, column: 1, line: 28 }, start: { character: 613, column: 1, line: 28 },
end: { character: 621, column: 8, line: 28 } end: { character: 620, column: 8, line: 28 }
}, },
{ {
code: 'css-unused-selector', code: 'css-unused-selector',
message: 'Unused CSS selector ".e + .f"', message: 'Unused CSS selector ".e + .f"',
start: { character: 641, column: 1, line: 29 }, start: { character: 640, column: 1, line: 29 },
end: { character: 648, column: 8, line: 29 } end: { character: 647, column: 8, line: 29 }
}, },
{ {
code: 'css-unused-selector', code: 'css-unused-selector',
message: 'Unused CSS selector ".f + .f"', message: 'Unused CSS selector ".f + .f"',
start: { character: 668, column: 1, line: 30 }, start: { character: 667, column: 1, line: 30 },
end: { character: 675, column: 8, line: 30 } end: { character: 674, column: 8, line: 30 }
}, },
{ {
code: 'css-unused-selector', code: 'css-unused-selector',
message: 'Unused CSS selector ".g + .j"', message: 'Unused CSS selector ".g + .j"',
start: { character: 695, column: 1, line: 31 }, start: { character: 694, column: 1, line: 31 },
end: { character: 702, column: 8, line: 31 } end: { character: 701, column: 8, line: 31 }
}, },
{ {
code: 'css-unused-selector', code: 'css-unused-selector',
message: 'Unused CSS selector ".g + .h + .i + .j"', message: 'Unused CSS selector ".g + .h + .i + .j"',
start: { character: 722, column: 1, line: 32 }, start: { character: 721, column: 1, line: 32 },
end: { character: 739, column: 18, line: 32 } end: { character: 738, column: 18, line: 32 }
} }
] ]
}); });

@ -5,14 +5,14 @@ export default test({
{ {
code: 'css-unused-selector', code: 'css-unused-selector',
message: 'Unused CSS selector ".a + .d"', message: 'Unused CSS selector ".a + .d"',
start: { character: 172, column: 1, line: 12 }, start: { character: 171, column: 1, line: 12 },
end: { character: 179, column: 8, line: 12 } end: { character: 178, column: 8, line: 12 }
}, },
{ {
code: 'css-unused-selector', code: 'css-unused-selector',
message: 'Unused CSS selector ".b + .c"', message: 'Unused CSS selector ".b + .c"',
start: { character: 199, column: 1, line: 13 }, start: { character: 198, column: 1, line: 13 },
end: { character: 206, column: 8, line: 13 } end: { character: 205, column: 8, line: 13 }
} }
] ]
}); });

@ -5,20 +5,20 @@ export default test({
{ {
code: 'css-unused-selector', code: 'css-unused-selector',
message: 'Unused CSS selector ".a + .b"', message: 'Unused CSS selector ".a + .b"',
start: { character: 84, column: 1, line: 9 }, start: { character: 83, column: 1, line: 9 },
end: { character: 91, column: 8, line: 9 } end: { character: 90, column: 8, line: 9 }
}, },
{ {
code: 'css-unused-selector', code: 'css-unused-selector',
message: 'Unused CSS selector ".b + .c"', message: 'Unused CSS selector ".b + .c"',
start: { character: 111, column: 1, line: 10 }, start: { character: 110, column: 1, line: 10 },
end: { character: 118, column: 8, line: 10 } end: { character: 117, column: 8, line: 10 }
}, },
{ {
code: 'css-unused-selector', code: 'css-unused-selector',
message: 'Unused CSS selector ".c + .f"', message: 'Unused CSS selector ".c + .f"',
start: { character: 138, column: 1, line: 11 }, start: { character: 137, column: 1, line: 11 },
end: { character: 145, column: 8, line: 11 } end: { character: 144, column: 8, line: 11 }
} }
] ]
}); });

@ -5,20 +5,20 @@ export default test({
{ {
code: 'css-unused-selector', code: 'css-unused-selector',
message: 'Unused CSS selector "article > *"', message: 'Unused CSS selector "article > *"',
start: { character: 10, column: 1, line: 2 }, start: { character: 9, column: 1, line: 2 },
end: { character: 21, column: 12, line: 2 } end: { character: 20, column: 12, line: 2 }
}, },
{ {
code: 'css-unused-selector', code: 'css-unused-selector',
message: 'Unused CSS selector "article *"', message: 'Unused CSS selector "article *"',
start: { character: 49, column: 1, line: 6 }, start: { character: 47, column: 1, line: 6 },
end: { character: 58, column: 10, line: 6 } end: { character: 56, column: 10, line: 6 }
}, },
{ {
code: 'css-unused-selector', code: 'css-unused-selector',
message: 'Unused CSS selector ".article > *"', message: 'Unused CSS selector ".article > *"',
start: { character: 86, column: 1, line: 10 }, start: { character: 83, column: 1, line: 10 },
end: { character: 98, column: 13, line: 10 } end: { character: 95, column: 13, line: 10 }
} }
] ]
}); });

@ -0,0 +1,20 @@
import { test } from '../../test';
export default test({
warnings: [
{
code: 'css-unused-selector',
end: {
character: 32,
column: 3,
line: 5
},
message: 'Unused CSS selector "h2"',
start: {
character: 30,
column: 1,
line: 5
}
}
]
});

@ -8,12 +8,17 @@ import { mount, unmount } from 'svelte';
import { suite, type BaseTest } from '../suite.js'; import { suite, type BaseTest } from '../suite.js';
import type { CompileOptions, Warning } from '#compiler'; import type { CompileOptions, Warning } from '#compiler';
// function normalize_warning(warning) { function normalize_warning(warning: Warning) {
// warning.frame = warning.frame.replace(/^\n/, '').replace(/^\t+/gm, '').replace(/\s+$/gm, ''); delete warning.filename;
// delete warning.filename; return warning;
// delete warning.toString; }
// return warning;
// } function load_warnings(path: string) {
if (!fs.existsSync(path)) {
return [];
}
return JSON.parse(fs.readFileSync(path, 'utf-8')).map(normalize_warning);
}
interface CssTest extends BaseTest { interface CssTest extends BaseTest {
compileOptions?: Partial<CompileOptions>; compileOptions?: Partial<CompileOptions>;
@ -22,9 +27,6 @@ interface CssTest extends BaseTest {
} }
const { test, run } = suite<CssTest>(async (config, cwd) => { const { test, run } = suite<CssTest>(async (config, cwd) => {
// TODO
// const expected_warnings = (config.warnings || []).map(normalize_warning);
await compile_directory(cwd, 'client', { cssHash: () => 'svelte-xyz', ...config.compileOptions }); await compile_directory(cwd, 'client', { cssHash: () => 'svelte-xyz', ...config.compileOptions });
await compile_directory(cwd, 'server', { cssHash: () => 'svelte-xyz', ...config.compileOptions }); await compile_directory(cwd, 'server', { cssHash: () => 'svelte-xyz', ...config.compileOptions });
@ -33,11 +35,11 @@ const { test, run } = suite<CssTest>(async (config, cwd) => {
assert.equal(dom_css, ssr_css); assert.equal(dom_css, ssr_css);
// TODO reenable const dom_warnings = load_warnings(`${cwd}/_output/client/input.svelte.warnings.json`);
// const dom_warnings = dom.warnings.map(normalize_warning); const ssr_warnings = load_warnings(`${cwd}/_output/server/input.svelte.warnings.json`);
// const ssr_warnings = ssr.warnings.map(normalize_warning); const expected_warnings = (config.warnings || []).map(normalize_warning);
// assert.deepEqual(dom_warnings, ssr_warnings); assert.deepEqual(dom_warnings, ssr_warnings);
// assert.deepEqual(dom_warnings.map(normalize_warning), expected_warnings); assert.deepEqual(dom_warnings.map(normalize_warning), expected_warnings);
const expected = { const expected = {
html: try_read_file(`${cwd}/expected.html`), html: try_read_file(`${cwd}/expected.html`),

@ -71,7 +71,7 @@ export async function compile_directory(
for (const file of glob('**', { cwd, filesOnly: true })) { for (const file of glob('**', { cwd, filesOnly: true })) {
if (file.startsWith('_')) continue; if (file.startsWith('_')) continue;
let text = fs.readFileSync(`${cwd}/${file}`, 'utf-8'); let text = fs.readFileSync(`${cwd}/${file}`, 'utf-8').replace(/\r\n/g, '\n');
let opts = { let opts = {
filename: path.join(cwd, file), filename: path.join(cwd, file),
...compileOptions, ...compileOptions,
@ -138,6 +138,10 @@ export async function compile_directory(
write(`${output_dir}/${file}.css.map`, JSON.stringify(compiled.css.map, null, '\t')); write(`${output_dir}/${file}.css.map`, JSON.stringify(compiled.css.map, null, '\t'));
} }
} }
if (compiled.warnings.length > 0) {
write(`${output_dir}/${file}.warnings.json`, JSON.stringify(compiled.warnings, null, '\t'));
}
} }
} }
} }

@ -78,6 +78,7 @@
"content": { "content": {
"start": 23, "start": 23,
"end": 48, "end": 48,
"comment": null,
"styles": "\n\tdiv {\n\t\tcolor: red;\n\t}\n" "styles": "\n\tdiv {\n\t\tcolor: red;\n\t}\n"
} }
} }

@ -78,6 +78,7 @@
"content": { "content": {
"start": 23, "start": 23,
"end": 48, "end": 48,
"comment": null,
"styles": "\n\tdiv {\n\t\tcolor: red;\n\t}\n" "styles": "\n\tdiv {\n\t\tcolor: red;\n\t}\n"
} }
} }

@ -1074,6 +1074,7 @@
"content": { "content": {
"start": 7, "start": 7,
"end": 798, "end": 798,
"comment": null,
"styles": "\n /* test that all these are parsed correctly */\n\th1:nth-of-type(2n+1){\n background: red;\n }\n h1:nth-child(-n + 3 of li.important) {\n background: red;\n }\n h1:nth-child(1) {\n background: red;\n }\n h1:nth-child(p) {\n background: red;\n }\n h1:nth-child(n+7) {\n background: red;\n }\n h1:nth-child(even) {\n background: red;\n }\n h1:nth-child(odd) {\n background: red;\n }\n h1:nth-child(\n n\n ) {\n background: red;\n }\n h1:global(nav) {\n background: red;\n }\n\t\th1:nth-of-type(10n+1){\n background: red;\n }\n\t\th1:nth-of-type(-2n+3){\n background: red;\n }\n\t\th1:nth-of-type(+12){\n background: red;\n }\n\t\th1:nth-of-type(+3n){\n background: red;\n }\n" "styles": "\n /* test that all these are parsed correctly */\n\th1:nth-of-type(2n+1){\n background: red;\n }\n h1:nth-child(-n + 3 of li.important) {\n background: red;\n }\n h1:nth-child(1) {\n background: red;\n }\n h1:nth-child(p) {\n background: red;\n }\n h1:nth-child(n+7) {\n background: red;\n }\n h1:nth-child(even) {\n background: red;\n }\n h1:nth-child(odd) {\n background: red;\n }\n h1:nth-child(\n n\n ) {\n background: red;\n }\n h1:global(nav) {\n background: red;\n }\n\t\th1:nth-of-type(10n+1){\n background: red;\n }\n\t\th1:nth-of-type(-2n+3){\n background: red;\n }\n\t\th1:nth-of-type(+12){\n background: red;\n }\n\t\th1:nth-of-type(+3n){\n background: red;\n }\n"
} }
}, },

@ -393,6 +393,7 @@
"content": { "content": {
"start": 7, "start": 7,
"end": 378, "end": 378,
"comment": null,
"styles": "\n /* test that all these are parsed correctly */\n\t::view-transition-old(x-y) {\n\t\tcolor: red;\n }\n\t:global(::view-transition-old(x-y)) {\n\t\tcolor: red;\n }\n\t::highlight(rainbow-color-1) {\n\t\tcolor: red;\n\t}\n\tcustom-element::part(foo) {\n\t\tcolor: red;\n\t}\n\t::slotted(.content) {\n\t\tcolor: red;\n\t}\n\t:is( /*button*/\n\t\tbutton, /*p after h1*/\n\t\th1 + p\n\t\t){\n\t\tcolor: red;\n\t}\n" "styles": "\n /* test that all these are parsed correctly */\n\t::view-transition-old(x-y) {\n\t\tcolor: red;\n }\n\t:global(::view-transition-old(x-y)) {\n\t\tcolor: red;\n }\n\t::highlight(rainbow-color-1) {\n\t\tcolor: red;\n\t}\n\tcustom-element::part(foo) {\n\t\tcolor: red;\n\t}\n\t::slotted(.content) {\n\t\tcolor: red;\n\t}\n\t:is( /*button*/\n\t\tbutton, /*p after h1*/\n\t\th1 + p\n\t\t){\n\t\tcolor: red;\n\t}\n"
} }
}, },

@ -71,6 +71,7 @@
"content": { "content": {
"start": 43, "start": 43,
"end": 197, "end": 197,
"comment": null,
"styles": "\n\t@import url(\"https://fonts.googleapis.com/css2?family=Poppins:wght@400;700&display=swap\");\n\th1 {\n\t\tfont-weight: bold;\n\t\tbackground: url(\"whatever\");\n\t}\n" "styles": "\n\t@import url(\"https://fonts.googleapis.com/css2?family=Poppins:wght@400;700&display=swap\");\n\th1 {\n\t\tfont-weight: bold;\n\t\tbackground: url(\"whatever\");\n\t}\n"
} }
}, },

@ -1087,6 +1087,8 @@ declare module 'svelte/compiler' {
start: number; start: number;
end: number; end: number;
styles: string; styles: string;
/** Possible comment atop the style tag */
comment: Comment | null;
}; };
} }

Loading…
Cancel
Save