From 19f6727c8d4d7f0af045b4eaba57b75091e98aea Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Sun, 17 Feb 2019 13:44:49 -0500 Subject: [PATCH] =?UTF-8?q?handle=20implicit=20and=20explicit-but-undefine?= =?UTF-8?q?d=20props=20=E2=80=94=20fixes=20#2024?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/compile/Component.ts | 22 ++++++++++++++++++- src/compile/render-dom/index.ts | 16 +++++++++----- src/compile/render-ssr/index.ts | 11 ++++++---- .../runtime/samples/props-implicit/_config.js | 17 ++++++++++++++ .../samples/props-implicit/main.svelte | 3 +++ .../samples/props-undeclared/_config.js | 3 +++ .../samples/props-undeclared/main.svelte | 5 +++++ 7 files changed, 67 insertions(+), 10 deletions(-) create mode 100644 test/runtime/samples/props-implicit/_config.js create mode 100644 test/runtime/samples/props-implicit/main.svelte create mode 100644 test/runtime/samples/props-undeclared/_config.js create mode 100644 test/runtime/samples/props-undeclared/main.svelte diff --git a/src/compile/Component.ts b/src/compile/Component.ts index 7940a7052d..09f5261c63 100644 --- a/src/compile/Component.ts +++ b/src/compile/Component.ts @@ -28,6 +28,7 @@ type ComponentOptions = { immutable?: boolean; props?: string; props_object?: string; + props_node?: Node; }; // We need to tell estree-walker that it should always @@ -131,7 +132,25 @@ export default class Component { if (this.componentOptions.props) { this.has_reactive_assignments = true; - const variable = this.var_lookup.get(this.componentOptions.props_object); + const name = this.componentOptions.props_object; + + if (!this.ast.module && !this.ast.instance) { + this.add_var({ + name, + export_name: name, + implicit: true + }); + } + + const variable = this.var_lookup.get(name); + + if (!variable) { + this.error(this.componentOptions.props_node, { + code: 'missing-declaration', + message: `'${name}' is not defined` + }); + } + variable.reassigned = true; } @@ -1229,6 +1248,7 @@ function process_component_options(component: Component, nodes) { const { name } = flattenReference(attribute.expression); componentOptions.props = `[✂${start}-${end}✂]`; + componentOptions.props_node = attribute.expression; componentOptions.props_object = name; } diff --git a/src/compile/render-dom/index.ts b/src/compile/render-dom/index.ts index 748c2a1412..14638553a5 100644 --- a/src/compile/render-dom/index.ts +++ b/src/compile/render-dom/index.ts @@ -258,11 +258,13 @@ export default function dom( ${component.fully_hoisted.length > 0 && component.fully_hoisted.join('\n\n')} `); - const filtered_declarations = component.vars.filter(variable => { - return (variable.referenced || variable.export_name) && !variable.hoistable; - }).map(variable => variable.name); + const filtered_declarations = component.vars + .filter(v => ((v.referenced || v.export_name) && !v.hoistable)) + .map(v => v.name); const filtered_props = props.filter(prop => { + if (prop.name === component.componentOptions.props_object) return false; + const variable = component.var_lookup.get(prop.name); if (variable.hoistable) return false; @@ -284,6 +286,7 @@ export default function dom( const has_definition = ( component.javascript || filtered_props.length > 0 || + component.componentOptions.props_object || component.partly_hoisted.length > 0 || filtered_declarations.length > 0 || component.reactive_declarations.length > 0 @@ -299,8 +302,11 @@ export default function dom( }); const user_code = component.javascript || ( - !component.ast.instance && !component.ast.module && filtered_props.length > 0 - ? `let { ${filtered_props.map(x => x.name).join(', ')} } = $$props;` + !component.ast.instance && !component.ast.module && (filtered_props.length > 0 || component.componentOptions.props) + ? [ + component.componentOptions.props && `let ${component.componentOptions.props} = $$props;`, + filtered_props.length > 0 && `let { ${filtered_props.map(x => x.name).join(', ')} } = $$props;` + ].filter(Boolean).join('\n') : null ); diff --git a/src/compile/render-ssr/index.ts b/src/compile/render-ssr/index.ts index a6d3123a33..0383e8931c 100644 --- a/src/compile/render-ssr/index.ts +++ b/src/compile/render-ssr/index.ts @@ -24,14 +24,17 @@ export default function ssr( let user_code; - // TODO remove this, just use component.symbols everywhere - const props = component.vars.filter(variable => !variable.module && variable.export_name); + // TODO remove this, just use component.vars everywhere + const props = component.vars.filter(variable => !variable.module && variable.export_name && variable.export_name !== component.componentOptions.props_object); if (component.javascript) { component.rewrite_props(); user_code = component.javascript; - } else if (!component.ast.instance && !component.ast.module && props.length > 0) { - user_code = `let { ${props.map(prop => prop.export_name).join(', ')} } = $$props;` + } else if (!component.ast.instance && !component.ast.module && (props.length > 0 || component.componentOptions.props)) { + user_code = [ + component.componentOptions.props && `let ${component.componentOptions.props} = $$props;`, + props.length > 0 && `let { ${props.map(prop => prop.export_name).join(', ')} } = $$props;` + ].filter(Boolean).join('\n'); } const reactive_stores = component.vars.filter(variable => variable.name[0] === '$'); diff --git a/test/runtime/samples/props-implicit/_config.js b/test/runtime/samples/props-implicit/_config.js new file mode 100644 index 0000000000..354aa1bcee --- /dev/null +++ b/test/runtime/samples/props-implicit/_config.js @@ -0,0 +1,17 @@ +export default { + props: { + x: 1 + }, + + html: ` +
{"x":1}
+ `, + + async test({ assert, component, target }) { + await component.$set({ x: 2 }); + + assert.htmlEqual(target.innerHTML, ` +
{"x":2}
+ `); + } +}; \ No newline at end of file diff --git a/test/runtime/samples/props-implicit/main.svelte b/test/runtime/samples/props-implicit/main.svelte new file mode 100644 index 0000000000..0beafd3f07 --- /dev/null +++ b/test/runtime/samples/props-implicit/main.svelte @@ -0,0 +1,3 @@ + + +
{JSON.stringify(foo)}
\ No newline at end of file diff --git a/test/runtime/samples/props-undeclared/_config.js b/test/runtime/samples/props-undeclared/_config.js new file mode 100644 index 0000000000..e7d09b76bf --- /dev/null +++ b/test/runtime/samples/props-undeclared/_config.js @@ -0,0 +1,3 @@ +export default { + error: `'foo' is not defined` +}; \ No newline at end of file diff --git a/test/runtime/samples/props-undeclared/main.svelte b/test/runtime/samples/props-undeclared/main.svelte new file mode 100644 index 0000000000..a05b8985a6 --- /dev/null +++ b/test/runtime/samples/props-undeclared/main.svelte @@ -0,0 +1,5 @@ + + + + +
{JSON.stringify(foo)}
\ No newline at end of file