Repository: sveltejs/svelte (JavaScript)
Date: 2020-01-19 18:02:32+00:00
Task type: Bug Fix

Issue:
Multiline class attribute value breaks svelte
**Describe the bug**
At my team we spread classes into multiple lines when there are more than two classes to make it more readable. This breaks svelte.

```html
<div
  class="
    foo
  "
>
</div>

<style>
  .foo {
    background: red;
  }
</style>
```

**Logs**
```
ERROR in ./src/_components/Foo.svelte
Module Error (from ./node_modules/eslint-loader/dist/cjs.js):

[...]/_components/Foo.svelte
  9:3  warning  Unused CSS selector  css-unused-selector
```

**To Reproduce**
To reproduce just spread the classes named in the value of the class attribute into multiple lines, like in this REPL https://svelte.dev/repl/b85c17a37a0547f58f1bd221ae4bd8bc?version=3.16.7

```html
<div
  class="
    foo
  "
>
</div>

<style>
  .foo {
    background: red;
  }
</style>
```

**Expected behavior**
Components are working as classes weren't written in multiple lines.



Issue discussion:
This look real similar to https://github.com/sveltejs/svelte/issues/4240
This was broken by me in #3552. Fix coming shortly.

Solution patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,7 @@
 
 * Disallow two-way binding to a variable declared by an `{#await}` block ([#4012](https://github.com/sveltejs/svelte/issues/4012))
 * Allow access to `let:` variables in sibling attributes on slot root ([#4173](https://github.com/sveltejs/svelte/issues/4173))
+* Fix `~=` and class selector matching against values separated by any whitespace characters ([#4242](https://github.com/sveltejs/svelte/issues/4242))
 * Fix code generation for `await`ed expressions that need parentheses ([#4267](https://github.com/sveltejs/svelte/issues/4267))
 * Add some more known globals ([#4276](https://github.com/sveltejs/svelte/pull/4276))
 * Correctly apply event modifiers to `<svelte:body>` events ([#4278](https://github.com/sveltejs/svelte/issues/4278))
diff --git a/src/compiler/compile/css/Selector.ts b/src/compiler/compile/css/Selector.ts
--- a/src/compiler/compile/css/Selector.ts
+++ b/src/compiler/compile/css/Selector.ts
@@ -171,7 +171,7 @@ function apply_selector(blocks: Block[], node: Element, stack: Element[], to_enc
 				if (ancestor_block.global) {
 					continue;
 				}
-				
+
 				for (const stack_node of stack) {
 					if (block_might_apply_to_node(ancestor_block, stack_node) !== BlockAppliesToNode.NotPossible) {
 						to_encapsulate.push({ node: stack_node, block: ancestor_block });
@@ -256,7 +256,7 @@ function test_attribute(operator, expected_value, case_insensitive, value) {
 	}
 	switch (operator) {
 		case '=': return value === expected_value;
-		case '~=': return ` ${value} `.includes(` ${expected_value} `);
+		case '~=': return value.split(/\s/).includes(expected_value);
 		case '|=': return `${value}-`.startsWith(`${expected_value}-`);
 		case '^=': return value.startsWith(expected_value);
 		case '$=': return value.endsWith(expected_value);
@@ -295,7 +295,7 @@ function attribute_matches(node: CssNode, name: string, expected_value: string,
 
 		// impossible to find out all combinations
 		if (current_possible_values.has(UNKNOWN)) return true;
-		
+
 		if (prev_values.length > 0) {
 			const start_with_space = [];
 			const remaining = [];


Test patch:
diff --git a/test/css/samples/attribute-selector-word-arbitrary-whitespace/expected.css b/test/css/samples/attribute-selector-word-arbitrary-whitespace/expected.css
new file mode 100644
--- /dev/null
+++ b/test/css/samples/attribute-selector-word-arbitrary-whitespace/expected.css
@@ -0,0 +1 @@
+.foo.svelte-xyz{color:red}[class~="bar"].svelte-xyz{background:blue}
\ No newline at end of file
diff --git a/test/css/samples/attribute-selector-word-arbitrary-whitespace/input.svelte b/test/css/samples/attribute-selector-word-arbitrary-whitespace/input.svelte
new file mode 100644
--- /dev/null
+++ b/test/css/samples/attribute-selector-word-arbitrary-whitespace/input.svelte
@@ -0,0 +1,13 @@
+<div class="
+foo
+bar
+"></div>
+
+<style>
+	.foo {
+		color: red;
+	}
+	[class~="bar"] {
+		background: blue;
+	}
+</style>