diff --git a/package-lock.json b/package-lock.json index bcde04de20..66dd55ef88 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "svelte", - "version": "3.6.7", + "version": "3.6.9", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts b/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts index c5cd58af0e..1e3fe06712 100644 --- a/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts +++ b/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts @@ -195,11 +195,12 @@ export default class InlineComponentWrapper extends Wrapper { if (attr.is_spread) { const value = attr.expression.render(block); initial_props.push(value); - let value_object_check = value + + let value_object = value if (attr.expression.node.type !== 'ObjectExpression') { - value_object_check = `typeof ${value} === 'object' && ${value} !== null ? ${value} : {}`; + value_object = `@get_spread_object(${value})`; } - changes.push(condition ? `${condition} && (${value_object_check})` : value_object_check); + changes.push(condition ? `${condition} && ${value_object}` : value_object); } else { const obj = `{ ${quote_name_if_necessary(name)}: ${attr.get_value(block)} }`; initial_props.push(obj); diff --git a/src/runtime/internal/spread.ts b/src/runtime/internal/spread.ts index 0075c947cd..203b0b11e9 100644 --- a/src/runtime/internal/spread.ts +++ b/src/runtime/internal/spread.ts @@ -35,3 +35,7 @@ export function get_spread_update(levels, updates) { return update; } + +export function get_spread_object(spread_props) { + return typeof spread_props === 'object' && spread_props !== null ? spread_props : {}; +} \ No newline at end of file diff --git a/test/runtime/samples/spread-component-dynamic-non-object-boolean/_config.js b/test/runtime/samples/spread-component-dynamic-non-object-boolean/_config.js deleted file mode 100644 index f4f79052a5..0000000000 --- a/test/runtime/samples/spread-component-dynamic-non-object-boolean/_config.js +++ /dev/null @@ -1,24 +0,0 @@ -export default { - props: { - props: { - foo: 'lol', - baz: 40 + 2, - } - }, - - html: ` -

foo: lol

-

baz: 42

-

qux: named

- `, - - test({ assert, component, target }) { - component.props = true; - - assert.htmlEqual(target.innerHTML, ` -

foo: undefined

-

baz: undefined

-

qux: named

- `); - } -}; diff --git a/test/runtime/samples/spread-component-dynamic-non-object-multiple-dependencies/Widget.svelte b/test/runtime/samples/spread-component-dynamic-non-object-multiple-dependencies/Widget.svelte index 373bf23f51..3433ffc243 100644 --- a/test/runtime/samples/spread-component-dynamic-non-object-multiple-dependencies/Widget.svelte +++ b/test/runtime/samples/spread-component-dynamic-non-object-multiple-dependencies/Widget.svelte @@ -1,6 +1,11 @@ -{foo} {baz} +

foo: {foo}

+

baz: {baz}

+

qux: {qux}

+

corge: {corge}

diff --git a/test/runtime/samples/spread-component-dynamic-non-object-multiple-dependencies/_config.js b/test/runtime/samples/spread-component-dynamic-non-object-multiple-dependencies/_config.js index d69c6b96ba..c5e23a023c 100644 --- a/test/runtime/samples/spread-component-dynamic-non-object-multiple-dependencies/_config.js +++ b/test/runtime/samples/spread-component-dynamic-non-object-multiple-dependencies/_config.js @@ -1,10 +1,53 @@ export default { - html: `b baz`, - test({ assert, component, target }) { - component.bar = undefined; - assert.htmlEqual( - target.innerHTML, - `b undefined` - ); + props: { + props: { + foo: 'lol', + baz: 40 + 2, + } }, + + html: ` +

foo: lol

+

baz: 42

+

qux: named

+

corge: b

+ `, + + test({ assert, component, target }) { + const html = ` +

foo: undefined

+

baz: undefined

+

qux: named

+

corge: b

+ `; + + // test undefined + component.props = undefined; + assert.htmlEqual(target.innerHTML, html); + + // set object props + component.props = this.props.props; + assert.htmlEqual(target.innerHTML, this.html); + + // test null + component.props = null; + assert.htmlEqual(target.innerHTML, html); + + // set object props + component.props = this.props.props; + assert.htmlEqual(target.innerHTML, this.html); + + // test boolean + component.props = true; + assert.htmlEqual(target.innerHTML, html); + + // set object props + component.props = this.props.props; + assert.htmlEqual(target.innerHTML, this.html); + + // test number + component.props = 123; + assert.htmlEqual(target.innerHTML, html); + + } }; diff --git a/test/runtime/samples/spread-component-dynamic-non-object-multiple-dependencies/main.svelte b/test/runtime/samples/spread-component-dynamic-non-object-multiple-dependencies/main.svelte index a60043391a..5f9f9cbff0 100644 --- a/test/runtime/samples/spread-component-dynamic-non-object-multiple-dependencies/main.svelte +++ b/test/runtime/samples/spread-component-dynamic-non-object-multiple-dependencies/main.svelte @@ -1,10 +1,13 @@ - +
+ +
diff --git a/test/runtime/samples/spread-component-dynamic-non-object-null/Widget.svelte b/test/runtime/samples/spread-component-dynamic-non-object-null/Widget.svelte deleted file mode 100644 index bc168d4956..0000000000 --- a/test/runtime/samples/spread-component-dynamic-non-object-null/Widget.svelte +++ /dev/null @@ -1,9 +0,0 @@ - - -

foo: {foo}

-

baz: {baz}

-

qux: {qux}

diff --git a/test/runtime/samples/spread-component-dynamic-non-object-null/_config.js b/test/runtime/samples/spread-component-dynamic-non-object-null/_config.js deleted file mode 100644 index 4569ba2cbc..0000000000 --- a/test/runtime/samples/spread-component-dynamic-non-object-null/_config.js +++ /dev/null @@ -1,24 +0,0 @@ -export default { - props: { - props: { - foo: 'lol', - baz: 40 + 2, - } - }, - - html: ` -

foo: lol

-

baz: 42

-

qux: named

- `, - - test({ assert, component, target }) { - component.props = null; - - assert.htmlEqual(target.innerHTML, ` -

foo: undefined

-

baz: undefined

-

qux: named

- `); - } -}; diff --git a/test/runtime/samples/spread-component-dynamic-non-object-null/main.svelte b/test/runtime/samples/spread-component-dynamic-non-object-null/main.svelte deleted file mode 100644 index 3ca281903e..0000000000 --- a/test/runtime/samples/spread-component-dynamic-non-object-null/main.svelte +++ /dev/null @@ -1,9 +0,0 @@ - - -
- -
diff --git a/test/runtime/samples/spread-component-dynamic-non-object-number/_config.js b/test/runtime/samples/spread-component-dynamic-non-object-number/_config.js deleted file mode 100644 index 0f34e93ac4..0000000000 --- a/test/runtime/samples/spread-component-dynamic-non-object-number/_config.js +++ /dev/null @@ -1,24 +0,0 @@ -export default { - props: { - props: { - foo: 'lol', - baz: 40 + 2, - } - }, - - html: ` -

foo: lol

-

baz: 42

-

qux: named

- `, - - test({ assert, component, target }) { - component.props = 1337; - - assert.htmlEqual(target.innerHTML, ` -

foo: undefined

-

baz: undefined

-

qux: named

- `); - } -}; diff --git a/test/runtime/samples/spread-component-dynamic-non-object-number/main.svelte b/test/runtime/samples/spread-component-dynamic-non-object-number/main.svelte deleted file mode 100644 index 3ca281903e..0000000000 --- a/test/runtime/samples/spread-component-dynamic-non-object-number/main.svelte +++ /dev/null @@ -1,9 +0,0 @@ - - -
- -
diff --git a/test/runtime/samples/spread-component-dynamic-non-object-undefined/Widget.svelte b/test/runtime/samples/spread-component-dynamic-non-object-undefined/Widget.svelte deleted file mode 100644 index bc168d4956..0000000000 --- a/test/runtime/samples/spread-component-dynamic-non-object-undefined/Widget.svelte +++ /dev/null @@ -1,9 +0,0 @@ - - -

foo: {foo}

-

baz: {baz}

-

qux: {qux}

diff --git a/test/runtime/samples/spread-component-dynamic-non-object-undefined/_config.js b/test/runtime/samples/spread-component-dynamic-non-object-undefined/_config.js deleted file mode 100644 index ecae122755..0000000000 --- a/test/runtime/samples/spread-component-dynamic-non-object-undefined/_config.js +++ /dev/null @@ -1,24 +0,0 @@ -export default { - props: { - props: { - foo: 'lol', - baz: 40 + 2, - } - }, - - html: ` -

foo: lol

-

baz: 42

-

qux: named

- `, - - test({ assert, component, target }) { - component.props = undefined; - - assert.htmlEqual(target.innerHTML, ` -

foo: undefined

-

baz: undefined

-

qux: named

- `); - } -}; diff --git a/test/runtime/samples/spread-component-dynamic-non-object-undefined/main.svelte b/test/runtime/samples/spread-component-dynamic-non-object-undefined/main.svelte deleted file mode 100644 index 3ca281903e..0000000000 --- a/test/runtime/samples/spread-component-dynamic-non-object-undefined/main.svelte +++ /dev/null @@ -1,9 +0,0 @@ - - -
- -
diff --git a/test/runtime/samples/spread-component-dynamic-non-object-boolean/Widget.svelte b/test/runtime/samples/spread-component-dynamic-non-object/Widget.svelte similarity index 100% rename from test/runtime/samples/spread-component-dynamic-non-object-boolean/Widget.svelte rename to test/runtime/samples/spread-component-dynamic-non-object/Widget.svelte diff --git a/test/runtime/samples/spread-component-dynamic-non-object/_config.js b/test/runtime/samples/spread-component-dynamic-non-object/_config.js new file mode 100644 index 0000000000..094f2fbb9b --- /dev/null +++ b/test/runtime/samples/spread-component-dynamic-non-object/_config.js @@ -0,0 +1,51 @@ +export default { + props: { + props: { + foo: 'lol', + baz: 40 + 2, + } + }, + + html: ` +

foo: lol

+

baz: 42

+

qux: named

+ `, + + test({ assert, component, target }) { + const html = ` +

foo: undefined

+

baz: undefined

+

qux: named

+ `; + + // test undefined + component.props = undefined; + assert.htmlEqual(target.innerHTML, html); + + // set object props + component.props = this.props.props; + assert.htmlEqual(target.innerHTML, this.html); + + // test null + component.props = null; + assert.htmlEqual(target.innerHTML, html); + + // set object props + component.props = this.props.props; + assert.htmlEqual(target.innerHTML, this.html); + + // test boolean + component.props = true; + assert.htmlEqual(target.innerHTML, html); + + // set object props + component.props = this.props.props; + assert.htmlEqual(target.innerHTML, this.html); + + // test number + component.props = 123; + assert.htmlEqual(target.innerHTML, html); + + } +}; diff --git a/test/runtime/samples/spread-component-dynamic-non-object-boolean/main.svelte b/test/runtime/samples/spread-component-dynamic-non-object/main.svelte similarity index 100% rename from test/runtime/samples/spread-component-dynamic-non-object-boolean/main.svelte rename to test/runtime/samples/spread-component-dynamic-non-object/main.svelte diff --git a/test/runtime/samples/spread-component-dynamic-non-object-number/Widget.svelte b/test/runtime/samples/spread-component-side-effects/Widget.svelte similarity index 72% rename from test/runtime/samples/spread-component-dynamic-non-object-number/Widget.svelte rename to test/runtime/samples/spread-component-side-effects/Widget.svelte index bc168d4956..69349e66b4 100644 --- a/test/runtime/samples/spread-component-dynamic-non-object-number/Widget.svelte +++ b/test/runtime/samples/spread-component-side-effects/Widget.svelte @@ -1,9 +1,9 @@ +

i: {i}

foo: {foo}

-

baz: {baz}

qux: {qux}

diff --git a/test/runtime/samples/spread-component-side-effects/_config.js b/test/runtime/samples/spread-component-side-effects/_config.js new file mode 100644 index 0000000000..35c4fb7474 --- /dev/null +++ b/test/runtime/samples/spread-component-side-effects/_config.js @@ -0,0 +1,19 @@ +export default { + props: {}, + + html: ` +

i: 1

+

foo: foo

+

qux: named

+ `, + + test({ assert, component, target }) { + component.foo = 'lol'; + + assert.htmlEqual(target.innerHTML, ` +

i: 2

+

foo: lol

+

qux: named

+ `); + } +}; diff --git a/test/runtime/samples/spread-component-side-effects/main.svelte b/test/runtime/samples/spread-component-side-effects/main.svelte new file mode 100644 index 0000000000..8c2dcfd2c3 --- /dev/null +++ b/test/runtime/samples/spread-component-side-effects/main.svelte @@ -0,0 +1,16 @@ + + +
+ +