Repository: sveltejs/svelte (JavaScript)
Date: 2018-04-04 12:20:25+00:00
Task type: Bug Fix

Issue:
If in #each block naming collision
Stuff broke after 1.55.1 for me, I got naming collisions in this case:
```html
{{#each list as nested}}
  {{#if true}}
    <Nested :nested/>
  {{/if}}
{{/each}}
<script>
  import Nested from './Nested.html';
  export default {
    data: () => ({
      list: [1,2]
    }),
    components: {
      Nested
    }
  };
</script>
```
The output in 1.58.2 is:
```javascript
// (2:2) {{#if true}}
function create_if_block(component, state) {
	var nested = state.nested, each_value = state.each_value, nested_index = state.nested_index;

	var nested = new Nested({
		root: component.root,
		data: { nested: nested }
	});

	return {
		c: function create() {
			nested._fragment.c();
		},

		m: function mount(target, anchor) {
			nested._mount(target, anchor);
		},

		p: function update(changed, state) {
			nested = state.nested;
			each_value = state.each_value;
			nested_index = state.nested_index;
			var nested_changes = {};
			if (changed.list) nested_changes.nested = nested;
			nested._set(nested_changes);
		},

		u: function unmount() {
			nested._unmount();
		},

		d: function destroy() {
			nested.destroy(false);
		}
	};
}
```


Issue discussion:
I think https://github.com/sveltejs/svelte/blob/fcfbffe50bf27caaca37749cdca05f5d5e42d727/src/generators/nodes/EachBlock.ts#L64 should be changed to
```javascript
const context = this.generator.getUniqueName(this.context);
```
However if I change it I get 3 errors on the runtime deconflict-component-refs test.

Solution patch:
diff --git a/src/generators/Generator.ts b/src/generators/Generator.ts
--- a/src/generators/Generator.ts
+++ b/src/generators/Generator.ts
@@ -398,7 +398,7 @@ export default class Generator {
 		return alias;
 	}
 
-	getUniqueNameMaker() {
+	getUniqueNameMaker(names: string[]) {
 		const localUsedNames = new Set();
 
 		function add(name: string) {
@@ -407,6 +407,7 @@ export default class Generator {
 
 		reservedNames.forEach(add);
 		this.userVars.forEach(add);
+		names.forEach(add);
 
 		return (name: string) => {
 			if (test) name = `${name}$`;
diff --git a/src/generators/dom/Block.ts b/src/generators/dom/Block.ts
--- a/src/generators/dom/Block.ts
+++ b/src/generators/dom/Block.ts
@@ -105,7 +105,7 @@ export default class Block {
 		this.hasOutroMethod = false;
 		this.outros = 0;
 
-		this.getUniqueName = this.generator.getUniqueNameMaker();
+		this.getUniqueName = this.generator.getUniqueNameMaker([...this.contexts.values()]);
 		this.variables = new Map();
 
 		this.aliases = new Map()
diff --git a/src/generators/dom/index.ts b/src/generators/dom/index.ts
--- a/src/generators/dom/index.ts
+++ b/src/generators/dom/index.ts
@@ -48,33 +48,6 @@ export class DomGenerator extends Generator {
 		// initial values for e.g. window.innerWidth, if there's a <:Window> meta tag
 		this.metaBindings = [];
 	}
-
-	getUniqueNameMaker() {
-		const localUsedNames = new Set();
-
-		function add(name: string) {
-			localUsedNames.add(name);
-		}
-
-		reservedNames.forEach(add);
-		this.userVars.forEach(add);
-		for (const name in shared) {
-			localUsedNames.add(test ? `${name}$` : name);
-		}
-
-		return (name: string) => {
-			if (test) name = `${name}$`;
-			let alias = name;
-			for (
-				let i = 1;
-				this.usedNames.has(alias) ||
-				localUsedNames.has(alias);
-				alias = `${name}_${i++}`
-			);
-			localUsedNames.add(alias);
-			return alias;
-		};
-	}
 }
 
 export default function dom(


Test patch:
diff --git a/test/runtime/samples/component-name-deconflicted/Nested.html b/test/runtime/samples/component-name-deconflicted/Nested.html
new file mode 100644
--- /dev/null
+++ b/test/runtime/samples/component-name-deconflicted/Nested.html
@@ -0,0 +1 @@
+<span>{{nested}}</span>
\ No newline at end of file
diff --git a/test/runtime/samples/component-name-deconflicted/_config.js b/test/runtime/samples/component-name-deconflicted/_config.js
new file mode 100644
--- /dev/null
+++ b/test/runtime/samples/component-name-deconflicted/_config.js
@@ -0,0 +1,17 @@
+export default {
+	html: `
+		<span>1</span>
+		<span>2</span>
+	`,
+
+	test(assert, component, target) {
+		component.set({
+			list: [3, 4]
+		});
+
+		assert.htmlEqual(target.innerHTML, `
+			<span>3</span>
+			<span>4</span>
+		`);
+	}
+};
\ No newline at end of file
diff --git a/test/runtime/samples/component-name-deconflicted/main.html b/test/runtime/samples/component-name-deconflicted/main.html
new file mode 100644
--- /dev/null
+++ b/test/runtime/samples/component-name-deconflicted/main.html
@@ -0,0 +1,18 @@
+{{#each list as nested}}
+	{{#if true}}
+		<Nested :nested/>
+	{{/if}}
+{{/each}}
+
+<script>
+	import Nested from './Nested.html';
+
+	export default {
+		data: () => ({
+			list: [1, 2]
+		}),
+		components: {
+			Nested
+		}
+	};
+</script>
\ No newline at end of file