diff --git a/src/compiler/compile/render_dom/Block.ts b/src/compiler/compile/render_dom/Block.ts index b77cf61112..3f485f82e1 100644 --- a/src/compiler/compile/render_dom/Block.ts +++ b/src/compiler/compile/render_dom/Block.ts @@ -486,7 +486,7 @@ export default class Block { `); this.chunks.destroy.push( - b`@run_all(${dispose});` + b`${dispose}.forEach((#v) => #v());` ); } } diff --git a/src/compiler/compile/render_dom/index.ts b/src/compiler/compile/render_dom/index.ts index 4009c6bddf..dbcd2e83d2 100644 --- a/src/compiler/compile/render_dom/index.ts +++ b/src/compiler/compile/render_dom/index.ts @@ -72,32 +72,48 @@ export default function dom( const uses_props = component.var_lookup.has('$$props'); const uses_rest = component.var_lookup.has('$$restProps'); - const $$props = uses_props || uses_rest ? `$$new_props` : `$$props`; + const uses_$$ = uses_props || uses_rest; + const $$props = uses_$$ ? `$$new_props` : `$$props`; const props = component.vars.filter(variable => !variable.module && variable.export_name); const writable_props = props.filter(variable => variable.writable); const omit_props_names = component.get_unique_name('omit_props_names'); - const compute_rest = x`@compute_rest_props($$props, ${omit_props_names.name})`; + const rest = uses_rest ? b` - const ${omit_props_names.name} = [${props.map(prop => `"${prop.export_name}"`).join(',')}]; - let $$restProps = ${compute_rest}; + const ${omit_props_names.name} = [${props.map(prop => `"${prop.export_name}"`)}]; + const $$restProps = {}; + for (#k in $$props) { + if (!#keys.has(#k) && #k[0] !== '$') { + $$restProps[#k] = $$props[#k]; + } + } ` : null; - const set = (uses_props || uses_rest || writable_props.length > 0 || component.slots.size > 0) - ? x` - ${$$props} => { - ${uses_props && renderer.invalidate('$$props', x`$$props = @assign(@assign({}, $$props), @exclude_internal_props($$new_props))`)} - ${uses_rest && !uses_props && x`$$props = @assign(@assign({}, $$props), @exclude_internal_props($$new_props))`} - ${uses_rest && renderer.invalidate('$$restProps', x`$$restProps = ${compute_rest}`)} - ${writable_props.map(prop => - b`if ('${prop.export_name}' in ${$$props}) ${renderer.invalidate(prop.name, x`${prop.name} = ${$$props}.${prop.export_name}`)};` - )} - ${component.slots.size > 0 && - b`if ('$$scope' in ${$$props}) ${renderer.invalidate('$$scope', x`$$scope = ${$$props}.$$scope`)};`} + const process_new_$$ = b` + for (#k in $$new_props) { + if (#k[0] !== '$') { + ${uses_rest ? b` + if (!#keys.has(#k)) { + $$props[#k] = ($$restProps[#k] = $$new_props[#k]); + } else { + $$props[#k] = $$new_props[#k]; + }` + : b`$$props[#k] = $$new_props[#k];`} } - ` - : null; - + } + ${uses_props && renderer.invalidate("$$props")} + ${uses_rest && renderer.invalidate("$$restProps")} + ` + + const set = (uses_$$ || writable_props.length > 0 || component.slots.size > 0) + ? x`${$$props} => { + ${uses_$$ ? process_new_$$ : null} + ${writable_props.map(prop => b`if ('${prop.export_name}' in ${$$props}) ${renderer.invalidate(prop.name, x`${prop.name} = ${$$props}.${prop.export_name}`)};`)} + ${component.slots.size > 0 && b`if ('$$scope' in ${$$props}) ${renderer.invalidate('$$scope', x`$$scope = ${$$props}.$$scope`)};`} + }` + : null; + + const k = set ? b`let #k;` : null const accessors = []; const not_equal = component.component_options.immutable ? x`@not_equal` : x`@safe_not_equal`; @@ -188,7 +204,7 @@ export default function dom( if (uses_props || injectable_vars.length > 0) { inject_state = x` ${$$props} => { - ${uses_props && renderer.invalidate('$$props', x`$$props = @assign(@assign({}, $$props), $$new_props)`)} + ${uses_props && renderer.invalidate('$$props', x`$$props = { ...$$props, ...$$new_props }`)} ${injectable_vars.map( v => b`if ('${v.name}' in $$props) ${renderer.invalidate(v.name, x`${v.name} = ${$$props}.${v.name}`)};` )} @@ -251,7 +267,7 @@ export default function dom( const insert = (reassigned || export_name) ? b`${`$$subscribe_${name}`}()` - : b`@component_subscribe($$self, ${name}, #value => $$invalidate(${i}, ${value} = #value))`; + : b`$$self.$$.on_destroy.push(@subscribe(${name}, #value => {$$invalidate(${i}, (${value} = #value));})`; if (component.compile_options.dev) { return b`@validate_store(${name}, '${name}'); ${insert}`; @@ -335,7 +351,9 @@ export default function dom( }) .map(({ name }) => b` ${component.compile_options.dev && b`@validate_store(${name.slice(1)}, '${name.slice(1)}');`} - @component_subscribe($$self, ${name.slice(1)}, $$value => $$invalidate(${renderer.context_lookup.get(name).index}, ${name} = $$value)); + $$self.$$.on_destroy.push(@subscribe(${name.slice(1)}, #value => { + $$invalidate(${renderer.context_lookup.get(name).index}, (${name} = #value)); + })); `); const resubscribable_reactive_store_unsubscribers = reactive_stores @@ -386,7 +404,14 @@ export default function dom( const subscribe = `$$subscribe_${name}`; const i = renderer.context_lookup.get($name).index; - return b`let ${$name}, ${unsubscribe} = @noop, ${subscribe} = () => (${unsubscribe}(), ${unsubscribe} = @subscribe(${name}, $$value => $$invalidate(${i}, ${$name} = $$value)), ${name})`; + return b` + let ${$name}, + ${unsubscribe} = @noop, + ${subscribe} = () => { + ${unsubscribe}(); + ${unsubscribe} = @subscribe(${name}, (#value) => { $$invalidate(${i}, (${$name} = #value)); }); + return ${name}; + };`; } return b`let ${$name};`; @@ -412,6 +437,8 @@ export default function dom( body.push(b` function ${definition}(${args}) { + ${k} + ${rest} ${reactive_store_declarations} @@ -449,7 +476,7 @@ export default function dom( ${fixed_reactive_declarations} - ${uses_props && b`$$props = @exclude_internal_props($$props);`} + ${uses_props && b`for (#k in $$props) if (#k[0] === '$') delete $$props[#k];`} return ${return_value}; } diff --git a/src/compiler/compile/render_dom/wrappers/EachBlock.ts b/src/compiler/compile/render_dom/wrappers/EachBlock.ts index 1efadfb90c..5a713a4c51 100644 --- a/src/compiler/compile/render_dom/wrappers/EachBlock.ts +++ b/src/compiler/compile/render_dom/wrappers/EachBlock.ts @@ -604,6 +604,9 @@ export default class EachBlockWrapper extends Wrapper { `); } - block.chunks.destroy.push(b`@destroy_each(${iterations}, detaching);`); + block.chunks.destroy.push(b` + for (let #i = 0; #i < ${iterations}.length; #i += 1) { + if (${iterations}[#i]) ${iterations}[#i].d(detaching); + }`); } } diff --git a/src/compiler/compile/render_dom/wrappers/Element/Attribute.ts b/src/compiler/compile/render_dom/wrappers/Element/Attribute.ts index ca941b7be9..d43d3a78ad 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/Attribute.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/Attribute.ts @@ -215,7 +215,7 @@ export default class AttributeWrapper { if (scoped_css && rendered.length === 2) { // we have a situation like class={possiblyUndefined} - rendered[0] = x`@null_to_empty(${rendered[0]})`; + rendered[0] = x`null != ${rendered[0]} ? ${rendered[0]} : ""`; } return rendered.reduce((lhs, rhs) => x`${lhs} + ${rhs}`); diff --git a/src/compiler/compile/render_dom/wrappers/Element/EventHandler.ts b/src/compiler/compile/render_dom/wrappers/Element/EventHandler.ts index 157e186ea6..18f859051f 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/EventHandler.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/EventHandler.ts @@ -31,7 +31,7 @@ export default class EventHandlerWrapper { if (this.node.reassigned) { block.maintain_context = true; - return x`function () { if (@is_function(${snippet})) ${snippet}.apply(this, arguments); }`; + return x`function () { if ("function" === typeof (${snippet})) ${snippet}.apply(this, arguments); }`; } return snippet; } diff --git a/src/compiler/compile/render_dom/wrappers/Element/index.ts b/src/compiler/compile/render_dom/wrappers/Element/index.ts index 83bc8be94e..62b606efe1 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/index.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/index.ts @@ -690,11 +690,10 @@ export default class ElementWrapper extends Wrapper { }); block.chunks.init.push(b` - let ${levels} = [${initial_props}]; - - let ${data} = {}; - for (let #i = 0; #i < ${levels}.length; #i += 1) { - ${data} = @assign(${data}, ${levels}[#i]); + const ${levels} = [${initial_props}]; + let ${data} = ${levels}[0] || {}; + for (let i = 1; i < ${levels}.length; i++) { + ${data} = { ...${data}, ...${levels}[i] }; } `); diff --git a/src/compiler/compile/render_dom/wrappers/Head.ts b/src/compiler/compile/render_dom/wrappers/Head.ts index e0b723d6dd..9dccb54269 100644 --- a/src/compiler/compile/render_dom/wrappers/Head.ts +++ b/src/compiler/compile/render_dom/wrappers/Head.ts @@ -36,7 +36,7 @@ export default class HeadWrapper extends Wrapper { let nodes; if (this.renderer.options.hydratable && this.fragment.nodes.length) { nodes = block.get_unique_name('head_nodes'); - block.chunks.claim.push(b`const ${nodes} = @query_selector_all('[data-svelte="${this.node.id}"]', @_document.head);`); + block.chunks.claim.push(b`const ${nodes} = Array.from(( @_document.head || @_document.body ).querySelectorAll('[data-svelte="${this.node.id}"]'));`); } this.fragment.render(block, x`@_document.head` as unknown as Identifier, nodes); diff --git a/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts b/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts index 00f803bbbd..1527f665e7 100644 --- a/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts +++ b/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts @@ -241,7 +241,7 @@ export default class InlineComponentWrapper extends Wrapper { let value_object = value; if (attr.expression.node.type !== 'ObjectExpression') { - value_object = x`@get_spread_object(${value})`; + value_object = x`typeof (#buffer = ${value}) === 'object' && #buffer !== null ? #buffer : {}` } change_object = value_object; } else { @@ -265,16 +265,13 @@ export default class InlineComponentWrapper extends Wrapper { ]; `); - statements.push(b` - for (let #i = 0; #i < ${levels}.length; #i += 1) { - ${props} = @assign(${props}, ${levels}[#i]); - } - `); + statements.push(b`${props} = @_Object.assign(${props}, ...${levels});`); if (all_dependencies.size) { const condition = renderer.dirty(Array.from(all_dependencies)); updates.push(b` + let #buffer; const ${name_changes} = ${condition} ? @get_spread_update(${levels}, [ ${changes} ]) : {} @@ -424,7 +421,7 @@ export default class InlineComponentWrapper extends Wrapper { `); block.chunks.create.push( - b`if (${name}) @create_component(${name}.$$.fragment);` + b`if (${name} && ${name}.$$.fragment) ${name}.$$.fragment.c();` ); if (parent_nodes && this.renderer.options.hydratable) { @@ -465,7 +462,7 @@ export default class InlineComponentWrapper extends Wrapper { ${munged_bindings} ${munged_handlers} - @create_component(${name}.$$.fragment); + if(${name}.$$.fragment) ${name}.$$.fragment.c(); @transition_in(${name}.$$.fragment, 1); @mount_component(${name}, ${update_mount_node}, ${anchor}); } else { @@ -500,11 +497,11 @@ export default class InlineComponentWrapper extends Wrapper { ${munged_handlers} `); - block.chunks.create.push(b`@create_component(${name}.$$.fragment);`); + block.chunks.create.push(b`if(${name}.$$.fragment) ${name}.$$.fragment.c();`); if (parent_nodes && this.renderer.options.hydratable) { block.chunks.claim.push( - b`@claim_component(${name}.$$.fragment, ${parent_nodes});` + b`if(${name}.$$.fragment) ${name}.$$.fragment.l(${parent_nodes});` ); } diff --git a/src/compiler/compile/render_dom/wrappers/Slot.ts b/src/compiler/compile/render_dom/wrappers/Slot.ts index 268875acaf..fed9ad37b7 100644 --- a/src/compiler/compile/render_dom/wrappers/Slot.ts +++ b/src/compiler/compile/render_dom/wrappers/Slot.ts @@ -126,10 +126,15 @@ export default class SlotWrapper extends Wrapper { const slot = block.get_unique_name(`${sanitize(slot_name)}_slot`); const slot_definition = block.get_unique_name(`${sanitize(slot_name)}_slot_template`); const slot_or_fallback = has_fallback ? block.get_unique_name(`${sanitize(slot_name)}_slot_or_fallback`) : slot; + const $$scope = renderer.reference('$$scope'); + const context = x` + ${slot_definition}[1] && ${get_slot_context_fn} + ? @_Object.assign(${$$scope}.ctx.slice(), ${slot_definition}[1](${get_slot_context_fn}(#ctx))) + : ${$$scope}.ctx`; block.chunks.init.push(b` const ${slot_definition} = ${renderer.reference('$$slots')}.${slot_name}; - const ${slot} = @create_slot(${slot_definition}, #ctx, ${renderer.reference('$$scope')}, ${get_slot_context_fn}); + const ${slot} = ${slot_definition} && ${slot_definition}[0](${context}); ${has_fallback ? b`const ${slot_or_fallback} = ${slot} || ${this.fallback.name}(#ctx);` : null} `); @@ -172,7 +177,8 @@ export default class SlotWrapper extends Wrapper { const slot_update = b` if (${slot}.p && ${renderer.dirty(dynamic_dependencies)}) { - @update_slot(${slot}, ${slot_definition}, #ctx, ${renderer.reference('$$scope')}, #dirty, ${get_slot_changes_fn}, ${get_slot_context_fn}); + const #changes = @get_slot_changes(${slot_definition}, ${$$scope}, #dirty, ${get_slot_changes_fn}) + if (#changes) ${slot}.p(${context}, #changes); } `; const fallback_update = has_fallback && fallback_dynamic_dependencies.length > 0 && b` diff --git a/src/compiler/compile/render_dom/wrappers/shared/add_actions.ts b/src/compiler/compile/render_dom/wrappers/shared/add_actions.ts index 3d8c4fbbc0..c3172631db 100644 --- a/src/compiler/compile/render_dom/wrappers/shared/add_actions.ts +++ b/src/compiler/compile/render_dom/wrappers/shared/add_actions.ts @@ -29,11 +29,11 @@ export function add_action(block: Block, target: string, action: Action) { const fn = block.renderer.reference(action.name); block.event_listeners.push( - x`@action_destroyer(${id} = ${fn}.call(null, ${target}, ${snippet}))` + x`(${id} = ${fn}.call(null, ${target}, ${snippet})) && 'function' === typeof ${id}.destroy ? ${id}.destroy : @noop` ); if (dependencies && dependencies.length > 0) { - let condition = x`${id} && @is_function(${id}.update)`; + let condition = x`${id} && "function" === typeof ${id}.update`; if (dependencies.length > 0) { condition = x`${condition} && ${block.renderer.dirty(dependencies)}`; diff --git a/src/compiler/compile/render_ssr/handlers/AwaitBlock.ts b/src/compiler/compile/render_ssr/handlers/AwaitBlock.ts index 6a62f872bb..3464ad82d8 100644 --- a/src/compiler/compile/render_ssr/handlers/AwaitBlock.ts +++ b/src/compiler/compile/render_ssr/handlers/AwaitBlock.ts @@ -13,7 +13,7 @@ export default function(node: AwaitBlock, renderer: Renderer, options: RenderOpt renderer.add_expression(x` function(__value) { - if (@is_promise(__value)) return ${pending}; + if (__value && typeof __value === 'object' && typeof __value.then === 'function') return ${pending}; return (function(${node.then_node ? node.then_node : ''}) { return ${then}; }(__value)); }(${node.expression.node}) `); diff --git a/src/compiler/compile/render_ssr/handlers/shared/get_attribute_value.ts b/src/compiler/compile/render_ssr/handlers/shared/get_attribute_value.ts index 5c89a7a008..f13f52df18 100644 --- a/src/compiler/compile/render_ssr/handlers/shared/get_attribute_value.ts +++ b/src/compiler/compile/render_ssr/handlers/shared/get_attribute_value.ts @@ -9,7 +9,7 @@ export function get_class_attribute_value(attribute: Attribute): ESTreeExpressio // handle special case — `class={possiblyUndefined}` with scoped CSS if (attribute.chunks.length === 2 && (attribute.chunks[1] as Text).synthetic) { const value = (attribute.chunks[0] as Expression).node; - return x`@escape(@null_to_empty(${value})) + "${(attribute.chunks[1] as Text).data}"`; + return x`(${x`${value} != null ? @escape(${value}) : ""`}) + "${(attribute.chunks[1] as Text).data}"`; } return get_attribute_value(attribute); diff --git a/src/compiler/compile/render_ssr/index.ts b/src/compiler/compile/render_ssr/index.ts index c87fe3bdd9..8abc4082b4 100644 --- a/src/compiler/compile/render_ssr/index.ts +++ b/src/compiler/compile/render_ssr/index.ts @@ -32,8 +32,14 @@ export default function ssr( component.stylesheet.render(options.filename, true); const uses_rest = component.var_lookup.has('$$restProps'); - const props = component.vars.filter(variable => !variable.module && variable.export_name); - const rest = uses_rest ? b`let $$restProps = @compute_rest_props($$props, [${props.map(prop => `"${prop.export_name}"`).join(',')}]);` : null; + const props = component.vars.filter((variable => !variable.module && variable.export_name)); + const rest = uses_rest + ? b` + let #k; + const #keys = new Set([${props.map(prop => `"${prop.export_name}"`)}]); + let $$restProps = {}; + for (#k in $$props){ if (!#keys.has(#k) && #k[0] !== '$'){ $$restProps[#k] = $$props[#k];}}` + : null; const reactive_stores = component.vars.filter(variable => variable.name[0] === '$' && variable.name[1] !== '$'); const reactive_store_values = reactive_stores @@ -42,7 +48,7 @@ export default function ssr( const store = component.var_lookup.get(store_name); if (store && store.hoistable) return null; - const assignment = b`${name} = @get_store_value(${store_name});`; + const assignment = b`@subscribe(${store_name}, (#v) => { ${name} = #v; })();`; return component.compile_options.dev ? b`@validate_store(${store_name}, '${store_name}'); ${assignment}` @@ -50,16 +56,12 @@ export default function ssr( }) .filter(Boolean); - component.rewrite_props(({ name }) => { - const value = `$${name}`; - - let insert = b`${value} = @get_store_value(${name})`; - if (component.compile_options.dev) { - insert = b`@validate_store(${name}, '${name}'); ${insert}`; - } - - return insert; - }); + component.rewrite_props( + ({ name }) => + b` + ${component.compile_options.dev && b`@validate_store_dev(${name}, '${name}');`} + @subscribe(${name}, (#v) => { ${`$${name}`} = #v; })();` + ); const instance_javascript = component.extract_javascript(component.ast.instance); @@ -138,10 +140,9 @@ export default function ssr( ...reactive_stores.map(({ name }) => { const store_name = name.slice(1); const store = component.var_lookup.get(store_name); - if (store && store.hoistable) { - return b`let ${name} = @get_store_value(${store_name});`; - } - return b`let ${name};`; + return b` + let ${name}; + ${store && store.hoistable && b`@subscribe(${store_name},(#v) => { ${name}=#v; })();`}`; }), instance_javascript, diff --git a/src/runtime/animate/index.ts b/src/runtime/animate/index.ts index 087c0f7141..4f5324610c 100644 --- a/src/runtime/animate/index.ts +++ b/src/runtime/animate/index.ts @@ -1,5 +1,4 @@ import { cubicOut } from 'svelte/easing'; -import { is_function } from 'svelte/internal'; // todo: same as Transition, should it be shared? export interface AnimationConfig { @@ -35,7 +34,7 @@ export function flip(node: Element, animation: { from: DOMRect; to: DOMRect }, p return { delay, - duration: is_function(duration) ? duration(d) : duration, + duration: typeof duration === "function" ? duration(d) : duration, easing, css: (_t, u) => `transform: ${transform} translate(${u * dx}px, ${u * dy}px);` }; diff --git a/src/runtime/internal/Component.ts b/src/runtime/internal/Component.ts index 7d2a92fa1b..ccec235c8d 100644 --- a/src/runtime/internal/Component.ts +++ b/src/runtime/internal/Component.ts @@ -1,6 +1,6 @@ import { add_render_callback, flush, schedule_update, dirty_components } from './scheduler'; import { current_component, set_current_component } from './lifecycle'; -import { blank_object, is_function, run, run_all, noop } from './utils'; +import { noop } from './utils'; import { children, detach } from './dom'; import { transition_in } from './transitions'; @@ -59,13 +59,13 @@ export function mount_component(component, target, anchor) { // onMount happens before the initial afterUpdate add_render_callback(() => { - const new_on_destroy = on_mount.map(run).filter(is_function); + const new_on_destroy = on_mount.map(v => v()).filter(v => typeof v === "function"); if (on_destroy) { on_destroy.push(...new_on_destroy); } else { // Edge case - component was destroyed immediately, // most likely as a result of a binding initialising - run_all(new_on_destroy); + new_on_destroy.forEach(v => v()); } component.$$.on_mount = []; }); @@ -76,7 +76,7 @@ export function mount_component(component, target, anchor) { export function destroy_component(component, detaching) { const $$ = component.$$; if ($$.fragment !== null) { - run_all($$.on_destroy); + $$.on_destroy.forEach(v => v()); $$.fragment && $$.fragment.d(detaching); @@ -110,7 +110,7 @@ export function init(component, options, instance, create_fragment, not_equal, p props, update: noop, not_equal, - bound: blank_object(), + bound: Object.create(null), // lifecycle on_mount: [], @@ -120,7 +120,7 @@ export function init(component, options, instance, create_fragment, not_equal, p context: new Map(parent_component ? parent_component.$$.context : []), // everything else - callbacks: blank_object(), + callbacks: Object.create(null), dirty }; @@ -139,7 +139,7 @@ export function init(component, options, instance, create_fragment, not_equal, p $$.update(); ready = true; - run_all($$.before_update); + $$.before_update.forEach(v => v()); // `false` as a special case of no DOM component $$.fragment = create_fragment ? create_fragment($$.ctx) : false; diff --git a/src/runtime/internal/await_block.ts b/src/runtime/internal/await_block.ts index f70cbd6c2c..32f8156a11 100644 --- a/src/runtime/internal/await_block.ts +++ b/src/runtime/internal/await_block.ts @@ -1,4 +1,3 @@ -import { is_promise } from './utils'; import { check_outros, group_outros, transition_in, transition_out } from './transitions'; import { flush } from './scheduler'; import { get_current_component, set_current_component } from './lifecycle'; @@ -52,7 +51,7 @@ export function handle_promise(promise, info) { } } - if (is_promise(promise)) { + if (promise && typeof promise === 'object' && typeof promise.then === 'function') { const current_component = get_current_component(); promise.then(value => { set_current_component(current_component); diff --git a/src/runtime/internal/dev.ts b/src/runtime/internal/dev.ts index 751f1f802b..f3e655639f 100644 --- a/src/runtime/internal/dev.ts +++ b/src/runtime/internal/dev.ts @@ -1,6 +1,12 @@ import { custom_event, append, insert, detach, listen, attr } from './dom'; import { SvelteComponent } from './Component'; +export function add_location(element, file, line, column, char) { + element.__svelte_meta = { + loc: { file, line, column, char } + }; +} + export function dispatch_dev(type: string, detail?: T) { document.dispatchEvent(custom_event(type, { version: '__VERSION__', ...detail })); } @@ -79,6 +85,15 @@ export function set_data_dev(text, data) { text.data = data; } +export function validate_component(component, name) { + if (!component || !component.$$render) { + if (name === 'svelte:component') name += ' this={...}'; + throw new Error(`<${name}> is not a valid SSR component. You may need to review your build config to ensure that dependencies are compiled, rather than imported as pre-compiled modules`); + } + + return component; +} + export function validate_each_argument(arg) { if (typeof arg !== 'string' && !(arg && typeof arg === 'object' && 'length' in arg)) { let msg = '{#each} only iterates over array-like objects.'; @@ -97,6 +112,24 @@ export function validate_slots(name, slot, keys) { } } +export function validate_store(store, name) { + if (store != null && typeof store.subscribe !== 'function') { + throw new Error(`'${name}' is not a store with a 'subscribe' method`); + } +} + +export function validate_each_keys(ctx, list, get_context, get_key) { + const keys = new Set(); + for (let i = 0; i < list.length; i++) { + const key = get_key(get_context(ctx, list, i)); + if (keys.has(key)) { + throw new Error(`Cannot have duplicate keys in a keyed each`); + } + keys.add(key); + } +} + + type Props = Record; export interface SvelteComponentDev { $set(props?: Props): void; diff --git a/src/runtime/internal/dom.ts b/src/runtime/internal/dom.ts index f67fd13b2d..677afa5a24 100644 --- a/src/runtime/internal/dom.ts +++ b/src/runtime/internal/dom.ts @@ -1,5 +1,3 @@ -import { has_prop } from "./utils"; - export function append(target: Node, node: Node) { target.appendChild(node); } @@ -26,18 +24,10 @@ export function element_is(name: K, is: s return document.createElement(name, { is }); } -export function object_without_properties(obj: T, exclude: K[]) { - const target = {} as Pick>; - for (const k in obj) { - if ( - has_prop(obj, k) - // @ts-ignore - && exclude.indexOf(k) === -1 - ) { - // @ts-ignore - target[k] = obj[k]; - } - } +export function object_without_properties(obj: T, excluded: K) { + const target = {} as Pick>; + let key; + for (key in obj) if (!~excluded.indexOf(key)) target[key] = obj[key]; return target; } @@ -85,6 +75,15 @@ export function self(fn) { }; } +export function once(fn) { + let ran = false; + return function(this: any, ...args) { + if (ran) return; + ran = true; + fn.call(this, ...args); + }; +} + export function attr(node: Element, attribute: string, value?: string) { if (value == null) node.removeAttribute(attribute); else if (node.getAttribute(attribute) !== value) node.setAttribute(attribute, value); @@ -309,10 +308,6 @@ export function custom_event(type: string, detail?: T) { return e; } -export function query_selector_all(selector: string, parent: HTMLElement = document.body) { - return Array.from(parent.querySelectorAll(selector)); -} - export class HtmlTag { e: HTMLElement; n: ChildNode[]; diff --git a/src/runtime/internal/keyed_each.ts b/src/runtime/internal/keyed_each.ts index b397335c87..b1ac429c9c 100644 --- a/src/runtime/internal/keyed_each.ts +++ b/src/runtime/internal/keyed_each.ts @@ -106,15 +106,4 @@ export function update_keyed_each(old_blocks, dirty, get_key, dynamic, ctx, list while (n) insert(new_blocks[n - 1]); return new_blocks; -} - -export function validate_each_keys(ctx, list, get_context, get_key) { - const keys = new Set(); - for (let i = 0; i < list.length; i++) { - const key = get_key(get_context(ctx, list, i)); - if (keys.has(key)) { - throw new Error(`Cannot have duplicate keys in a keyed each`); - } - keys.add(key); - } -} +} \ No newline at end of file diff --git a/src/runtime/internal/scheduler.ts b/src/runtime/internal/scheduler.ts index b0db71035a..35d946c1b8 100644 --- a/src/runtime/internal/scheduler.ts +++ b/src/runtime/internal/scheduler.ts @@ -1,4 +1,3 @@ -import { run_all } from './utils'; import { set_current_component } from './lifecycle'; export const dirty_components = []; @@ -43,7 +42,15 @@ export function flush() { for (let i = 0; i < dirty_components.length; i += 1) { const component = dirty_components[i]; set_current_component(component); - update(component.$$); + const { $$ } = component + if ($$.fragment !== null) { + $$.update(); + $$.before_update.forEach(v => v()); + const dirty = $$.dirty; + $$.dirty = [-1]; + $$.fragment && $$.fragment.p($$.ctx, dirty); + $$.after_update.forEach(add_render_callback); + } } dirty_components.length = 0; @@ -74,16 +81,4 @@ export function flush() { update_scheduled = false; flushing = false; seen_callbacks.clear(); -} - -function update($$) { - if ($$.fragment !== null) { - $$.update(); - run_all($$.before_update); - const dirty = $$.dirty; - $$.dirty = [-1]; - $$.fragment && $$.fragment.p($$.ctx, dirty); - - $$.after_update.forEach(add_render_callback); - } -} +} \ No newline at end of file diff --git a/src/runtime/internal/spread.ts b/src/runtime/internal/spread.ts index 203b0b11e9..6006b327ce 100644 --- a/src/runtime/internal/spread.ts +++ b/src/runtime/internal/spread.ts @@ -34,8 +34,4 @@ 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/src/runtime/internal/ssr.ts b/src/runtime/internal/ssr.ts index 646a81d817..459905fc3b 100644 --- a/src/runtime/internal/ssr.ts +++ b/src/runtime/internal/ssr.ts @@ -1,5 +1,4 @@ import { set_current_component, current_component } from './lifecycle'; -import { run_all, blank_object } from './utils'; import { boolean_attributes } from '../../compiler/compile/render_ssr/handlers/shared/boolean_attributes'; export const invalid_attribute_name_character = /[\s'">/=\u{FDD0}-\u{FDEF}\u{FFFE}\u{FFFF}\u{1FFFE}\u{1FFFF}\u{2FFFE}\u{2FFFF}\u{3FFFE}\u{3FFFF}\u{4FFFE}\u{4FFFF}\u{5FFFE}\u{5FFFF}\u{6FFFE}\u{6FFFF}\u{7FFFE}\u{7FFFF}\u{8FFFE}\u{8FFFF}\u{9FFFE}\u{9FFFF}\u{AFFFE}\u{AFFFF}\u{BFFFE}\u{BFFFF}\u{CFFFE}\u{CFFFF}\u{DFFFE}\u{DFFFF}\u{EFFFE}\u{EFFFF}\u{FFFFE}\u{FFFFF}\u{10FFFE}\u{10FFFF}]/u; @@ -56,15 +55,6 @@ export const missing_component = { $$render: () => '' }; -export function validate_component(component, name) { - if (!component || !component.$$render) { - if (name === 'svelte:component') name += ' this={...}'; - throw new Error(`<${name}> is not a valid SSR component. You may need to review your build config to ensure that dependencies are compiled, rather than imported as pre-compiled modules`); - } - - return component; -} - export function debug(file, line, column, values) { console.log(`{@debug} ${file ? file + ' ' : ''}(${line}:${column})`); // eslint-disable-line no-console console.log(values); // eslint-disable-line no-console @@ -85,7 +75,7 @@ export function create_ssr_component(fn) { on_mount: [], before_update: [], after_update: [], - callbacks: blank_object() + callbacks: Object.create(null) }; set_current_component({ $$ }); @@ -111,7 +101,7 @@ export function create_ssr_component(fn) { const html = $$render(result, props, {}, options); - run_all(on_destroy); + on_destroy.forEach(v => v()); return { html, diff --git a/src/runtime/internal/transitions.ts b/src/runtime/internal/transitions.ts index ed23d3c1dd..ce7a036b49 100644 --- a/src/runtime/internal/transitions.ts +++ b/src/runtime/internal/transitions.ts @@ -1,4 +1,4 @@ -import { identity as linear, is_function, noop, run_all } from './utils'; +import { identity as linear, noop } from './utils'; import { now } from "./environment"; import { loop } from './loop'; import { create_rule, delete_rule } from './style_manager'; @@ -36,7 +36,7 @@ export function group_outros() { export function check_outros() { if (!outros.r) { - run_all(outros.c); + outros.c.forEach(v => v()); } outros = outros.p; } @@ -129,7 +129,8 @@ export function create_in_transition(node: Element & ElementCSSInlineStyle, fn: delete_rule(node); - if (is_function(config)) { + if (typeof config === "function") { + //@ts-ignore config = config(); wait().then(go); } else { @@ -185,7 +186,7 @@ export function create_out_transition(node: Element & ElementCSSInlineStyle, fn: if (!--group.r) { // this will result in `end()` being called, // so we don't need to clean up here - run_all(group.c); + group.c.forEach(v => v()); } return false; @@ -201,7 +202,7 @@ export function create_out_transition(node: Element & ElementCSSInlineStyle, fn: }); } - if (is_function(config)) { + if (typeof config === "function") { wait().then(() => { // @ts-ignore config = config(); @@ -313,7 +314,7 @@ export function create_bidirectional_transition(node: Element & ElementCSSInline clear_animation(); } else { // outro — needs to be coordinated - if (!--running_program.group.r) run_all(running_program.group.c); + if (!--running_program.group.r) running_program.group.c.forEach(v => v()); } } @@ -334,7 +335,7 @@ export function create_bidirectional_transition(node: Element & ElementCSSInline return { run(b) { - if (is_function(config)) { + if (typeof config === "function") { wait().then(() => { // @ts-ignore config = config(); diff --git a/src/runtime/internal/utils.ts b/src/runtime/internal/utils.ts index d752c9de9d..4c2ff415ca 100644 --- a/src/runtime/internal/utils.ts +++ b/src/runtime/internal/utils.ts @@ -2,38 +2,6 @@ export function noop() {} export const identity = x => x; -export function assign(tar: T, src: S): T & S { - // @ts-ignore - for (const k in src) tar[k] = src[k]; - return tar as T & S; -} - -export function is_promise(value: any): value is PromiseLike { - return value && typeof value === 'object' && typeof value.then === 'function'; -} - -export function add_location(element, file, line, column, char) { - element.__svelte_meta = { - loc: { file, line, column, char } - }; -} - -export function run(fn) { - return fn(); -} - -export function blank_object() { - return Object.create(null); -} - -export function run_all(fns) { - fns.forEach(run); -} - -export function is_function(thing: any): thing is Function { - return typeof thing === 'function'; -} - export function safe_not_equal(a, b) { return a != a ? b == b : a !== b || ((a && typeof a === 'object') || typeof a === 'function'); } @@ -42,10 +10,15 @@ export function not_equal(a, b) { return a != a ? b == b : a !== b; } -export function validate_store(store, name) { - if (store != null && typeof store.subscribe !== 'function') { - throw new Error(`'${name}' is not a store with a 'subscribe' method`); - } +export function get_slot_changes(definition, $$scope, dirty, fn) { + if (!definition[2] || !fn) return $$scope.dirty; + const lets = definition[2](fn(dirty)); + if ($$scope.dirty === void 0) return lets; + else if (typeof lets === 'object') { + const merged = new Array(Math.max($$scope.dirty.length, lets.length)); + for (let i = 0; i < merged.length; i += 1) merged[i] = $$scope.dirty[i] | lets[i]; + return merged; + } else return $$scope.dirty | lets; } export function subscribe(store, ...callbacks) { @@ -56,94 +29,7 @@ export function subscribe(store, ...callbacks) { return unsub.unsubscribe ? () => unsub.unsubscribe() : unsub; } -export function get_store_value(store) { - let value; - subscribe(store, _ => value = _)(); - return value; -} - -export function component_subscribe(component, store, callback) { - component.$$.on_destroy.push(subscribe(store, callback)); -} - -export function create_slot(definition, ctx, $$scope, fn) { - if (definition) { - const slot_ctx = get_slot_context(definition, ctx, $$scope, fn); - return definition[0](slot_ctx); - } -} - -export function get_slot_context(definition, ctx, $$scope, fn) { - return definition[1] && fn - ? assign($$scope.ctx.slice(), definition[1](fn(ctx))) - : $$scope.ctx; -} - -export function get_slot_changes(definition, $$scope, dirty, fn) { - if (definition[2] && fn) { - const lets = definition[2](fn(dirty)); - - if ($$scope.dirty === undefined) { - return lets; - } - - if (typeof lets === 'object') { - const merged = []; - const len = Math.max($$scope.dirty.length, lets.length); - for (let i = 0; i < len; i += 1) { - merged[i] = $$scope.dirty[i] | lets[i]; - } - - return merged; - } - - return $$scope.dirty | lets; - } - - return $$scope.dirty; -} - -export function update_slot(slot, slot_definition, ctx, $$scope, dirty, get_slot_changes_fn, get_slot_context_fn) { - const slot_changes = get_slot_changes(slot_definition, $$scope, dirty, get_slot_changes_fn); - if (slot_changes) { - const slot_context = get_slot_context(slot_definition, ctx, $$scope, get_slot_context_fn); - slot.p(slot_context, slot_changes); - } -} - -export function exclude_internal_props(props) { - const result = {}; - for (const k in props) if (k[0] !== '$') result[k] = props[k]; - return result; -} - -export function compute_rest_props(props, keys) { - const rest = {}; - keys = new Set(keys); - for (const k in props) if (!keys.has(k) && k[0] !== '$') rest[k] = props[k]; - return rest; -} - -export function once(fn) { - let ran = false; - return function(this: any, ...args) { - if (ran) return; - ran = true; - fn.call(this, ...args); - }; -} - -export function null_to_empty(value) { - return value == null ? '' : value; -} - export function set_store_value(store, ret, value = ret) { store.set(value); return ret; -} - -export const has_prop = (obj, prop) => Object.prototype.hasOwnProperty.call(obj, prop); - -export function action_destroyer(action_result) { - return action_result && is_function(action_result.destroy) ? action_result.destroy : noop; } \ No newline at end of file diff --git a/src/runtime/motion/tweened.ts b/src/runtime/motion/tweened.ts index c802604c0e..62d05c023f 100644 --- a/src/runtime/motion/tweened.ts +++ b/src/runtime/motion/tweened.ts @@ -1,5 +1,5 @@ import { Readable, writable } from 'svelte/store'; -import { assign, loop, now, Task } from 'svelte/internal'; +import { loop, now, Task } from 'svelte/internal'; import { linear } from 'svelte/easing'; import { is_date } from './utils'; @@ -91,7 +91,7 @@ export function tweened(value?: T, defaults: Options = {}): Tweened { duration = 400, easing = linear, interpolate = get_interpolator - } = assign(assign({}, defaults), opts); + } = { ...defaults, ...opts }; if (duration === 0) { if (previous_task) { diff --git a/src/runtime/store/index.ts b/src/runtime/store/index.ts index 2bbfdfcd60..c114545004 100644 --- a/src/runtime/store/index.ts +++ b/src/runtime/store/index.ts @@ -1,4 +1,4 @@ -import { run_all, subscribe, noop, safe_not_equal, is_function, get_store_value } from 'svelte/internal'; +import { subscribe, noop, safe_not_equal } from 'svelte/internal'; /** Callback to inform of a value updates. */ type Subscriber = (value: T) => void; @@ -169,7 +169,7 @@ export function derived(stores: Stores, fn: Function, initial_value?: T): Rea if (auto) { set(result as T); } else { - cleanup = is_function(result) ? result as Unsubscriber : noop; + cleanup = "function" === typeof result ? result as Unsubscriber : noop; } }; @@ -191,7 +191,7 @@ export function derived(stores: Stores, fn: Function, initial_value?: T): Rea sync(); return function stop() { - run_all(unsubscribers); + unsubscribers.forEach(v => v()); cleanup(); }; }); @@ -201,4 +201,8 @@ export function derived(stores: Stores, fn: Function, initial_value?: T): Rea * Get the current value from a store by subscribing and immediately unsubscribing. * @param store readable */ -export { get_store_value as get }; \ No newline at end of file +export function get(store) { + let value; + subscribe(store, _ => value = _)(); + return value; +} \ No newline at end of file diff --git a/src/runtime/transition/index.ts b/src/runtime/transition/index.ts index 0a20c81b1f..2575b472e5 100644 --- a/src/runtime/transition/index.ts +++ b/src/runtime/transition/index.ts @@ -1,5 +1,4 @@ import { cubicOut, cubicInOut, linear } from 'svelte/easing'; -import { assign, is_function } from 'svelte/internal'; type EasingFunction = (t: number) => number; @@ -217,7 +216,8 @@ export function crossfade({ fallback, ...defaults }: CrossfadeParams & { delay = 0, duration = d => Math.sqrt(d) * 30, easing = cubicOut - } = assign(assign({}, defaults), params); + //@ts-ignore + } = {...defaults, params}; const to = node.getBoundingClientRect(); const dx = from.left - to.left; @@ -232,7 +232,7 @@ export function crossfade({ fallback, ...defaults }: CrossfadeParams & { return { delay, - duration: is_function(duration) ? duration(d) : duration, + duration: typeof duration === "function" ? duration(d) : duration, easing, css: (t, u) => ` opacity: ${t * opacity};