Skip to content

Commit 45d375e

Browse files
authored
Merge pull request #1941 from sveltejs/gh-1889
allow reactive store references anywhere in script
2 parents c6d2cdd + e15d13b commit 45d375e

File tree

5 files changed

+81
-22
lines changed

5 files changed

+81
-22
lines changed

package-lock.json

Lines changed: 5 additions & 13 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@
6363
"eslint-plugin-html": "^4.0.3",
6464
"eslint-plugin-import": "^2.11.0",
6565
"estree-walker": "^0.6.0",
66-
"is-reference": "^1.1.0",
66+
"is-reference": "^1.1.1",
6767
"jsdom": "^11.8.0",
6868
"kleur": "^3.0.0",
6969
"locate-character": "^2.0.5",

src/compile/Component.ts

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -539,9 +539,43 @@ export default class Component {
539539
this.extract_imports_and_exports(script.content, this.imports, this.props);
540540
this.hoist_instance_declarations();
541541
this.extract_reactive_declarations();
542+
this.extract_reactive_store_references();
542543
this.javascript = this.extract_javascript(script);
543544
}
544545

546+
extract_reactive_store_references() {
547+
// TODO this pattern happens a lot... can we abstract it
548+
// (or better still, do fewer AST walks)?
549+
const component = this;
550+
let { instance_scope: scope, instance_scope_map: map } = this;
551+
552+
walk(this.instance_script.content, {
553+
enter(node, parent) {
554+
if (map.has(node)) {
555+
scope = map.get(node);
556+
}
557+
558+
if (isReference(node, parent)) {
559+
const object = getObject(node);
560+
const { name } = object;
561+
562+
if (name[0] === '$' && !scope.has(name)) {
563+
component.warn_if_undefined(object, null);
564+
565+
// cheeky hack
566+
component.template_references.add(name);
567+
}
568+
}
569+
},
570+
571+
leave(node) {
572+
if (map.has(node)) {
573+
scope = scope.parent;
574+
}
575+
}
576+
});
577+
}
578+
545579
rewrite_props() {
546580
const component = this;
547581
const { code, instance_scope, instance_scope_map: map, meta } = this;
@@ -735,7 +769,11 @@ export default class Component {
735769
const { name } = flattenReference(node);
736770
const owner = scope.findOwner(name);
737771

738-
if (owner === instance_scope) {
772+
if (name[0] === '$' && !owner) {
773+
hoistable = false;
774+
}
775+
776+
else if (owner === instance_scope) {
739777
if (name === fn_declaration.id.name) return;
740778
if (hoistable_names.has(name)) return;
741779
if (imported_declarations.has(name)) return;
@@ -818,13 +856,7 @@ export default class Component {
818856
const object = getObject(node);
819857
const { name } = object;
820858

821-
if (component.declarations.indexOf(name) !== -1) {
822-
dependencies.add(name);
823-
} else if (name[0] === '$') {
824-
component.warn_if_undefined(object, null);
825-
826-
// cheeky hack
827-
component.template_references.add(name);
859+
if (name[0] === '$' || component.declarations.indexOf(name) !== -1) {
828860
dependencies.add(name);
829861
}
830862

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { writable } from '../../../../store.js';
2+
3+
const count = writable(0);
4+
5+
export default {
6+
props: {
7+
count
8+
},
9+
10+
html: `
11+
<button>+1</button>
12+
`,
13+
14+
async test({ assert, component, target, window }) {
15+
assert.equal(component.get_count(), 0);
16+
17+
const button = target.querySelector('button');
18+
const click = new window.MouseEvent('click');
19+
20+
await button.dispatchEvent(click);
21+
assert.equal(component.get_count(), 1);
22+
23+
await count.set(42);
24+
assert.equal(component.get_count(), 42);
25+
}
26+
};
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<script>
2+
export let count;
3+
4+
export function get_count() {
5+
return $count;
6+
}
7+
</script>
8+
9+
<button on:click="{() => count.update(n => n + 1)}">+1</button>

0 commit comments

Comments
 (0)