diff --git a/src/css/Selector.ts b/src/css/Selector.ts index a505f15a10..07a0fb9786 100644 --- a/src/css/Selector.ts +++ b/src/css/Selector.ts @@ -1,4 +1,5 @@ import MagicString from 'magic-string'; +import { gatherPossibleValues, UNKNOWN } from './gatherPossibleValues'; import { Validator } from '../validate/index'; import { Node } from '../interfaces'; @@ -192,12 +193,22 @@ function attributeMatches(node: Node, name: string, expectedValue: string, opera const attr = node.attributes.find((attr: Node) => attr.name === name); if (!attr) return false; if (attr.value === true) return operator === null; - if (isDynamic(attr.value)) return true; - - const actualValue = attr.value[0].data; + if (attr.value.length > 1) return true; const pattern = operators[operator](expectedValue, caseInsensitive ? 'i' : ''); - return pattern.test(actualValue); + const value = attr.value[0]; + + if (value.type === 'Text') return pattern.test(value.data); + + const possibleValues = new Set(); + gatherPossibleValues(value.expression, possibleValues); + if (possibleValues.has(UNKNOWN)) return true; + + for (const x of Array.from(possibleValues)) { // TypeScript for-of is slightly unlike JS + if (pattern.test(x)) return true; + } + + return false; } function isDynamic(value: Node) { diff --git a/src/css/gatherPossibleValues.ts b/src/css/gatherPossibleValues.ts new file mode 100644 index 0000000000..829626b9e3 --- /dev/null +++ b/src/css/gatherPossibleValues.ts @@ -0,0 +1,18 @@ +import { Node } from '../interfaces'; + +export const UNKNOWN = {}; + +export function gatherPossibleValues(node: Node, set: Set) { + if (node.type === 'Literal') { + set.add(node.value); + } + + else if (node.type === 'ConditionalExpression') { + gatherPossibleValues(node.consequent, set); + gatherPossibleValues(node.alternate, set); + } + + else { + set.add(UNKNOWN); + } +} \ No newline at end of file diff --git a/test/css/index.js b/test/css/index.js index 8b4d60c2ce..0d0b0e1b4a 100644 --- a/test/css/index.js +++ b/test/css/index.js @@ -13,7 +13,7 @@ function tryRequire(file) { } function normalizeWarning(warning) { - warning.frame = warning.frame.replace(/^\n/, '').replace(/^\t+/gm, ''); + warning.frame = warning.frame.replace(/^\n/, '').replace(/^\t+/gm, '').replace(/\s+$/gm, ''); delete warning.filename; delete warning.toString; return warning; diff --git a/test/css/samples/unused-selector-ternary/_config.js b/test/css/samples/unused-selector-ternary/_config.js new file mode 100644 index 0000000000..427e75a35d --- /dev/null +++ b/test/css/samples/unused-selector-ternary/_config.js @@ -0,0 +1,24 @@ +export default { + cascade: false, + + data: { + active: true + }, + + warnings: [{ + filename: "SvelteComponent.html", + message: "Unused CSS selector", + loc: { + line: 12, + column: 1 + }, + pos: 125, + frame: ` + 10: } + 11: + 12: .maybeactive { + ^ + 13: color: green; + 14: }` + }] +}; \ No newline at end of file diff --git a/test/css/samples/unused-selector-ternary/expected.css b/test/css/samples/unused-selector-ternary/expected.css new file mode 100644 index 0000000000..b6bba2d5f3 --- /dev/null +++ b/test/css/samples/unused-selector-ternary/expected.css @@ -0,0 +1 @@ +.active[svelte-xyz]{color:red}.inactive[svelte-xyz]{color:blue} \ No newline at end of file diff --git a/test/css/samples/unused-selector-ternary/expected.html b/test/css/samples/unused-selector-ternary/expected.html new file mode 100644 index 0000000000..5b0c6b6143 --- /dev/null +++ b/test/css/samples/unused-selector-ternary/expected.html @@ -0,0 +1 @@ +
\ No newline at end of file diff --git a/test/css/samples/unused-selector-ternary/input.html b/test/css/samples/unused-selector-ternary/input.html new file mode 100644 index 0000000000..edffee317e --- /dev/null +++ b/test/css/samples/unused-selector-ternary/input.html @@ -0,0 +1,15 @@ +
+ + \ No newline at end of file diff --git a/test/css/samples/unused-selector/warnings.json b/test/css/samples/unused-selector/warnings.json deleted file mode 100644 index 6d6c3f5deb..0000000000 --- a/test/css/samples/unused-selector/warnings.json +++ /dev/null @@ -1,10 +0,0 @@ -[{ - "filename": "SvelteComponent.html", - "message": "Unused CSS selector", - "loc": { - "line": 8, - "column": 1 - }, - "pos": 61, - "frame": " 6: }\n 7: \n 8: .bar {\n ^\n 9: color: blue;\n10: }" -}] \ No newline at end of file