From 3b5a7df5c4c42cf6ceeb338e01ccd5ebe7504756 Mon Sep 17 00:00:00 2001 From: rixo Date: Thu, 5 Dec 2019 22:24:21 +0100 Subject: [PATCH] add $$inject special prop, clean $capture_state & $inject_state --- src/compiler/compile/render_dom/index.ts | 54 ++++++++++---- .../samples/capture-inject-state/expected.js | 74 ++++++++++++++----- .../samples/capture-inject-state/input.svelte | 11 ++- test/js/samples/debug-empty/expected.js | 4 + .../debug-foo-bar-baz-things/expected.js | 4 + test/js/samples/debug-foo/expected.js | 4 + test/js/samples/debug-hoisted/expected.js | 6 +- .../samples/debug-no-dependencies/expected.js | 10 ++- .../expected.js | 4 + test/js/samples/loop-protect/expected.js | 11 +-- 10 files changed, 140 insertions(+), 42 deletions(-) diff --git a/src/compiler/compile/render_dom/index.ts b/src/compiler/compile/render_dom/index.ts index eb29e1aa6f..9fb02ddb8d 100644 --- a/src/compiler/compile/render_dom/index.ts +++ b/src/compiler/compile/render_dom/index.ts @@ -91,7 +91,10 @@ export default function dom( const accessors = []; const not_equal = component.component_options.immutable ? x`@not_equal` : x`@safe_not_equal`; - let dev_props_check; let inject_state: Expression; let capture_state: Expression; + let dev_props_check: Node[] | Node; + let inject_state: Expression; + let capture_state: Expression; + let props_inject: Node[] | Node; props.forEach(prop => { const variable = component.var_lookup.get(prop.name); @@ -165,21 +168,35 @@ export default function dom( } const capturable_vars = component.vars.filter( - variable => variable.writable && (!variable.injected || variable.name[0] === '$') + v => !v.internal && v.name != null && !(v.name[0] === '$' && v.name[1] === '$') ); - const injectable_vars = capturable_vars.filter(variable => variable.name[0] !== '$'); + const injectable_vars = capturable_vars.filter( + v => !v.module && v.writable && v.name[0] !== '$' + ); - capture_state = x`() => ({ ${capturable_vars.map(prop => p`${prop.name}`)} }) `; + capture_state = capturable_vars.length > 0 + ? x`() => ({ ${capturable_vars.map(prop => p`${prop.name}`)} })` + : x`@noop`; + + if (uses_props || injectable_vars.length > 0) { + inject_state = x` + ${$$props} => { + ${uses_props && renderer.invalidate('$$props', x`$$props = @assign(@assign({}, $$props), $$new_props)`)} + ${injectable_vars.map( + v => b`if ('${v.name}' in $$props) ${renderer.invalidate(v.name, x`${v.name} = ${$$props}.${v.name}`)};` + )} + } + `; - inject_state = x` - ${(uses_props || injectable_vars.length > 0) && $$props} => { - ${uses_props && renderer.invalidate('$$props', x`$$props = @assign(@assign({}, $$props), $$new_props)`)} - ${injectable_vars.map(prop => b` - if ('${prop.name}' in $$props) ${renderer.invalidate(prop.name, x`${prop.name} = ${$$props}.${prop.name}`)}; - `)} - } - `; + props_inject = b` + if ($$props && "$$inject" in $$props) { + $$self.$inject_state($$props.$$inject); + } + `; + } else { + inject_state = x`@noop`; + } } // instrument assignments @@ -230,7 +247,12 @@ export default function dom( } const args = [x`$$self`]; - if (props.length > 0 || component.has_reactive_assignments || component.slots.size > 0) { + const has_invalidate = props.length > 0 || + component.has_reactive_assignments || + component.slots.size > 0 || + capture_state || + inject_state; + if (has_invalidate) { args.push(x`$$props`, x`$$invalidate`); } @@ -278,7 +300,9 @@ export default function dom( uses_props || component.partly_hoisted.length > 0 || initial_context.length > 0 || - component.reactive_declarations.length > 0 + component.reactive_declarations.length > 0 || + capture_state || + inject_state ); const definition = has_definition @@ -393,6 +417,8 @@ export default function dom( ${injected.map(name => b`let ${name};`)} + ${/* before reactive declarations */ props_inject} + ${reactive_declarations.length > 0 && b` $$self.$$.update = () => { ${reactive_declarations} diff --git a/test/js/samples/capture-inject-state/expected.js b/test/js/samples/capture-inject-state/expected.js index c850d82f33..6e4c3bb0ea 100644 --- a/test/js/samples/capture-inject-state/expected.js +++ b/test/js/samples/capture-inject-state/expected.js @@ -28,18 +28,26 @@ function create_fragment(ctx) { let t4; let t5; let t6; + let t7; + let t8; + let t9; + let t10; const block = { c: function create() { p = element("p"); - t0 = text(/*$prop*/ ctx[1]); + t0 = text(/*prop*/ ctx[0]); t1 = space(); - t2 = text(/*realName*/ ctx[0]); + t2 = text(/*realName*/ ctx[1]); t3 = space(); - t4 = text(/*local*/ ctx[2]); + t4 = text(/*local*/ ctx[3]); t5 = space(); t6 = text(priv); - add_location(p, file, 13, 0, 232); + t7 = space(); + t8 = text(/*$prop*/ ctx[2]); + t9 = space(); + t10 = text(/*shadowedByModule*/ ctx[4]); + add_location(p, file, 22, 0, 430); }, l: function claim(nodes) { throw new Error("options.hydrate only works if the component was compiled with the `hydratable: true` option"); @@ -53,10 +61,15 @@ function create_fragment(ctx) { append_dev(p, t4); append_dev(p, t5); append_dev(p, t6); + append_dev(p, t7); + append_dev(p, t8); + append_dev(p, t9); + append_dev(p, t10); }, p: function update(ctx, [dirty]) { - if (dirty & /*$prop*/ 2) set_data_dev(t0, /*$prop*/ ctx[1]); - if (dirty & /*realName*/ 1) set_data_dev(t2, /*realName*/ ctx[0]); + if (dirty & /*prop*/ 1) set_data_dev(t0, /*prop*/ ctx[0]); + if (dirty & /*realName*/ 2) set_data_dev(t2, /*realName*/ ctx[1]); + if (dirty & /*$prop*/ 4) set_data_dev(t8, /*$prop*/ ctx[2]); }, i: noop, o: noop, @@ -76,12 +89,17 @@ function create_fragment(ctx) { return block; } +let moduleLiveBinding; +const moduleContantProps = 4; +let moduleLet; +const moduleConst = 2; +let shadowedByModule; const priv = "priv"; function instance($$self, $$props, $$invalidate) { let $prop, $$unsubscribe_prop = noop, - $$subscribe_prop = () => ($$unsubscribe_prop(), $$unsubscribe_prop = subscribe(prop, $$value => $$invalidate(1, $prop = $$value)), prop); + $$subscribe_prop = () => ($$unsubscribe_prop(), $$unsubscribe_prop = subscribe(prop, $$value => $$invalidate(2, $prop = $$value)), prop); $$self.$$.on_destroy.push(() => $$unsubscribe_prop()); let { prop } = $$props; @@ -89,6 +107,7 @@ function instance($$self, $$props, $$invalidate) { $$subscribe_prop(); let { alias: realName } = $$props; let local; + let shadowedByModule; const writable_props = ["prop", "alias"]; Object.keys($$props).forEach(key => { @@ -96,27 +115,47 @@ function instance($$self, $$props, $$invalidate) { }); $$self.$set = $$props => { - if ("prop" in $$props) $$subscribe_prop($$invalidate(3, prop = $$props.prop)); - if ("alias" in $$props) $$invalidate(0, realName = $$props.alias); + if ("prop" in $$props) $$subscribe_prop($$invalidate(0, prop = $$props.prop)); + if ("alias" in $$props) $$invalidate(1, realName = $$props.alias); }; - $$self.$capture_state = () => ({ prop, realName, local, $prop }); + $$self.$capture_state = () => ({ + moduleLiveBinding, + moduleContantProps, + moduleLet, + moduleConst, + shadowedByModule, + prop, + realName, + local, + priv, + shadowedByModule, + computed, + $prop + }); $$self.$inject_state = $$props => { - if ("prop" in $$props) $$subscribe_prop($$invalidate(3, prop = $$props.prop)); - if ("realName" in $$props) $$invalidate(0, realName = $$props.realName); - if ("local" in $$props) $$invalidate(2, local = $$props.local); + if ("prop" in $$props) $$subscribe_prop($$invalidate(0, prop = $$props.prop)); + if ("realName" in $$props) $$invalidate(1, realName = $$props.realName); + if ("local" in $$props) $$invalidate(3, local = $$props.local); + if ("shadowedByModule" in $$props) $$invalidate(4, shadowedByModule = $$props.shadowedByModule); + if ("computed" in $$props) computed = $$props.computed; }; let computed; + + if ($$props && "$$inject" in $$props) { + $$self.$inject_state($$props.$$inject); + } + $: computed = local * 2; - return [realName, $prop, local, prop]; + return [prop, realName, $prop, local, shadowedByModule]; } class Component extends SvelteComponentDev { constructor(options) { super(options); - init(this, options, instance, create_fragment, safe_not_equal, { prop: 3, alias: 0 }); + init(this, options, instance, create_fragment, safe_not_equal, { prop: 0, alias: 1 }); dispatch_dev("SvelteRegisterComponent", { component: this, @@ -128,11 +167,11 @@ class Component extends SvelteComponentDev { const { ctx } = this.$$; const props = options.props || ({}); - if (/*prop*/ ctx[3] === undefined && !("prop" in props)) { + if (/*prop*/ ctx[0] === undefined && !("prop" in props)) { console.warn(" was created without expected prop 'prop'"); } - if (/*realName*/ ctx[0] === undefined && !("alias" in props)) { + if (/*realName*/ ctx[1] === undefined && !("alias" in props)) { console.warn(" was created without expected prop 'alias'"); } } @@ -155,3 +194,4 @@ class Component extends SvelteComponentDev { } export default Component; +export { moduleLiveBinding, moduleContantProps }; \ No newline at end of file diff --git a/test/js/samples/capture-inject-state/input.svelte b/test/js/samples/capture-inject-state/input.svelte index 2a3fb4d291..a1051bc147 100644 --- a/test/js/samples/capture-inject-state/input.svelte +++ b/test/js/samples/capture-inject-state/input.svelte @@ -1,3 +1,10 @@ + -

{$prop} {realName} {local} {priv}

+

{prop} {realName} {local} {priv} {$prop} {shadowedByModule}

diff --git a/test/js/samples/debug-empty/expected.js b/test/js/samples/debug-empty/expected.js index 4cbb90b05e..059588c333 100644 --- a/test/js/samples/debug-empty/expected.js +++ b/test/js/samples/debug-empty/expected.js @@ -85,6 +85,10 @@ function instance($$self, $$props, $$invalidate) { if ("name" in $$props) $$invalidate(0, name = $$props.name); }; + if ($$props && "$$inject" in $$props) { + $$self.$inject_state($$props.$$inject); + } + return [name]; } diff --git a/test/js/samples/debug-foo-bar-baz-things/expected.js b/test/js/samples/debug-foo-bar-baz-things/expected.js index 11d22ee889..ea16a38cdd 100644 --- a/test/js/samples/debug-foo-bar-baz-things/expected.js +++ b/test/js/samples/debug-foo-bar-baz-things/expected.js @@ -192,6 +192,10 @@ function instance($$self, $$props, $$invalidate) { if ("baz" in $$props) $$invalidate(3, baz = $$props.baz); }; + if ($$props && "$$inject" in $$props) { + $$self.$inject_state($$props.$$inject); + } + return [things, foo, bar, baz]; } diff --git a/test/js/samples/debug-foo/expected.js b/test/js/samples/debug-foo/expected.js index ed52bcb916..8e3d7a005c 100644 --- a/test/js/samples/debug-foo/expected.js +++ b/test/js/samples/debug-foo/expected.js @@ -180,6 +180,10 @@ function instance($$self, $$props, $$invalidate) { if ("foo" in $$props) $$invalidate(1, foo = $$props.foo); }; + if ($$props && "$$inject" in $$props) { + $$self.$inject_state($$props.$$inject); + } + return [things, foo]; } diff --git a/test/js/samples/debug-hoisted/expected.js b/test/js/samples/debug-hoisted/expected.js index 1129484c10..c77168ef4f 100644 --- a/test/js/samples/debug-hoisted/expected.js +++ b/test/js/samples/debug-hoisted/expected.js @@ -47,7 +47,7 @@ function create_fragment(ctx) { return block; } -function instance($$self) { +function instance($$self, $$props, $$invalidate) { let obj = { x: 5 }; let kobzol = 5; $$self.$capture_state = () => ({ obj, kobzol }); @@ -57,6 +57,10 @@ function instance($$self) { if ("kobzol" in $$props) $$invalidate(1, kobzol = $$props.kobzol); }; + if ($$props && "$$inject" in $$props) { + $$self.$inject_state($$props.$$inject); + } + return [obj, kobzol]; } diff --git a/test/js/samples/debug-no-dependencies/expected.js b/test/js/samples/debug-no-dependencies/expected.js index 054dda7953..76e17a2e81 100644 --- a/test/js/samples/debug-no-dependencies/expected.js +++ b/test/js/samples/debug-no-dependencies/expected.js @@ -131,10 +131,16 @@ function create_fragment(ctx) { return block; } +function instance($$self, $$props, $$invalidate) { + $$self.$capture_state = noop; + $$self.$inject_state = noop; + return []; +} + class Component extends SvelteComponentDev { constructor(options) { super(options); - init(this, options, null, create_fragment, safe_not_equal, {}); + init(this, options, instance, create_fragment, safe_not_equal, {}); dispatch_dev("SvelteRegisterComponent", { component: this, @@ -145,4 +151,4 @@ class Component extends SvelteComponentDev { } } -export default Component; \ No newline at end of file +export default Component; diff --git a/test/js/samples/dev-warning-missing-data-computed/expected.js b/test/js/samples/dev-warning-missing-data-computed/expected.js index 90e65a24c6..286884ca16 100644 --- a/test/js/samples/dev-warning-missing-data-computed/expected.js +++ b/test/js/samples/dev-warning-missing-data-computed/expected.js @@ -83,6 +83,10 @@ function instance($$self, $$props, $$invalidate) { if ("bar" in $$props) $$invalidate(1, bar = $$props.bar); }; + if ($$props && "$$inject" in $$props) { + $$self.$inject_state($$props.$$inject); + } + $$self.$$.update = () => { if ($$self.$$.dirty & /*foo*/ 1) { $: $$invalidate(1, bar = foo * 2); diff --git a/test/js/samples/loop-protect/expected.js b/test/js/samples/loop-protect/expected.js index 0e7367084d..c2a99098fb 100644 --- a/test/js/samples/loop-protect/expected.js +++ b/test/js/samples/loop-protect/expected.js @@ -34,7 +34,7 @@ function create_fragment(ctx) { return block; } -function instance($$self) { +function instance($$self, $$props, $$invalidate) { const guard = loop_guard(100); while (true) { @@ -63,11 +63,8 @@ function instance($$self) { guard_4(); } while (true); - $$self.$capture_state = () => ({}); - - $$self.$inject_state = () => { - - }; + $$self.$capture_state = () => ({ foo }); + $$self.$inject_state = noop; $: { const guard_3 = loop_guard(100); @@ -104,4 +101,4 @@ class Component extends SvelteComponentDev { } } -export default Component; +export default Component; \ No newline at end of file