Repository: sveltejs/svelte (JavaScript)
Date: 2019-01-25 20:21:23+00:00
Task type: Bug Fix

Issue:
Variables within `context=module` inaccessible from template
Taking the [example from here](https://v3.svelte.technology/guide#module-context), only adding the HTML template to (visually) print the value of `answer`:

When plopped into the V3 REPL: 
```
actual ~> Answer: undefined
expect ~> Answer: 42
```

The "main script" properly logs `we can 'see' module-level variables like 42` 👍 

```html
<h1>Answer: {answer}!</h1>

<script context="module">
	console.log(`this will run once`);
	const answer = 42;
</script>

<script>
	console.log(`this will run once per instance`);
	console.log(`we can 'see' module-level variables like ${answer}`);
</script>
```


Issue discussion:

Solution patch:
diff --git a/src/compile/nodes/shared/Expression.ts b/src/compile/nodes/shared/Expression.ts
--- a/src/compile/nodes/shared/Expression.ts
+++ b/src/compile/nodes/shared/Expression.ts
@@ -240,7 +240,7 @@ export default class Expression {
 							dependencies.add(name);
 							component.template_references.add(name);
 						}
-					} else if (!is_synthetic && !component.hoistable_names.has(name) && !component.imported_declarations.has(name)) {
+					} else if (!is_synthetic && isContextual(component, template_scope, name)) {
 						code.prependRight(node.start, key === 'key' && parent.shorthand
 							? `${name}: ctx.`
 							: 'ctx.');
@@ -436,4 +436,17 @@ function get_function_name(node, parent) {
 	}
 
 	return 'func';
+}
+
+function isContextual(component: Component, scope: TemplateScope, name: string) {
+	// if it's a name below root scope, it's contextual
+	if (!scope.isTopLevel(name)) return true;
+
+	// hoistables, module declarations, and imports are non-contextual
+	if (component.hoistable_names.has(name)) return false;
+	if (component.module_scope && component.module_scope.declarations.has(name)) return false;
+	if (component.imported_declarations.has(name)) return false;
+
+	// assume contextual
+	return true;
 }
\ No newline at end of file
diff --git a/src/compile/nodes/shared/TemplateScope.ts b/src/compile/nodes/shared/TemplateScope.ts
--- a/src/compile/nodes/shared/TemplateScope.ts
+++ b/src/compile/nodes/shared/TemplateScope.ts
@@ -40,4 +40,8 @@ export default class TemplateScope {
 		if (this.parent) return this.parent.containsMutable(names);
 		else return false;
 	}
+
+	isTopLevel(name: string) {
+		return !this.parent || !this.names.has(name) && this.parent.isTopLevel(name);
+	}
 }
\ No newline at end of file


Test patch:
diff --git a/test/runtime/samples/each-block-scope-shadow/_config.js b/test/runtime/samples/each-block-scope-shadow/_config.js
new file mode 100644
--- /dev/null
+++ b/test/runtime/samples/each-block-scope-shadow/_config.js
@@ -0,0 +1,3 @@
+export default {
+	html: '(alpaca)(baboon)(capybara)'
+};
diff --git a/test/runtime/samples/each-block-scope-shadow/main.html b/test/runtime/samples/each-block-scope-shadow/main.html
new file mode 100644
--- /dev/null
+++ b/test/runtime/samples/each-block-scope-shadow/main.html
@@ -0,0 +1,8 @@
+{#each animals as animal}
+	({animal})
+{/each}
+
+<script>
+	let animal = 'lemur';
+	let animals = ['alpaca', 'baboon', 'capybara'];
+</script>
\ No newline at end of file
diff --git a/test/runtime/samples/module-context-with-instance-script/_config.js b/test/runtime/samples/module-context-with-instance-script/_config.js
new file mode 100644
--- /dev/null
+++ b/test/runtime/samples/module-context-with-instance-script/_config.js
@@ -0,0 +1,3 @@
+export default {
+	html: `<p>(42)(99)</p>`
+};
\ No newline at end of file
diff --git a/test/runtime/samples/module-context-with-instance-script/main.html b/test/runtime/samples/module-context-with-instance-script/main.html
new file mode 100644
--- /dev/null
+++ b/test/runtime/samples/module-context-with-instance-script/main.html
@@ -0,0 +1,9 @@
+<script context="module">
+	const foo = 42;
+</script>
+
+<script>
+	export let bar = 99;
+</script>
+
+<p>({foo})({bar})</p>
\ No newline at end of file