Repository: sveltejs/svelte (JavaScript)
Date: 2019-03-09 21:38:33+00:00
Task type: Bug Fix

Issue:
Component name isn't deconflicted against assumed globals
Contrary to what https://v3.svelte.technology/tutorial/self says, you *can* use `<Folder>` instead of `<svelte:self>`. That's a bug.


Issue discussion:

Solution patch:
diff --git a/src/compile/Component.ts b/src/compile/Component.ts
--- a/src/compile/Component.ts
+++ b/src/compile/Component.ts
@@ -157,8 +157,8 @@ export default class Component {
 			variable.reassigned = true;
 		}
 
-		this.name = this.getUniqueName(name);
 		this.fragment = new Fragment(this, ast.html);
+		this.name = this.getUniqueName(name);
 
 		this.walk_instance_js_post_template();
 
@@ -200,6 +200,8 @@ export default class Component {
 				referenced: true,
 				writable: true
 			});
+		} else {
+			this.usedNames.add(name);
 		}
 	}
 
@@ -235,19 +237,20 @@ export default class Component {
 
 			const banner = `/* ${this.file ? `${this.file} ` : ``}generated by Svelte v${"__VERSION__"} */`;
 
-			// TODO use same regex for both
-			result = result.replace(compileOptions.generate === 'ssr' ? /(@+|#+)(\w*(?:-\w*)?)/g : /(@+)(\w*(?:-\w*)?)/g, (match: string, sigil: string, name: string) => {
-				if (sigil === '@') {
-					if (internal_exports.has(name)) {
-						if (compileOptions.dev && internal_exports.has(`${name}Dev`)) name = `${name}Dev`;
-						this.helpers.add(name);
-					}
+			result = result
+				.replace(/__svelte:self__/g, this.name)
+				.replace(compileOptions.generate === 'ssr' ? /(@+|#+)(\w*(?:-\w*)?)/g : /(@+)(\w*(?:-\w*)?)/g, (match: string, sigil: string, name: string) => {
+					if (sigil === '@') {
+						if (internal_exports.has(name)) {
+							if (compileOptions.dev && internal_exports.has(`${name}Dev`)) name = `${name}Dev`;
+							this.helpers.add(name);
+						}
 
-					return this.alias(name);
-				}
+						return this.alias(name);
+					}
 
-				return sigil.slice(1) + name;
-			});
+					return sigil.slice(1) + name;
+				});
 
 			const importedHelpers = Array.from(this.helpers)
 				.sort()
diff --git a/src/compile/render-dom/wrappers/InlineComponent/index.ts b/src/compile/render-dom/wrappers/InlineComponent/index.ts
--- a/src/compile/render-dom/wrappers/InlineComponent/index.ts
+++ b/src/compile/render-dom/wrappers/InlineComponent/index.ts
@@ -63,7 +63,7 @@ export default class InlineComponentWrapper extends Wrapper {
 		});
 
 		this.var = (
-			this.node.name === 'svelte:self' ? renderer.component.name :
+			this.node.name === 'svelte:self' ? '__svelte:self__' : // TODO conflict-proof this
 			this.node.name === 'svelte:component' ? 'switch_instance' :
 			this.node.name
 		).toLowerCase();
diff --git a/src/compile/render-ssr/handlers/InlineComponent.ts b/src/compile/render-ssr/handlers/InlineComponent.ts
--- a/src/compile/render-ssr/handlers/InlineComponent.ts
+++ b/src/compile/render-ssr/handlers/InlineComponent.ts
@@ -74,7 +74,7 @@ export default function(node, renderer: Renderer, options) {
 
 	const expression = (
 		node.name === 'svelte:self'
-			? node.component.name
+			? '__svelte:self__' // TODO conflict-proof this
 			: node.name === 'svelte:component'
 				? `((${snip(node.expression)}) || @missingComponent)`
 				: node.name


Test patch:
diff --git a/test/runtime/samples/component-name-deconflicted-globals/Countdown.svelte b/test/runtime/samples/component-name-deconflicted-globals/Countdown.svelte
new file mode 100644
--- /dev/null
+++ b/test/runtime/samples/component-name-deconflicted-globals/Countdown.svelte
@@ -0,0 +1,10 @@
+<script>
+	export let count;
+</script>
+
+<span>{count}</span>
+
+{#if count > 1}
+	<!-- this shouldn't work — we have to use <svelte:self> instead -->
+	<Countdown count={count - 1}/>
+{/if}
\ No newline at end of file
diff --git a/test/runtime/samples/component-name-deconflicted-globals/_config.js b/test/runtime/samples/component-name-deconflicted-globals/_config.js
new file mode 100644
--- /dev/null
+++ b/test/runtime/samples/component-name-deconflicted-globals/_config.js
@@ -0,0 +1,5 @@
+export default {
+	preserveIdentifiers: true,
+
+	error: 'Countdown is not defined'
+};
\ No newline at end of file
diff --git a/test/runtime/samples/component-name-deconflicted-globals/main.svelte b/test/runtime/samples/component-name-deconflicted-globals/main.svelte
new file mode 100644
--- /dev/null
+++ b/test/runtime/samples/component-name-deconflicted-globals/main.svelte
@@ -0,0 +1,5 @@
+<script>
+	import Countdown from './Countdown.svelte';
+</script>
+
+<Countdown count={5}/>
\ No newline at end of file