Merge branch 'master' into pr/5986

pull/5986/head
Conduitry 6 years ago
commit 5d5c35e41d

@ -13,4 +13,3 @@ insert_final_newline = false
[{package.json,.travis.yml,.eslintrc.json}] [{package.json,.travis.yml,.eslintrc.json}]
indent_style = space indent_style = space
indent_size = 2

@ -1,5 +1,14 @@
# Svelte changelog # Svelte changelog
## Unreleased
* In custom elements, call `onMount` functions when connecting and clean up when disconnecting ([#1152](https://github.com/sveltejs/svelte/issues/1152), [#2227](https://github.com/sveltejs/svelte/issues/2227), [#4522](https://github.com/sveltejs/svelte/pull/4522))
* Do not emit `contextual-store` warnings for function parameters or declared variables ([#6008](https://github.com/sveltejs/svelte/pull/6008))
## 3.32.3
* Fix removal of lone `:host` selectors ([#5982](https://github.com/sveltejs/svelte/issues/5982))
## 3.32.2 ## 3.32.2
* Fix unnecessary additional invalidation with `<Component bind:prop={obj.foo}/>` ([#3075](https://github.com/sveltejs/svelte/issues/3075), [#4447](https://github.com/sveltejs/svelte/issues/4447), [#5555](https://github.com/sveltejs/svelte/issues/5555)) * Fix unnecessary additional invalidation with `<Component bind:prop={obj.foo}/>` ([#3075](https://github.com/sveltejs/svelte/issues/3075), [#4447](https://github.com/sveltejs/svelte/issues/4447), [#5555](https://github.com/sveltejs/svelte/issues/5555))

@ -0,0 +1,4 @@
if (!process.env.PUBLISH) {
console.error('npm publish must be run with the PUBLISH environment variable set');
process.exit(1);
}

2
package-lock.json generated

@ -1,6 +1,6 @@
{ {
"name": "svelte", "name": "svelte",
"version": "3.32.2", "version": "3.32.3",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {

@ -1,6 +1,6 @@
{ {
"name": "svelte", "name": "svelte",
"version": "3.32.2", "version": "3.32.3",
"description": "Cybernetically enhanced web apps", "description": "Cybernetically enhanced web apps",
"module": "index.mjs", "module": "index.mjs",
"main": "index", "main": "index",
@ -73,7 +73,7 @@
"dev": "rollup -cw", "dev": "rollup -cw",
"pretest": "npm run build", "pretest": "npm run build",
"posttest": "agadoo internal/index.mjs", "posttest": "agadoo internal/index.mjs",
"prepublishOnly": "npm run lint && PUBLISH=true npm test", "prepublishOnly": "node check_publish_env.js && npm run lint && npm test",
"tsd": "tsc -p src/compiler --emitDeclarationOnly && tsc -p src/runtime --emitDeclarationOnly", "tsd": "tsc -p src/compiler --emitDeclarationOnly && tsc -p src/runtime --emitDeclarationOnly",
"lint": "eslint \"{src,test}/**/*.{ts,js}\"" "lint": "eslint \"{src,test}/**/*.{ts,js}\""
}, },

@ -751,7 +751,7 @@ export default class Component {
return this.skip(); return this.skip();
} }
component.warn_on_undefined_store_value_references(node, parent, scope); component.warn_on_undefined_store_value_references(node, parent, prop, scope);
}, },
leave(node: Node) { leave(node: Node) {
@ -843,7 +843,7 @@ export default class Component {
}); });
} }
warn_on_undefined_store_value_references(node, parent, scope: Scope) { warn_on_undefined_store_value_references(node: Node, parent: Node, prop: string, scope: Scope) {
if ( if (
node.type === 'LabeledStatement' && node.type === 'LabeledStatement' &&
node.label.name === '$' && node.label.name === '$' &&
@ -855,7 +855,7 @@ export default class Component {
}); });
} }
if (is_reference(node as Node, parent as Node)) { if (is_reference(node, parent)) {
const object = get_object(node); const object = get_object(node);
const { name } = object; const { name } = object;
@ -865,7 +865,8 @@ export default class Component {
} }
if (name[1] !== '$' && scope.has(name.slice(1)) && scope.find_owner(name.slice(1)) !== this.instance_scope) { if (name[1] !== '$' && scope.has(name.slice(1)) && scope.find_owner(name.slice(1)) !== this.instance_scope) {
this.error(node, { if (!((/Function/.test(parent.type) && prop === 'params') || (parent.type === 'VariableDeclarator' && prop === 'id'))) {
this.error(node as any, {
code: 'contextual-store', code: 'contextual-store',
message: 'Stores must be declared at the top level of the component (this may change in a future version of Svelte)' message: 'Stores must be declared at the top level of the component (this may change in a future version of Svelte)'
}); });
@ -873,6 +874,7 @@ export default class Component {
} }
} }
} }
}
loop_protect(node, scope: Scope, timeout: number): Node | null { loop_protect(node, scope: Scope, timeout: number): Node | null {
if (node.type === 'WhileStatement' || if (node.type === 'WhileStatement' ||

@ -44,7 +44,10 @@ export default class Selector {
} }
this.local_blocks = this.blocks.slice(0, i); this.local_blocks = this.blocks.slice(0, i);
this.used = this.local_blocks.length === 0;
const host_only = this.blocks.length === 1 && this.blocks[0].host;
this.used = this.local_blocks.length === 0 || host_only;
} }
apply(node: Element) { apply(node: Element) {

@ -485,7 +485,7 @@ export default function dom(
${css.code && b`this.shadowRoot.innerHTML = \`<style>${css.code.replace(/\\/g, '\\\\')}${options.dev ? `\n/*# sourceMappingURL=${css.map.toUrl()} */` : ''}</style>\`;`} ${css.code && b`this.shadowRoot.innerHTML = \`<style>${css.code.replace(/\\/g, '\\\\')}${options.dev ? `\n/*# sourceMappingURL=${css.map.toUrl()} */` : ''}</style>\`;`}
@init(this, { target: this.shadowRoot, props: ${init_props} }, ${definition}, ${has_create_fragment ? 'create_fragment' : 'null'}, ${not_equal}, ${prop_indexes}, ${dirty}); @init(this, { target: this.shadowRoot, props: ${init_props}, customElement: true }, ${definition}, ${has_create_fragment ? 'create_fragment' : 'null'}, ${not_equal}, ${prop_indexes}, ${dirty});
${dev_props_check} ${dev_props_check}

@ -34,6 +34,7 @@ interface T$$ {
on_mount: any[]; on_mount: any[];
on_destroy: any[]; on_destroy: any[];
skip_bound: boolean; skip_bound: boolean;
on_disconnect: any[];
} }
export function bind(component, name, callback) { export function bind(component, name, callback) {
@ -52,13 +53,15 @@ export function claim_component(block, parent_nodes) {
block && block.l(parent_nodes); block && block.l(parent_nodes);
} }
export function mount_component(component, target, anchor) { export function mount_component(component, target, anchor, customElement) {
const { fragment, on_mount, on_destroy, after_update } = component.$$; const { fragment, on_mount, on_destroy, after_update } = component.$$;
fragment && fragment.m(target, anchor); fragment && fragment.m(target, anchor);
if (!customElement) {
// onMount happens before the initial afterUpdate // onMount happens before the initial afterUpdate
add_render_callback(() => { add_render_callback(() => {
const new_on_destroy = on_mount.map(run).filter(is_function); const new_on_destroy = on_mount.map(run).filter(is_function);
if (on_destroy) { if (on_destroy) {
on_destroy.push(...new_on_destroy); on_destroy.push(...new_on_destroy);
@ -69,6 +72,7 @@ export function mount_component(component, target, anchor) {
} }
component.$$.on_mount = []; component.$$.on_mount = [];
}); });
}
after_update.forEach(add_render_callback); after_update.forEach(add_render_callback);
} }
@ -113,6 +117,7 @@ export function init(component, options, instance, create_fragment, not_equal, p
// lifecycle // lifecycle
on_mount: [], on_mount: [],
on_destroy: [], on_destroy: [],
on_disconnect: [],
before_update: [], before_update: [],
after_update: [], after_update: [],
context: new Map(parent_component ? parent_component.$$.context : []), context: new Map(parent_component ? parent_component.$$.context : []),
@ -155,7 +160,7 @@ export function init(component, options, instance, create_fragment, not_equal, p
} }
if (options.intro) transition_in(component.$$.fragment); if (options.intro) transition_in(component.$$.fragment);
mount_component(component, options.target, options.anchor); mount_component(component, options.target, options.anchor, options.customElement);
flush(); flush();
} }
@ -173,6 +178,9 @@ if (typeof HTMLElement === 'function') {
} }
connectedCallback() { connectedCallback() {
const { on_mount } = this.$$;
this.$$.on_disconnect = on_mount.map(run).filter(is_function);
// @ts-ignore todo: improve typings // @ts-ignore todo: improve typings
for (const key in this.$$.slotted) { for (const key in this.$$.slotted) {
// @ts-ignore todo: improve typings // @ts-ignore todo: improve typings
@ -184,6 +192,10 @@ if (typeof HTMLElement === 'function') {
this[attr] = newValue; this[attr] = newValue;
} }
disconnectedCallback() {
run_all(this.$$.on_disconnect);
}
$destroy() { $destroy() {
destroy_component(this, 1); destroy_component(this, 1);
this.$destroy = noop; this.$destroy = noop;

@ -1 +1 @@
:host h1.svelte-xyz{color:red}:host>h1.svelte-xyz{color:red}:host>.svelte-xyz{color:red}:host span.svelte-xyz{color:red} :host h1.svelte-xyz{color:red}:host>h1.svelte-xyz{color:red}:host>.svelte-xyz{color:red}:host span.svelte-xyz{color:red}:host{color:red}

@ -18,6 +18,10 @@
:host > span { :host > span {
color: red; color: red;
} }
:host {
color: red;
}
</style> </style>
<h1>Hello!</h1> <h1>Hello!</h1>

@ -110,8 +110,8 @@ describe('custom-elements', function() {
const page = await browser.newPage(); const page = await browser.newPage();
page.on('console', (type, ...args) => { page.on('console', (type) => {
console[type](...args); console[type._type](type._text);
}); });
page.on('error', error => { page.on('error', error => {

@ -3,9 +3,12 @@
<script> <script>
import { onMount } from 'svelte'; import { onMount } from 'svelte';
export let prop = false;
export let propsInitialized;
export let wasCreated; export let wasCreated;
onMount(() => { onMount(() => {
propsInitialized = prop !== false;
wasCreated = true; wasCreated = true;
}); });
</script> </script>

@ -2,7 +2,9 @@ import * as assert from 'assert';
import './main.svelte'; import './main.svelte';
export default function (target) { export default function (target) {
target.innerHTML = '<my-app/>'; target.innerHTML = '<my-app prop/>';
const el = target.querySelector('my-app'); const el = target.querySelector('my-app');
assert.ok(el.wasCreated); assert.ok(el.wasCreated);
assert.ok(el.propsInitialized);
} }

@ -0,0 +1,22 @@
<svelte:options tag="my-app"/>
<script>
import { onMount, onDestroy } from 'svelte';
let el;
let parentEl;
onMount(() => {
parentEl = el.parentNode.host.parentElement;
return () => {
parentEl.dataset.onMountDestroyed = true;
}
});
onDestroy(() => {
parentEl.dataset.destroyed = true;
})
</script>
<div bind:this={el}></div>

@ -0,0 +1,11 @@
import * as assert from 'assert';
import './main.svelte';
export default function (target) {
target.innerHTML = '<my-app/>';
const el = target.querySelector('my-app');
target.removeChild(el);
assert.ok(target.dataset.onMountDestroyed);
assert.equal(target.dataset.destroyed, undefined);
}

@ -40,7 +40,8 @@ class Component extends SvelteElement {
this, this,
{ {
target: this.shadowRoot, target: this.shadowRoot,
props: attribute_to_object(this.attributes) props: attribute_to_object(this.attributes),
customElement: true
}, },
null, null,
create_fragment, create_fragment,

@ -0,0 +1,25 @@
<script>
function test(store) {
// allow declaring $store as parameter
// it's not referring to the store value of the
// `store` variable in the upper scope
return derived(store, $store => {
});
}
function test2(store) {
// allow declaring the `$store` variable
// it is not referring to the store value of the `store` variable
let $store;
}
</script>
<div
on:test={(store) => {
derived(store, $store => {});
}}
on:test2={(store) => {
let $store;
}}
/>
Loading…
Cancel
Save