From 82d17c5a6fc959326dcfe22e24b45634f5255c60 Mon Sep 17 00:00:00 2001 From: pushkine Date: Fri, 15 May 2020 06:23:18 +0200 Subject: [PATCH] 15/05 --- .gitignore | 2 +- src/compiler/compile/index.ts | 2 +- .../compile/render_dom/wrappers/EachBlock.ts | 30 ++-- .../render_dom/wrappers/Element/Attribute.ts | 2 +- .../render_dom/wrappers/Element/index.ts | 32 ++-- .../compile/render_dom/wrappers/Slot.ts | 54 +++---- .../handlers/shared/get_attribute_value.ts | 2 +- src/compiler/compile/utils/get_slot_data.ts | 2 +- src/runtime/animate/index.ts | 2 +- src/runtime/easing/index.ts | 6 +- src/runtime/environment/index.ts | 4 +- src/runtime/internal/animations.ts | 58 +++---- src/runtime/internal/dev.tools.ts | 1 - src/runtime/internal/loop.ts | 26 ++-- src/runtime/internal/scheduler.ts | 7 +- src/runtime/internal/stores.ts | 42 ++--- src/runtime/internal/style_manager.ts | 92 ++++++----- src/runtime/internal/transitions.ts | 129 +++++++++------- src/runtime/motion/index.ts | 4 +- src/runtime/transition/index.ts | 6 +- test/runtime/ambient.ts | 4 + test/runtime/index.js | 145 +++++++++--------- 22 files changed, 327 insertions(+), 325 deletions(-) create mode 100644 test/runtime/ambient.ts diff --git a/.gitignore b/.gitignore index 63d00d18aa..69cfed1477 100644 --- a/.gitignore +++ b/.gitignore @@ -10,7 +10,7 @@ node_modules /animate /dev /easing -/environment +/environment/ /internal /interpolate /motion diff --git a/src/compiler/compile/index.ts b/src/compiler/compile/index.ts index 8f73475549..3374626189 100644 --- a/src/compiler/compile/index.ts +++ b/src/compiler/compile/index.ts @@ -68,7 +68,7 @@ function validate_options(options: CompileOptions, warnings: Warning[]) { } export default function compile(source: string, options: CompileOptions = {}) { - options = { generate: 'dom', dev: null, ...options }; + options = { generate: 'dom', dev: null, version: 3, ...options }; const stats = new Stats(); const warnings = []; diff --git a/src/compiler/compile/render_dom/wrappers/EachBlock.ts b/src/compiler/compile/render_dom/wrappers/EachBlock.ts index a365148181..5b648f8ec0 100644 --- a/src/compiler/compile/render_dom/wrappers/EachBlock.ts +++ b/src/compiler/compile/render_dom/wrappers/EachBlock.ts @@ -436,27 +436,29 @@ export default class EachBlockWrapper extends Wrapper { // We declare `i` as block scoped here, as the `remove_old_blocks` code // may rely on continuing where this iteration stopped. this.updates.push(b` - ${!has_update_method && b`const #old_length = ${each_block_value}.length;`} + ${!has_update_method && b`const #old_length = ${each_block}.length;`} ${each_block_value} = ${snippet}; ${__DEV__ && b`@validate_each_argument(${each_block_value});`} - let #i; - ${for_each_block( - (block, index) => b` + let #i = ${start}, #block; + ${for_loop( + each_block_value, + (_, index) => b` + #block = ${each_block}[${index}] const #child_ctx = ${each_context_getter}(#ctx, ${each_block_value}, ${index}); ${$if({ - if: (has_update_method || has_transitions) && block, + if: (has_update_method || has_transitions) && x`#block`, true: b` - ${has_update_method && b`${block}.p(#child_ctx, #dirty);`} - ${has_transitions && b`@transition_in(${block}, 1);`} + ${has_update_method && b`#block.p(#child_ctx, #dirty);`} + ${has_transitions && b`@transition_in(#block, 1);`} `, false: b` - ${block} = ${create_each_block}(#child_ctx); - ${block}.c(); - ${has_transitions && b`@transition_in(${block}, 1);`} - ${block}.m(${update_mount_node}, ${update_anchor_node}); + #block = ${each_block}[${index}] = ${create_each_block}(#child_ctx); + #block.c(); + ${has_transitions && b`@transition_in(#block, 1);`} + #block.m(${update_mount_node}, ${update_anchor_node}); `, })}`, - { i: start } + { i: null } )} ${this.block.group_transition_out((transition_out) => for_each_block( @@ -488,7 +490,7 @@ const for_loop = ( callback: (item: Node, index: Node, array: T) => Node[], { length = x`${arr}.length`, i = undefined } = {} ) => - i || i === null + i !== undefined ? b`for (${i}; #i < ${length}; #i++) { ${callback(x`${arr}[#i]`, x`#i`, arr)} }` : b`for (let #i = 0; #i < ${length}; #i++) { ${callback(x`${arr}[#i]`, x`#i`, arr)} }`; @@ -504,7 +506,7 @@ const $if = ({ if: condition, true: success, false: failure = null }) => { return b`if(!${condition}){ ${success} }`; } } else { - if (!failure) { + if (failure) { return failure; } } diff --git a/src/compiler/compile/render_dom/wrappers/Element/Attribute.ts b/src/compiler/compile/render_dom/wrappers/Element/Attribute.ts index f0cac1e63b..1ed9692c99 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/Attribute.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/Attribute.ts @@ -210,7 +210,7 @@ export default class AttributeWrapper { if (scoped_css && rendered.length === 2) { // we have a situation like class={possiblyUndefined} - rendered[0] = x`${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/index.ts b/src/compiler/compile/render_dom/wrappers/Element/index.ts index aa24bc181a..c0db934948 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/index.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/index.ts @@ -360,7 +360,7 @@ export default class ElementWrapper extends Wrapper { } } if (this.node.animation) { - this.add_animation(block, intro, outro); + this.add_animation(block, intro); } this.add_classes(block); this.add_manual_style_scoping(block); @@ -677,8 +677,8 @@ export default class ElementWrapper extends Wrapper { const fn = this.renderer.reference(intro.name); - let intro_block = b`${name} = @run_bidirectional_transition(${this.var}, ${fn}, true, ${snippet});`; - let outro_block = b`${name} = @run_bidirectional_transition(${this.var}, ${fn}, false, ${snippet});`; + let intro_block = b`${name} = @run_bidirectional_transition(${this.var}, ${fn}, 1, ${snippet});`; + let outro_block = b`${name} = @run_bidirectional_transition(${this.var}, ${fn}, 2, ${snippet});`; if (intro.is_local) { intro_block = b`if (#local) {${intro_block}}`; @@ -687,16 +687,12 @@ export default class ElementWrapper extends Wrapper { block.chunks.intro.push(intro_block); block.chunks.outro.push(outro_block); - block.chunks.destroy.push(b`if (detaching && ${name}) ${name}();`); + block.chunks.destroy.push(b`if (detaching) ${name}();`); } add_intro(block: Block, intro: Transition, outro: Transition) { if (outro) { const outro_var = block.alias(`${this.var.name}_outro`); - block.chunks.intro.push(b` - if (${outro_var}){ - ${outro_var}(1); - } - `); + block.chunks.intro.push(b`${outro_var}();`); } if (this.node.animation) { const [unfreeze_var, rect_var, stop_animation_var, animationFn, params] = run_animation(this, block); @@ -711,9 +707,9 @@ export default class ElementWrapper extends Wrapper { if (!intro) return; const [intro_var, node, transitionFn, params] = run_transition(this, block, intro, `intro`); - block.add_variable(intro_var); + block.add_variable(intro_var, x`@noop`); - let start_intro = b`${intro_var} = @run_transition(${node}, ${transitionFn}, true, ${params});`; + let start_intro = b`${intro_var} = @run_transition(${node}, ${transitionFn}, 1, ${params});`; if (intro.is_local) start_intro = b`if (#local) ${start_intro};`; block.chunks.intro.push(start_intro); } @@ -723,21 +719,21 @@ export default class ElementWrapper extends Wrapper { add_outro(block: Block, intro: Transition, outro: Transition) { if (intro) { const intro_var = block.alias(`${this.var.name}_intro`); - block.chunks.outro.push(b`if (${intro_var}) ${intro_var}();`); + block.chunks.outro.push(b`${intro_var}();`); } if (!outro) return; const [outro_var, node, transitionFn, params] = run_transition(this, block, outro, `outro`); - block.add_variable(outro_var); + block.add_variable(outro_var, x`@noop`); - let start_outro = b`${outro_var} = @run_transition(${node}, ${transitionFn}, false, ${params});`; + let start_outro = b`${outro_var} = @run_transition(${node}, ${transitionFn}, 2, ${params});`; if (intro.is_local) start_outro = b`if (#local) ${start_outro};`; block.chunks.outro.push(start_outro); - block.chunks.destroy.push(b`if (detaching && ${outro_var}) ${outro_var}();`); + block.chunks.destroy.push(b`if (detaching) ${outro_var}();`); } - add_animation(block: Block, intro: Transition, outro: Transition) { + add_animation(block: Block, intro: Transition) { const intro_var = intro && block.alias(`${this.var.name}_intro`); const [unfreeze_var, rect_var, stop_animation_var, name_var, params_var] = run_animation(this, block); @@ -747,8 +743,8 @@ export default class ElementWrapper extends Wrapper { block.add_variable(stop_animation_var, x`@noop`); block.chunks.measure.push(b` - if(!${unfreeze_var}) ${rect_var} = ${this.var}.getBoundingClientRect(); - ${intro && b`if(${intro_var}) ${intro_var}();`} + ${rect_var} = ${this.var}.getBoundingClientRect(); + ${intro && b`${intro_var}();`} `); block.chunks.fix.push(b` diff --git a/src/compiler/compile/render_dom/wrappers/Slot.ts b/src/compiler/compile/render_dom/wrappers/Slot.ts index 492136303a..16e2873f15 100644 --- a/src/compiler/compile/render_dom/wrappers/Slot.ts +++ b/src/compiler/compile/render_dom/wrappers/Slot.ts @@ -36,21 +36,14 @@ export default class SlotWrapper extends Wrapper { this.fallback = block.child({ comment: create_debugging_comment(this.node.children[0], this.renderer.component), name: this.renderer.component.get_unique_name(`fallback_block`), - type: 'fallback' + type: 'fallback', }); renderer.blocks.push(this.fallback); } - this.fragment = new FragmentWrapper( - renderer, - this.fallback, - node.children, - this, - strip_whitespace, - next_sibling - ); + this.fragment = new FragmentWrapper(renderer, this.fallback, node.children, this, strip_whitespace, next_sibling); - this.node.values.forEach(attribute => { + this.node.values.forEach((attribute) => { add_to_set(this.dependencies, attribute.dependencies); }); @@ -61,11 +54,7 @@ export default class SlotWrapper extends Wrapper { block.add_outro(); } - render( - block: Block, - parent_node: Identifier, - parent_nodes: Identifier - ) { + render(block: Block, parent_node: Identifier, parent_nodes: Identifier) { const { renderer } = this; const { slot_name } = this.node; @@ -81,20 +70,20 @@ export default class SlotWrapper extends Wrapper { const dependencies = new Set(); - this.node.values.forEach(attribute => { - attribute.chunks.forEach(chunk => { + this.node.values.forEach((attribute) => { + attribute.chunks.forEach((chunk) => { if ((chunk as Expression).dependencies) { add_to_set(dependencies, (chunk as Expression).contextual_dependencies); // add_to_set(dependencies, (chunk as Expression).dependencies); - (chunk as Expression).dependencies.forEach(name => { + (chunk as Expression).dependencies.forEach((name) => { const variable = renderer.component.var_lookup.get(name); if (variable && !variable.hoistable) dependencies.add(name); }); } }); - const dynamic_dependencies = Array.from(attribute.dependencies).filter(name => { + const dynamic_dependencies = Array.from(attribute.dependencies).filter((name) => { if (this.node.scope.is_let(name)) return true; const variable = renderer.component.var_lookup.get(name); return is_dynamic(variable); @@ -133,14 +122,10 @@ export default class SlotWrapper extends Wrapper { ${has_fallback ? b`const ${slot_or_fallback} = ${slot} || ${this.fallback.name}(#ctx);` : null} `); - block.chunks.create.push( - b`if (${slot_or_fallback}) ${slot_or_fallback}.c();` - ); + block.chunks.create.push(b`if (${slot_or_fallback}) ${slot_or_fallback}.c();`); if (renderer.options.hydratable) { - block.chunks.claim.push( - b`if (${slot_or_fallback}) ${slot_or_fallback}.l(${parent_nodes});` - ); + block.chunks.claim.push(b`if (${slot_or_fallback}) ${slot_or_fallback}.l(${parent_nodes});`); } block.chunks.mount.push(b` @@ -149,15 +134,11 @@ export default class SlotWrapper extends Wrapper { } `); - block.chunks.intro.push( - b`@transition_in(${slot_or_fallback}, #local);` - ); + block.chunks.intro.push(b`@transition_in(${slot_or_fallback}, #local);`); - block.chunks.outro.push( - b`@transition_out(${slot_or_fallback}, #local);` - ); + block.chunks.outro.push(b`@transition_out(${slot_or_fallback}, #local);`); - const is_dependency_dynamic = name => { + const is_dependency_dynamic = (name) => { if (name === '$$scope') return true; if (this.node.scope.is_let(name)) return true; const variable = renderer.component.var_lookup.get(name); @@ -178,7 +159,10 @@ export default class SlotWrapper extends Wrapper { ); } `; - const fallback_update = has_fallback && fallback_dynamic_dependencies.length > 0 && b` + const fallback_update = + has_fallback && + fallback_dynamic_dependencies.length > 0 && + b` if (${slot_or_fallback} && ${slot_or_fallback}.p && ${renderer.dirty(fallback_dynamic_dependencies)}) { ${slot_or_fallback}.p(#ctx, #dirty); } @@ -200,8 +184,6 @@ export default class SlotWrapper extends Wrapper { `); } - block.chunks.destroy.push( - b`if (${slot_or_fallback}) ${slot_or_fallback}.d(detaching);` - ); + block.chunks.destroy.push(b`if (${slot_or_fallback}) ${slot_or_fallback}.d(detaching);`); } } 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 bb011de5a3..792463ccf4 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(${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/utils/get_slot_data.ts b/src/compiler/compile/utils/get_slot_data.ts index 07795c08ae..d56b9179b3 100644 --- a/src/compiler/compile/utils/get_slot_data.ts +++ b/src/compiler/compile/utils/get_slot_data.ts @@ -5,7 +5,7 @@ import Block from '../render_dom/Block'; export default function get_slot_data(values: Map, block: Block = null) { return { - type: 'Expression', + type: 'ObjectExpression', properties: Array.from(values.values()) .filter((attribute) => attribute.name !== 'name') .map((attribute) => { diff --git a/src/runtime/animate/index.ts b/src/runtime/animate/index.ts index 73f2c4ea8e..d25117b02c 100644 --- a/src/runtime/animate/index.ts +++ b/src/runtime/animate/index.ts @@ -10,7 +10,7 @@ interface FlipParams { export function flip( node: Element, animation: { from: DOMRect; to: DOMRect }, - { delay = 0, duration = (d: number) => Math.sqrt(d) * 120, easing = cubicOut }: FlipParams + { delay = 0, duration = (d: number) => Math.sqrt(d) * 30, easing = cubicOut }: FlipParams ): AnimationConfig { const style = getComputedStyle(node).transform; const transform = style === 'none' ? '' : style; diff --git a/src/runtime/easing/index.ts b/src/runtime/easing/index.ts index 1e94aff747..6f20064b84 100644 --- a/src/runtime/easing/index.ts +++ b/src/runtime/easing/index.ts @@ -55,13 +55,13 @@ export const cubicBezier = (x1: number, y1: number, x2: number, y2: number) => { ); const ax = 1.0 - (x2 = 3.0 * (x2 - x1) - (x1 = 3.0 * x1)) - x1, ay = 1.0 - (y2 = 3.0 * (y2 - y1) - (y1 = 3.0 * y1)) - y1; - let r = 0.0, + let i = 0, + r = 0.0, s = 0.0, d = 0.0, x = 0.0; return (t: number) => { - r = t; - for (let i = 0; 32 > i; i++) + for (r = t, i = 0; 32 > i; i++) if (1e-5 > Math.abs((x = r * r * (r * ax + x1 + x2) - t))) return r * (r * (r * ay + y2) + y1); else if (1e-5 > Math.abs((d = r * (r * ax * 3.0 + x2 * 2.0) + x1))) break; else r = r - x / d; diff --git a/src/runtime/environment/index.ts b/src/runtime/environment/index.ts index 36183cf463..747a496de3 100644 --- a/src/runtime/environment/index.ts +++ b/src/runtime/environment/index.ts @@ -12,11 +12,13 @@ export const is_cors = } })(); export const has_Symbol = typeof Symbol === 'function'; + +declare var global: any; export const globals = is_browser ? window : typeof globalThis !== 'undefined' ? globalThis : global; export const resolved_promise = Promise.resolve(); export let now = /*#__PURE__*/ is_browser ? performance.now.bind(performance) : Date.now.bind(Date); -export let raf = /*#__PURE__*/ is_browser ? requestAnimationFrame : noop; +export let raf = /*#__PURE__*/ __TEST__ ? () => {} : is_browser ? requestAnimationFrame : noop; export let framerate = 1000 / 60; raf((t1) => { raf((d) => { diff --git a/src/runtime/internal/animations.ts b/src/runtime/internal/animations.ts index 1870ef2ddf..adc4cc0443 100644 --- a/src/runtime/internal/animations.ts +++ b/src/runtime/internal/animations.ts @@ -11,38 +11,42 @@ export interface AnimationConfig { type AnimationFn = (node: Element, { from, to }: { from: DOMRect; to: DOMRect }, params: any) => AnimationConfig; -export function run_animation(node: HTMLElement, from: DOMRect, fn: AnimationFn, params) { +export const run_animation = Function.prototype.call.bind(function run_animation( + this: HTMLElement, + from: DOMRect, + fn: AnimationFn, + params = {} +) { if (!from) return noop; return run_transition( - node, - (node, params) => fn(node, { from, to: node.getBoundingClientRect() }, params), - true, + this, + (_, params) => { + const to = this.getBoundingClientRect(); + if (from.left !== to.left || from.right !== to.right || from.top !== to.top || from.bottom !== to.bottom) { + return fn(this, { from, to }, params); + } else return null; + }, + 9, params ); -} +}); -export function fix_position(node: HTMLElement, { left, top }: DOMRect) { - const { position, width, height, transform } = getComputedStyle(node); +export const fix_position = Function.prototype.call.bind(function fix_position( + this: HTMLElement, + { left, top }: DOMRect +) { + const { position, width, height, transform } = getComputedStyle(this); if (position === 'absolute' || position === 'fixed') return noop; - const { position: og_position, width: og_width, height: og_height } = node.style; - node.style.position = 'absolute'; - node.style.width = width; - node.style.height = height; - const b = node.getBoundingClientRect(); - node.style.transform = `${transform === 'none' ? '' : transform} translate(${left - b.left}px, ${top - b.top}px)`; + const { position: og_position, width: og_width, height: og_height } = this.style; + this.style.position = 'absolute'; + this.style.width = width; + this.style.height = height; + const b = this.getBoundingClientRect(); + this.style.transform = `${transform === 'none' ? '' : transform} translate(${left - b.left}px, ${top - b.top}px)`; return () => { - node.style.position = og_position; - node.style.width = og_width; - node.style.height = og_height; - node.style.transform = ''; // unsafe + this.style.position = og_position; + this.style.width = og_width; + this.style.height = og_height; + this.style.transform = ''; // unsafe }; -} - -export function add_transform(node: HTMLElement, a: DOMRect) { - const b = node.getBoundingClientRect(); - if (a.left !== b.left || a.top !== b.top) { - const style = getComputedStyle(node); - const transform = style.transform === 'none' ? '' : style.transform; - node.style.transform = `${transform} translate(${a.left - b.left}px, ${a.top - b.top}px)`; - } -} +}); diff --git a/src/runtime/internal/dev.tools.ts b/src/runtime/internal/dev.tools.ts index 22348b157c..58d6da9e49 100644 --- a/src/runtime/internal/dev.tools.ts +++ b/src/runtime/internal/dev.tools.ts @@ -124,7 +124,6 @@ export function dev$element(element: Element | Node | EventTarget, event: keyof } } export function dev$block(event: keyof BlockEventsMap, payload) {} -export function dev$tracing(type, value: any) {} export function dev$assert(truthy: any, else_throw: string) { if (__DEV__ && !truthy) { throw new Error(else_throw); diff --git a/src/runtime/internal/loop.ts b/src/runtime/internal/loop.ts index 2d845b208a..981e8dd367 100644 --- a/src/runtime/internal/loop.ts +++ b/src/runtime/internal/loop.ts @@ -3,19 +3,23 @@ import { noop } from './utils'; type TaskCallback = (t: number) => boolean; type TaskCanceller = () => void; +/** manual upkeeping of next_frame.length */ +let n = 0; +let i = 0, + j = 0; +let v; let next_frame: Array = []; let running_frame: Array = []; -let next_frame_length = 0; const run = (t: number) => { - t = now(); [running_frame, next_frame] = [next_frame, running_frame]; - for (let i = (next_frame_length = 0), j = running_frame.length, v; i < j; i++) { + for (t = now(), i = n = 0, j = running_frame.length; i < j; i++) { if ((v = running_frame[i])(t)) { - next_frame[next_frame_length++] = v; + next_frame[n++] = v; } } - running_frame.length = 0; - if (next_frame_length) raf(run); + if ((running_frame.length = 0) < n) { + raf(run); + } }; type TimeoutTask = { timestamp: number; callback: (now: number) => void }; @@ -42,13 +46,13 @@ const run_timed = (now: number) => { return (running_timed = !!(timed_tasks.length = last_index + 1)); }; const unsafe_loop = (fn) => { - if (!next_frame_length) raf(run); - next_frame[next_frame_length++] = fn; + if (0 === n) raf(run); + next_frame[n++] = fn; }; export const loop = (fn) => { let running = true; - if (!next_frame_length) raf(run); - next_frame[next_frame_length++] = (t) => !running || fn(t); + if (0 === n) raf(run); + next_frame[n++] = (t) => !running || fn(t); return () => void (running = false); }; export const setFrameTimeout = (callback: () => void, timestamp: number): TaskCanceller => { @@ -103,4 +107,4 @@ export const onEachFrame = ( /** tests only */ export const clear_loops = () => - void (next_frame.length = running_frame.length = timed_tasks.length = pending_insert_timed.length = next_frame_length = +(running_timed = pending_inserts = false)); + void (next_frame.length = running_frame.length = timed_tasks.length = pending_insert_timed.length = n = +(running_timed = pending_inserts = false)); diff --git a/src/runtime/internal/scheduler.ts b/src/runtime/internal/scheduler.ts index b2fa55da08..5be0e527b7 100644 --- a/src/runtime/internal/scheduler.ts +++ b/src/runtime/internal/scheduler.ts @@ -1,5 +1,5 @@ import { set_current_component } from './lifecycle'; -import { resolved_promise } from 'svelte/environment'; +import { resolved_promise, now } from 'svelte/environment'; import { T$$ } from './Component'; let update_scheduled = false; @@ -43,6 +43,7 @@ export const flush = () => { let i = 0, j = 0, + t = 0, $$: T$$, dirty, before_update, @@ -74,7 +75,7 @@ export const flush = () => { } dirty_components.length = 0; - // update bindings [ in reverse order (#3145); is there a better way ? ] + // update bindings [ ...in reverse order (#3145) ] i = binding_callbacks.length; while (i--) binding_callbacks[i](); binding_callbacks.length = i = 0; @@ -95,7 +96,7 @@ export const flush = () => { // apply styles // todo : remove every non style callback from flush_callbacks - for (; i < j; i++) flush_callbacks[i](); + for (t = now(); i < j; i++) flush_callbacks[i](t); flush_callbacks.length = i = j = 0; is_flushing = false; diff --git a/src/runtime/internal/stores.ts b/src/runtime/internal/stores.ts index 4bb41dc5c5..db5e05e6c9 100644 --- a/src/runtime/internal/stores.ts +++ b/src/runtime/internal/stores.ts @@ -8,7 +8,7 @@ type Unsubscriber = () => void; interface Observable { subscribe(callback: Subscriber): Unsubscriber; } -type Observable_s = Observable[] | Observable; +type Obs = Observable[] | Observable; type Deriver = (values: any, setter?: Setter) => void | (() => void) | T; /** @@ -26,7 +26,8 @@ export class Store { for (let i = 0, j = 0, subscribers, value; i < this.update_queue.length; i++) for (j = 0, subscribers = this.update_queue[i], value = this.value_queue[i]; j < subscribers.length; j++) subscribers[j].run(value); - this.update_queue.length = this.value_queue.length = +(this.is_flushing = false); + this.update_queue.length = this.value_queue.length = 0; + this.is_flushing = false; } value: T; has_subscribers = false; @@ -97,7 +98,7 @@ export class Writable extends StartStopWritable { if (safe_not_equal(this.value, next_value)) super.set(next_value); } } -export class Derived, T> extends StartStopWritable { +export class Derived, T> extends StartStopWritable { cleanup = noop; target; deriver; @@ -129,9 +130,9 @@ export class Derived, T> extends St this.set = // deriver defines < 2 arguments ? deriver.length < 2 - ? // return value is store value + ? // deriver returned value is store value (v) => void super.set(deriver(v) as T) - : // return value is cleanup | void, store value is set manually + : // deriver returned value is cleanup | void, store value is set manually within deriver (v) => void (this.cleanup(), typeof (this.cleanup = deriver(v, super.set.bind(this)) as () => void) !== 'function' && @@ -144,11 +145,12 @@ export type createMotionTick = (prev_value: T, next_value: T) => SpringTick = (prev_value: T, next_value: T) => TweenTick; export type SpringTick = (current_value: T, elapsed: number, dt: number) => boolean; export type TweenTick = (t: number) => boolean; -/** applies motion fn to every leaf of any object */ -function parseStructure( + +/** applies motion function initializer to every leaf of any shape of array-like or object literal like value */ +const parseStructure = ( obj: unknown, schema: initCreateMotionTick | initCreateTweenTick -): initCreateMotionTick | initCreateTweenTick { +): initCreateMotionTick | initCreateTweenTick => { const isArray = Array.isArray(obj); if (typeof obj === 'object' && obj !== null && (isArray || Object.prototype === Object.getPrototypeOf(obj))) { const keys = Object.keys(obj); @@ -160,10 +162,10 @@ function parseStructure( pending = 0; const target = { ...obj }; obj = isArray ? [...(obj as T[])] : { ...obj }; - return (set) => (_from_value, to_value) => { + return (set) => (_, to_value) => { for (k in to_value) if (to_value[k] !== obj[k]) target[k] = to_value[k]; for (i = 0; i < l; i++) (pending |= 1 << i), (tickers[i] = createTickers[i](obj[keys[i]], target[keys[i]])); - return (_current, elapsed, dt) => { + return (_, elapsed, dt) => { for (i = 0; i < l; i++) if (pending & (1 << i) && !tickers[i](obj[keys[i]], elapsed, dt)) pending &= ~(1 << i); set(isArray ? [...(obj as T[])] : { ...(obj as any) }); return !!pending; @@ -171,16 +173,16 @@ function parseStructure( }; } return schema; -} +}; abstract class MotionStore extends Store { running = false; cancel = noop; - initCreateTicker; - createTicker; + init; + create; tick; constructor(value: T, startSetTick: initCreateMotionTick | initCreateTweenTick) { super(value); - this.createTicker = parseStructure(value, (this.initCreateTicker = startSetTick))(super.set.bind(this)); + this.create = parseStructure(value, (this.init = startSetTick))(super.set.bind(this)); } set(next_value: T) { const this_id = ++this.uidRunning; @@ -188,7 +190,7 @@ abstract class MotionStore extends Store { if (!this.value && (this.value as unknown) !== 0) { this.setImmediate(next_value); } else { - this.tick = this.createTicker(this.value, next_value); + this.tick = this.create(this.value, next_value); this.loop(() => this.clearStateSubscribers(true)); this.running = true; } @@ -202,7 +204,7 @@ abstract class MotionStore extends Store { } abstract loop(stop): void; setImmediate(value) { - this.createTicker = parseStructure(value, this.initCreateTicker)(super.set.bind(this)); + this.create = parseStructure(value, this.init)(super.set.bind(this)); super.set((this.value = value)); if (this.running) this.cancel(); this.running = false; @@ -233,8 +235,8 @@ abstract class MotionStore extends Store { } } export class SpringMotion extends MotionStore { - initCreateTicker: initCreateMotionTick; - createTicker: createMotionTick; + init: initCreateMotionTick; + create: createMotionTick; tick: SpringTick; elapsed = 0.0; loop(stop) { @@ -243,8 +245,8 @@ export class SpringMotion extends MotionStore { } } export class TweenMotion extends MotionStore { - initCreateTicker: initCreateTweenTick; - createTicker: createTweenTick; + init: initCreateTweenTick; + create: createTweenTick; tick: TweenTick; loop(stop) { if (this.running) this.cancel(); diff --git a/src/runtime/internal/style_manager.ts b/src/runtime/internal/style_manager.ts index 3f7afcf877..14affaa408 100644 --- a/src/runtime/internal/style_manager.ts +++ b/src/runtime/internal/style_manager.ts @@ -1,67 +1,63 @@ -import { element } from './dom'; import { framerate } from 'svelte/environment'; -enum SVELTE { - RULE = `__svelte_`, - STYLESHEET = `__svelte_stylesheet`, - RULESET = `__svelte_rules`, -} -interface ExtendedDoc extends Document { - [SVELTE.STYLESHEET]: CSSStyleSheet; - [SVELTE.RULESET]: Set; -} -const active_documents = new Set(); +let documents_uid = 0; let running_animations = 0; -function add_rule(node): [CSSStyleSheet, Set] { - const { ownerDocument } = node; - if (!active_documents.has(ownerDocument)) { - active_documents.add(ownerDocument); - if (!(SVELTE.STYLESHEET in ownerDocument)) - ownerDocument[SVELTE.STYLESHEET] = ownerDocument.head.appendChild(element('style')).sheet; - if (!(SVELTE.RULESET in ownerDocument)) ownerDocument[SVELTE.RULESET] = new Set(); - } - return [ownerDocument[SVELTE.STYLESHEET], ownerDocument[SVELTE.RULESET]]; -} +const document_uid = new Map(); +const document_stylesheets = new Map(); -function hash(str: string) { - // darkskyapp/string-hash - let hash = 5381; - let i = str.length; - while (i--) hash = ((hash << 5) - hash) ^ str.charCodeAt(i); - return hash >>> 0; -} -const gen = (step, css) => { +const current_rules = new Set(); +export const animate_css = Function.prototype.call.bind(function animate_css( + this: HTMLElement, + css: (t: number) => string, + duration: number, + delay = 0 +) { + if (!document_uid.has(this.ownerDocument)) { + document_uid.set(this.ownerDocument, documents_uid++); + document_stylesheets.set( + this.ownerDocument, + this.ownerDocument.head.appendChild(this.ownerDocument.createElement('style')).sheet + ); + } let rule = '{\n'; - for (let t = 0; t < 1; t += step) rule += `${100 * t}%{${css(t)}}\n`; + for (let t = 0, step = framerate / duration; t < 1; t += step) rule += `${100 * t}%{${css(t)}}\n`; rule += `100% {${css(1)}}\n}`; - const name = SVELTE.RULE + hash(rule); - return [name, `@keyframes ${name} ${rule}`]; -}; -function animate(this: HTMLElement, css: (t: number) => string, duration: number, delay = 0) { - const [name, rule] = gen(Math.max(1 / 1000, framerate / duration), css); - const [stylesheet, rules] = add_rule(this); - if (!rules.has(name)) { - rules.add(name); - stylesheet.insertRule(rule, stylesheet.cssRules.length); + + // darkskyapp/string-hash + let i = rule.length, + hash = 5381; + while (i--) hash = ((hash << 5) - hash) ^ rule.charCodeAt(i); + const name = '_' + (hash >>> 0) + document_uid.get(this.ownerDocument); + + if (!current_rules.has(name)) { + current_rules.add(name); + const stylesheet = document_stylesheets.get(this.ownerDocument); + stylesheet.insertRule(`@keyframes ${name} ${rule}`, stylesheet.cssRules.length); } + const previous = this.style.animation; this.style.animation = `${ previous ? `${previous}, ` : '' } ${duration}ms linear ${delay}ms 1 normal both running ${name}`; running_animations++; + return () => { const prev = (this.style.animation || '').split(', '); const next = prev.filter((anim) => !anim.includes(name)); if (prev.length !== next.length) this.style.animation = next.join(', '); - if (--running_animations) return; - active_documents.forEach(({ [SVELTE.STYLESHEET]: stylesheet, [SVELTE.RULESET]: ruleset }) => { - let i = stylesheet.cssRules.length; - while (i--) stylesheet.deleteRule(i); - ruleset.clear(); - }); - active_documents.clear(); + if (--running_animations === 0) { + document_stylesheets.forEach((stylesheet) => { + let i = stylesheet.cssRules.length; + while (i--) stylesheet.deleteRule(i); + }); + current_rules.clear(); + if (1 !== documents_uid) { + document_stylesheets.clear(); + document_uid.clear(); + documents_uid = 0; + } + } }; -} -export const animate_css = Function.prototype.call.bind(animate); +}); diff --git a/src/runtime/internal/transitions.ts b/src/runtime/internal/transitions.ts index d2c192bd1a..64104ecf70 100644 --- a/src/runtime/internal/transitions.ts +++ b/src/runtime/internal/transitions.ts @@ -5,9 +5,10 @@ import { now } from 'svelte/environment'; import { setFrameTimeout, setTweenTimeout } from './loop'; import { add_measure_callback } from './scheduler'; import { animate_css } from './style_manager'; +import { noop } from './utils'; type TransitionFn = (node: HTMLElement, params: any) => TransitionConfig; -export type StopResetReverse = (reset_reverse?: 1 | -1) => StopResetReverse; +export type StopResetReverse = (t?: number | -1) => StopResetReverse | void; export const transition_in = (block: Fragment, local?) => { if (!block || !block.i) return; @@ -46,72 +47,78 @@ export const group_transition_out = (fn) => { check_transition_group(current_group, false); transition_group = transition_group.p; }; -// todo : deprecate -function startStopDispatcher(node: Element, is_intro: boolean) { - node.dispatchEvent(custom_event(`${is_intro ? 'intro' : 'outro'}start`)); - return () => node.dispatchEvent(custom_event(`${is_intro ? 'intro' : 'outro'}end`)); -} /* todo: deprecate */ -const swap = (fn, is_intro) => - fn.length === 1 ? (is_intro ? fn : (t) => fn(1 - t)) : is_intro ? (t) => fn(t, 1 - t) : (t) => fn(1 - t, t); +const swap = (fn, rx) => + fn.length === 1 ? (rx & tx.intro ? fn : (t) => fn(1 - t)) : rx & tx.intro ? (t) => fn(t, 1 - t) : (t) => fn(1 - t, t); -const mirrored = (fn, is_intro, easing) => { - const run = swap(fn, is_intro); - return easing ? (!is_intro ? (t) => run(1 - easing(1 - t)) : (t) => run(easing(t))) : run; +const mirrored = (fn, rx, easing) => { + const run = swap(fn, rx); + return easing ? (rx & tx.intro ? (t) => run(easing(t)) : (t) => run(1 - easing(1 - t))) : run; }; - -const reversed = (fn, is_intro, easing, start = 0, end = 1) => { - const run = swap(fn, is_intro); +const reversed = (fn, rx, easing, start = 0, end = 1) => { + const run = swap(fn, rx); const difference = end - start; return easing ? (t) => run(start + difference * easing(t)) : (t) => run(start + difference * t); }; - -export const run_transition = ( - node: HTMLElement, +export enum tx { + intro = 1, + outro = 2, + bidirectional = 4, + bidirectional_intro = 5, + bidirectional_outro = 6, + animation = 8, +} +export const run_transition = Function.prototype.call.bind(function transition( + this: HTMLElement, fn: TransitionFn, - is_intro = true, + rx: tx, params = {}, /* internal to this file */ - is_bidirectional = false, elapsed_duration = 0, delay_left = -1, elapsed_ratio = 0 -) => { +) { let config; let running = true; let cancel_css; let cancel_raf; - let dispatch_end; let start_time = 0; let end_time = 0; const current_group = transition_group; - if (!is_intro) transition_group.r++; + if (rx & tx.outro) current_group.r++; - const start = ({ delay = 0, duration = 300, easing, tick, css, strategy = 'reverse' }: TransitionConfig) => { - if (!running) return; + add_measure_callback(() => { + if (null === (config = fn(this, params))) return noop; + return (t) => { + if (false === running) return void (running = false); + if ('then' in config) return void config.then(stop); - if (~delay_left) delay = delay_left; + let { delay = 0, duration = 300, easing, tick, css, strategy = 'reverse' }: TransitionConfig = + 'function' === typeof config ? (config = config()) : config; - const solver = strategy === 'reverse' ? reversed : mirrored; - const runner = (fn) => solver(fn, is_intro, easing, elapsed_ratio, 1); + const solver = 'reverse' === strategy ? reversed : mirrored; + const runner = (fn) => solver(fn, rx, easing, elapsed_ratio, 1); - if (solver === reversed) { - duration -= elapsed_duration; - } else if (solver === mirrored) { - delay -= elapsed_duration; - } + if (rx & tx.bidirectional) { + if (-1 !== delay_left) delay = delay_left; + if (solver === reversed) duration -= elapsed_duration; + else if (solver === mirrored) delay -= elapsed_duration; + } - end_time = (start_time = now() + delay) + duration; + end_time = (start_time = t + delay) + duration; - dispatch_end = startStopDispatcher(node, is_intro); + if (0 === (rx & tx.animation)) { + this.dispatchEvent(custom_event(`${rx & tx.intro ? 'in' : 'ou'}trostart`)); + } - if (css) cancel_css = animate_css(node, runner(css), duration, delay); - cancel_raf = tick ? setTweenTimeout(stop, end_time, runner(tick), duration) : setFrameTimeout(stop, end_time); - }; + if (css) cancel_css = animate_css(this, runner(css), duration, delay); + cancel_raf = tick ? setTweenTimeout(stop, end_time, runner(tick), duration) : setFrameTimeout(stop, end_time); + }; + }); const stop: StopResetReverse = (t?: number | 1 | -1) => { if (!running) return; @@ -119,49 +126,53 @@ export const run_transition = ( if (cancel_css) cancel_css(); if (cancel_raf) cancel_raf(); - if (t > end_time) { - if (dispatch_end) { - dispatch_end(); + + if (0 === (rx & tx.animation)) { + if (t >= end_time) { + this.dispatchEvent(custom_event(`${rx & tx.intro ? 'in' : 'ou'}troend`)); + } + if (rx & tx.outro) { + check_transition_group(current_group); } } - if (!is_intro) check_transition_group(current_group); - - if (is_bidirectional) { + if (rx & tx.bidirectional) { if (-1 === t) { return ( (t = now()) < end_time && run_transition( - node, + this, () => config, - !is_intro, + rx ^ 1, params, - true, end_time - t, start_time > t ? start_time - t : 0, (1 - elapsed_ratio) * (1 - config.easing(1 - (end_time - t) / (end_time - start_time))) ) ); } else { - running_bidi.delete(node); + running_bidi.delete(this); } } }; - add_measure_callback(() => { - config = fn(node, params); - return () => start(typeof config === 'function' ? (config = config()) : config); - }); - return stop; -}; +}); const running_bidi: Map = new Map(); -export const run_bidirectional_transition = (node: HTMLElement, fn: TransitionFn, is_intro: boolean, params: any) => { +export const run_bidirectional_transition = Function.prototype.call.bind(function bidirectional( + this: HTMLElement, + fn: TransitionFn, + rx: tx.intro | tx.outro, + params: any +) { let cancel; - if (running_bidi.has(node) && (cancel = running_bidi.get(node)(-1))) running_bidi.set(node, cancel); - else running_bidi.set(node, (cancel = run_transition(node, fn, is_intro, params, true))); + running_bidi.set( + this, + (cancel = + (running_bidi.has(this) && running_bidi.get(this)(-1)) || run_transition(this, fn, rx | tx.bidirectional, params)) + ); return cancel; -}; -export const run_duration = (duration, ...args): number => - typeof duration === 'function' ? duration.apply(null, args) : duration; +}); +export const run_duration = (duration, value1, value2?): number => + typeof duration === 'function' ? duration(value1, value2) : duration; diff --git a/src/runtime/motion/index.ts b/src/runtime/motion/index.ts index bf42a8339c..57267c4a63 100644 --- a/src/runtime/motion/index.ts +++ b/src/runtime/motion/index.ts @@ -4,7 +4,7 @@ interface TweenParams { delay?: number; duration?: number | ((from: T, to: T) => number); easing?: (t: number) => number; - interpolate?: (a: T, b: T) => (t: number) => T; + interpolate?: (from: T, to: T) => (t: number) => T; } interface SpringParams { stiffness?: number /* { 10 < 100 < 200 } */; @@ -110,7 +110,7 @@ export function tween( }; return { set, - /* todo: test update() */ + /* todo: test update() with objects */ update: (fn, params) => set(fn(store.value, value), params), setImmediate: store.setImmediate.bind(store), subscribe: store.subscribe.bind(store), diff --git a/src/runtime/transition/index.ts b/src/runtime/transition/index.ts index f8dfcf2354..7986ae7918 100644 --- a/src/runtime/transition/index.ts +++ b/src/runtime/transition/index.ts @@ -141,11 +141,11 @@ export function crossfade({ const to_receive: ElementMap = new Map(); const to_send: ElementMap = new Map(); - function crossfade( + const crossfade = ( from_node: Element, to_node: Element, { delay = default_delay, easing = default_easing, duration = default_duration }: TimeableConfig - ) { + ) => { const from = from_node.getBoundingClientRect(); const to = to_node.getBoundingClientRect(); const dx = from.left - to.left; @@ -165,7 +165,7 @@ export function crossfade({ transform: ${prev} translate(${u * dx}px,${u * dy}px) scale(${t + (1 - t) * dw}, ${t + (1 - t) * dh}); `, } as TransitionConfig; - } + }; const transition = (a: ElementMap, b: ElementMap, is_intro: boolean) => ( node: Element, params: MarkedCrossFadeConfig diff --git a/test/runtime/ambient.ts b/test/runtime/ambient.ts new file mode 100644 index 0000000000..e674471c6b --- /dev/null +++ b/test/runtime/ambient.ts @@ -0,0 +1,4 @@ +import * as assert from 'assert'; +type TestSetup = { + test: ({ assert: module.assert, component, mod, target, window, raf, compileOptions }) => void | Promise; +}; \ No newline at end of file diff --git a/test/runtime/index.js b/test/runtime/index.js index f070eb8185..f417971f32 100644 --- a/test/runtime/index.js +++ b/test/runtime/index.js @@ -1,20 +1,12 @@ -import * as assert from "assert"; -import * as path from "path"; -import * as fs from "fs"; +import * as assert from 'assert'; +import * as path from 'path'; +import * as fs from 'fs'; import { rollup } from 'rollup'; import * as virtual from '@rollup/plugin-virtual'; import * as glob from 'tiny-glob/sync.js'; -import { clear_loops, flush, set_now, set_raf } from "../../internal"; - -import { - showOutput, - loadConfig, - loadSvelte, - cleanRequireCache, - env, - setupHtmlEqual, - mkdirp -} from "../helpers.js"; +import { clear_loops, flush, set_now, set_raf } from '../../internal'; + +import { showOutput, loadConfig, loadSvelte, cleanRequireCache, env, setupHtmlEqual, mkdirp } from '../helpers.js'; let svelte$; let svelte; @@ -25,21 +17,26 @@ let compile = null; const sveltePath = process.cwd().split('\\').join('/'); let unhandled_rejection = false; -process.on('unhandledRejection', err => { +process.on('unhandledRejection', (err) => { unhandled_rejection = err; }); -describe("runtime", () => { +describe('runtime', () => { before(() => { svelte = loadSvelte(false); svelte$ = loadSvelte(true); - require.extensions[".svelte"] = function(module, filename) { - const options = Object.assign({ - filename - }, compileOptions); + require.extensions['.svelte'] = function (module, filename) { + const options = Object.assign( + { + filename, + }, + compileOptions + ); - const { js: { code } } = compile(fs.readFileSync(filename, "utf-8"), options); + const { + js: { code }, + } = compile(fs.readFileSync(filename, 'utf-8'), options); return module._compile(code, filename); }; @@ -50,7 +47,7 @@ describe("runtime", () => { const failed = new Set(); function runTest(dir, hydrate) { - if (dir[0] === ".") return; + if (dir[0] === '.') return; const config = loadConfig(`${__dirname}/samples/${dir}/_config.js`); const solo = config.solo || /\.solo/.test(dir); @@ -58,7 +55,7 @@ describe("runtime", () => { if (hydrate && config.skip_if_hydrate) return; if (solo && process.env.CI) { - throw new Error("Forgot to remove `solo: true` from test"); + throw new Error('Forgot to remove `solo: true` from test'); } (config.skip ? it.skip : solo ? it.only : it)(`${dir} ${hydrate ? '(with hydration)' : ''}`, () => { @@ -89,10 +86,10 @@ describe("runtime", () => { const window = env(); - glob('**/*.svelte', { cwd }).forEach(file => { + glob('**/*.svelte', { cwd }).forEach((file) => { if (file[0] === '_') return; - const dir = `${cwd}/_output/${hydrate ? 'hydratable' : 'normal'}`; + const dir = `${cwd}/_output/${hydrate ? 'hydratable' : 'normal'}`; const out = `${dir}/${file.replace(/\.svelte$/, '.js')}`; if (fs.existsSync(out)) { @@ -102,13 +99,10 @@ describe("runtime", () => { mkdirp(dir); try { - const { js } = compile( - fs.readFileSync(`${cwd}/${file}`, 'utf-8'), - { - ...compileOptions, - filename: file - } - ); + const { js } = compile(fs.readFileSync(`${cwd}/${file}`, 'utf-8'), { + ...compileOptions, + filename: file, + }); fs.writeFileSync(out, js.code); } catch (err) { @@ -124,13 +118,13 @@ describe("runtime", () => { const raf = { time: 0, callback: null, - tick: now => { + tick: (now) => { raf.time = now; if (raf.callback) raf.callback(); - } + }, }; set_now(() => raf.time); - set_raf(cb => { + set_raf((cb) => { raf.callback = () => { raf.callback = null; cb(raf.time); @@ -151,20 +145,24 @@ describe("runtime", () => { // Put things we need on window for testing window.SvelteComponent = SvelteComponent; - const target = window.document.querySelector("main"); + const target = window.document.querySelector('main'); const warnings = []; const warn = console.warn; - console.warn = warning => { + console.warn = (warning) => { warnings.push(warning); }; - const options = Object.assign({}, { - target, - hydrate, - props: config.props, - intro: config.intro - }, config.options || {}); + const options = Object.assign( + {}, + { + target, + hydrate, + props: config.props, + intro: config.intro, + }, + config.options || {} + ); const component = new SvelteComponent(options); @@ -172,14 +170,14 @@ describe("runtime", () => { if (config.error) { unintendedError = true; - throw new Error("Expected a runtime error"); + throw new Error('Expected a runtime error'); } if (config.warnings) { assert.deepEqual(warnings, config.warnings); } else if (warnings.length) { unintendedError = true; - throw new Error("Received unexpected warnings"); + throw new Error('Received unexpected warnings'); } if (config.html) { @@ -187,15 +185,17 @@ describe("runtime", () => { } if (config.test) { - return Promise.resolve(config.test({ - assert, - component, - mod, - target, - window, - raf, - compileOptions - })).then(() => { + return Promise.resolve( + config.test({ + assert, + component, + mod, + target, + window, + raf, + compileOptions, + }) + ).then(() => { component.$destroy(); if (unhandled_rejection) { @@ -204,14 +204,14 @@ describe("runtime", () => { }); } else { component.$destroy(); - assert.htmlEqual(target.innerHTML, ""); + assert.htmlEqual(target.innerHTML, ''); if (unhandled_rejection) { throw unhandled_rejection; } } }) - .catch(err => { + .catch((err) => { if (config.error && !unintendedError) { if (typeof config.error === 'function') { config.error(assert, err); @@ -221,12 +221,13 @@ describe("runtime", () => { } else { throw err; } - }).catch(err => { + }) + .catch((err) => { failed.add(dir); showOutput(cwd, compileOptions, compile); // eslint-disable-line no-console throw err; }) - .catch(err => { + .catch((err) => { // print a clickable link to open the directory err.stack += `\n\ncmd-click: ${path.relative(process.cwd(), cwd)}/main.svelte`; throw err; @@ -243,23 +244,23 @@ describe("runtime", () => { }); } - fs.readdirSync(`${__dirname}/samples`).forEach(dir => { + fs.readdirSync(`${__dirname}/samples`).forEach((dir) => { runTest(dir, false); runTest(dir, true); }); async function create_component(src = '
') { const { js } = svelte$.compile(src, { - format: "esm", - name: "SvelteComponent", - dev: true + format: 'esm', + name: 'SvelteComponent', + dev: true, }); const bundle = await rollup({ input: 'main.js', plugins: [ virtual({ - 'main.js': js.code + 'main.js': js.code, }), { name: 'svelte-packages', @@ -267,22 +268,20 @@ describe("runtime", () => { if (importee.startsWith('svelte/')) { return importee.replace('svelte', process.cwd()) + '/index.mjs'; } - } - } - ] + }, + }, + ], }); const result = await bundle.generate({ format: 'iife', - name: 'App' + name: 'App', }); - return eval( - `(function () { ${result.output[0].code}; return App; }())` - ); + return eval(`(function () { ${result.output[0].code}; return App; }())`); } - it("fails if options.target is missing in dev mode", async () => { + it('fails if options.target is missing in dev mode', async () => { const App = await create_component(); assert.throws(() => { @@ -290,13 +289,13 @@ describe("runtime", () => { }, /'target' is a required option/); }); - it("fails if options.hydrate is true but the component is non-hydratable", async () => { + it('fails if options.hydrate is true but the component is non-hydratable', async () => { const App = await create_component(); assert.throws(() => { new App({ target: { childNodes: [] }, - hydrate: true + hydrate: true, }); }, /options.hydrate only works if the component was compiled with the `hydratable: true` option/); });