Merge branch 'master' into pr/6578

pull/6578/head
Conduitry 5 years ago
commit a18f745efb

@ -1,5 +1,17 @@
# Svelte changelog # Svelte changelog
## Unreleased
* Support `export { ... } from` syntax in components ([#2214](https://github.com/sveltejs/svelte/issues/2214))
## 3.40.3
* Fix `<slot>` data when a transition is cancelled before completing ([#5394](https://github.com/sveltejs/svelte/issues/5394))
* Fix destructuring into variables beginning with `$` so that they result in store updates ([#5653](https://github.com/sveltejs/svelte/issues/5653))
* Fix `in:` transition configuration not properly updating when it's changed after its initial creation ([#6505](https://github.com/sveltejs/svelte/issues/6505))
* Fix applying `:global()` for `>` selector combinator ([#6550](https://github.com/sveltejs/svelte/issues/6550))
* Fix mounting component at detached DOM node ([#6567](https://github.com/sveltejs/svelte/issues/6567))
## 3.40.2 ## 3.40.2
* Fix dynamic `autofocus={...}` attribute handling ([#4995](https://github.com/sveltejs/svelte/issues/4995)) * Fix dynamic `autofocus={...}` attribute handling ([#4995](https://github.com/sveltejs/svelte/issues/4995))

2
package-lock.json generated

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

@ -1,6 +1,6 @@
{ {
"name": "svelte", "name": "svelte",
"version": "3.40.2", "version": "3.40.3",
"description": "Cybernetically enhanced web apps", "description": "Cybernetically enhanced web apps",
"module": "index.mjs", "module": "index.mjs",
"main": "index", "main": "index",

@ -516,6 +516,7 @@ The following modifiers are available:
* `capture` — fires the handler during the *capture* phase instead of the *bubbling* phase * `capture` — fires the handler during the *capture* phase instead of the *bubbling* phase
* `once` — remove the handler after the first time it runs * `once` — remove the handler after the first time it runs
* `self` — only trigger handler if event.target is the element itself * `self` — only trigger handler if event.target is the element itself
* `trusted` — only trigger handler if `event.trusted` is `true`. I.e. if the event is triggered by a user action.
Modifiers can be chained together, e.g. `on:click|once|capture={...}`. Modifiers can be chained together, e.g. `on:click|once|capture={...}`.

@ -25,5 +25,6 @@ The full list of modifiers:
* `capture` — fires the handler during the *capture* phase instead of the *bubbling* phase ([MDN docs](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Events#Event_bubbling_and_capture)) * `capture` — fires the handler during the *capture* phase instead of the *bubbling* phase ([MDN docs](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Events#Event_bubbling_and_capture))
* `once` — remove the handler after the first time it runs * `once` — remove the handler after the first time it runs
* `self` — only trigger handler if event.target is the element itself * `self` — only trigger handler if event.target is the element itself
* `trusted` — only trigger handler if `event.trusted` is `true`. I.e. if the event is triggered by a user action.
You can chain modifiers together, e.g. `on:click|once|capture={...}`. You can chain modifiers together, e.g. `on:click|once|capture={...}`.

@ -18,4 +18,4 @@ Returning to our [earlier ice cream example](tutorial/group-inputs), we can repl
</select> </select>
``` ```
> Press and hold the `shift` key for selecting multiple options. > Press and hold the `control` key for selecting multiple options.

@ -24,7 +24,7 @@ import TemplateScope from './nodes/shared/TemplateScope';
import fuzzymatch from '../utils/fuzzymatch'; import fuzzymatch from '../utils/fuzzymatch';
import get_object from './utils/get_object'; import get_object from './utils/get_object';
import Slot from './nodes/Slot'; import Slot from './nodes/Slot';
import { Node, ImportDeclaration, Identifier, ExpressionStatement, AssignmentExpression, Literal, Property, RestElement } from 'estree'; import { Node, ImportDeclaration, ExportNamedDeclaration, Identifier, ExpressionStatement, AssignmentExpression, Literal, Property, RestElement, ExportDefaultDeclaration, ExportAllDeclaration } from 'estree';
import add_to_set from './utils/add_to_set'; import add_to_set from './utils/add_to_set';
import check_graph_for_cycles from './utils/check_graph_for_cycles'; import check_graph_for_cycles from './utils/check_graph_for_cycles';
import { print, b } from 'code-red'; import { print, b } from 'code-red';
@ -70,6 +70,8 @@ export default class Component {
var_lookup: Map<string, Var> = new Map(); var_lookup: Map<string, Var> = new Map();
imports: ImportDeclaration[] = []; imports: ImportDeclaration[] = [];
exports_from: ExportNamedDeclaration[] = [];
instance_exports_from: ExportNamedDeclaration[] = [];
hoistable_nodes: Set<Node> = new Set(); hoistable_nodes: Set<Node> = new Set();
node_for_declaration: Map<string, Node> = new Map(); node_for_declaration: Map<string, Node> = new Map();
@ -333,7 +335,8 @@ export default class Component {
.map(variable => ({ .map(variable => ({
name: variable.name, name: variable.name,
as: variable.export_name as: variable.export_name
})) })),
this.exports_from
); );
css = compile_options.customElement css = compile_options.customElement
@ -492,22 +495,27 @@ export default class Component {
this.imports.push(node); this.imports.push(node);
} }
extract_exports(node) { extract_exports(node, module_script = false) {
const ignores = extract_svelte_ignore_from_comments(node); const ignores = extract_svelte_ignore_from_comments(node);
if (ignores.length) this.push_ignores(ignores); if (ignores.length) this.push_ignores(ignores);
const result = this._extract_exports(node); const result = this._extract_exports(node, module_script);
if (ignores.length) this.pop_ignores(); if (ignores.length) this.pop_ignores();
return result; return result;
} }
private _extract_exports(node) { private _extract_exports(node: ExportDefaultDeclaration | ExportNamedDeclaration | ExportAllDeclaration, module_script) {
if (node.type === 'ExportDefaultDeclaration') { if (node.type === 'ExportDefaultDeclaration') {
return this.error(node, compiler_errors.default_export); return this.error(node as any, compiler_errors.default_export);
} }
if (node.type === 'ExportNamedDeclaration') { if (node.type === 'ExportNamedDeclaration') {
if (node.source) { if (node.source) {
return this.error(node, compiler_errors.not_implemented); if (module_script) {
this.exports_from.push(node);
} else {
this.instance_exports_from.push(node);
}
return null;
} }
if (node.declaration) { if (node.declaration) {
if (node.declaration.type === 'VariableDeclaration') { if (node.declaration.type === 'VariableDeclaration') {
@ -516,7 +524,7 @@ export default class Component {
const variable = this.var_lookup.get(name); const variable = this.var_lookup.get(name);
variable.export_name = name; variable.export_name = name;
if (variable.writable && !(variable.referenced || variable.referenced_from_script || variable.subscribable)) { if (variable.writable && !(variable.referenced || variable.referenced_from_script || variable.subscribable)) {
this.warn(declarator, compiler_warnings.unused_export_let(this.name.name, name)); this.warn(declarator as any, compiler_warnings.unused_export_let(this.name.name, name));
} }
}); });
}); });
@ -536,7 +544,7 @@ export default class Component {
variable.export_name = specifier.exported.name; variable.export_name = specifier.exported.name;
if (variable.writable && !(variable.referenced || variable.referenced_from_script || variable.subscribable)) { if (variable.writable && !(variable.referenced || variable.referenced_from_script || variable.subscribable)) {
this.warn(specifier, compiler_warnings.unused_export_let(this.name.name, specifier.exported.name)); this.warn(specifier as any, compiler_warnings.unused_export_let(this.name.name, specifier.exported.name));
} }
} }
}); });
@ -612,7 +620,7 @@ export default class Component {
} }
if (/^Export/.test(node.type)) { if (/^Export/.test(node.type)) {
const replacement = this.extract_exports(node); const replacement = this.extract_exports(node, true);
if (replacement) { if (replacement) {
body[i] = replacement; body[i] = replacement;
} else { } else {

@ -174,10 +174,6 @@ export default {
code: 'default-export', code: 'default-export',
message: 'A component cannot have a default export' message: 'A component cannot have a default export'
}, },
not_implemented: {
code: 'not-implemented',
message: 'A component currently cannot have an export ... from'
},
illegal_declaration: { illegal_declaration: {
code: 'illegal-declaration', code: 'illegal-declaration',
message: 'The $ prefix is reserved, and cannot be used for variable and import names' message: 'The $ prefix is reserved, and cannot be used for variable and import names'

@ -1,7 +1,7 @@
import list from '../utils/list'; import list from '../utils/list';
import { ModuleFormat } from '../interfaces'; import { ModuleFormat } from '../interfaces';
import { b, x } from 'code-red'; import { b, x } from 'code-red';
import { Identifier, ImportDeclaration } from 'estree'; import { Identifier, ImportDeclaration, ExportNamedDeclaration } from 'estree';
const wrappers = { esm, cjs }; const wrappers = { esm, cjs };
@ -19,20 +19,21 @@ export default function create_module(
helpers: Array<{ name: string; alias: Identifier }>, helpers: Array<{ name: string; alias: Identifier }>,
globals: Array<{ name: string; alias: Identifier }>, globals: Array<{ name: string; alias: Identifier }>,
imports: ImportDeclaration[], imports: ImportDeclaration[],
module_exports: Export[] module_exports: Export[],
exports_from: ExportNamedDeclaration[]
) { ) {
const internal_path = `${sveltePath}/internal`; const internal_path = `${sveltePath}/internal`;
helpers.sort((a, b) => (a.name < b.name) ? -1 : 1); helpers.sort((a, b) => (a.name < b.name) ? -1 : 1);
globals.sort((a, b) => (a.name < b.name) ? -1 : 1); globals.sort((a, b) => (a.name < b.name) ? -1 : 1);
if (format === 'esm') { const formatter = wrappers[format];
return esm(program, name, banner, sveltePath, internal_path, helpers, globals, imports, module_exports);
}
if (format === 'cjs') return cjs(program, name, banner, sveltePath, internal_path, helpers, globals, imports, module_exports); if (!formatter) {
throw new Error(`options.format is invalid (must be ${list(Object.keys(wrappers))})`);
}
throw new Error(`options.format is invalid (must be ${list(Object.keys(wrappers))})`); return formatter(program, name, banner, sveltePath, internal_path, helpers, globals, imports, module_exports, exports_from);
} }
function edit_source(source, sveltePath) { function edit_source(source, sveltePath) {
@ -76,7 +77,8 @@ function esm(
helpers: Array<{ name: string; alias: Identifier }>, helpers: Array<{ name: string; alias: Identifier }>,
globals: Array<{ name: string; alias: Identifier }>, globals: Array<{ name: string; alias: Identifier }>,
imports: ImportDeclaration[], imports: ImportDeclaration[],
module_exports: Export[] module_exports: Export[],
exports_from: ExportNamedDeclaration[]
) { ) {
const import_declaration = { const import_declaration = {
type: 'ImportDeclaration', type: 'ImportDeclaration',
@ -94,6 +96,9 @@ function esm(
imports.forEach(node => { imports.forEach(node => {
node.source.value = edit_source(node.source.value, sveltePath); node.source.value = edit_source(node.source.value, sveltePath);
}); });
exports_from.forEach(node => {
node.source!.value = edit_source(node.source!.value, sveltePath);
});
const exports = module_exports.length > 0 && { const exports = module_exports.length > 0 && {
type: 'ExportNamedDeclaration', type: 'ExportNamedDeclaration',
@ -110,6 +115,7 @@ function esm(
${import_declaration} ${import_declaration}
${internal_globals} ${internal_globals}
${imports} ${imports}
${exports_from}
${program.body} ${program.body}
@ -127,7 +133,8 @@ function cjs(
helpers: Array<{ name: string; alias: Identifier }>, helpers: Array<{ name: string; alias: Identifier }>,
globals: Array<{ name: string; alias: Identifier }>, globals: Array<{ name: string; alias: Identifier }>,
imports: ImportDeclaration[], imports: ImportDeclaration[],
module_exports: Export[] module_exports: Export[],
exports_from: ExportNamedDeclaration[]
) { ) {
const internal_requires = { const internal_requires = {
type: 'VariableDeclaration', type: 'VariableDeclaration',
@ -183,6 +190,13 @@ function cjs(
const exports = module_exports.map(x => b`exports.${{ type: 'Identifier', name: x.as }} = ${{ type: 'Identifier', name: x.name }};`); const exports = module_exports.map(x => b`exports.${{ type: 'Identifier', name: x.as }} = ${{ type: 'Identifier', name: x.name }};`);
const user_exports_from = exports_from.map(node => {
const init = x`require("${edit_source(node.source.value, sveltePath)}")`;
return node.specifiers.map(specifier => {
return b`exports.${specifier.exported} = ${init}.${specifier.local};`;
});
});
program.body = b` program.body = b`
/* ${banner} */ /* ${banner} */
@ -190,6 +204,7 @@ function cjs(
${internal_requires} ${internal_requires}
${internal_globals} ${internal_globals}
${user_requires} ${user_requires}
${user_exports_from}
${program.body} ${program.body}

@ -227,7 +227,8 @@ function apply_selector(blocks: Block[], node: Element, to_encapsulate: Array<{
return false; return false;
} else if (block.combinator.name === '>') { } else if (block.combinator.name === '>') {
if (apply_selector(blocks, get_element_parent(node), to_encapsulate)) { const has_global_parent = blocks.every(block => block.global);
if (has_global_parent || apply_selector(blocks, get_element_parent(node), to_encapsulate)) {
to_encapsulate.push({ node, block }); to_encapsulate.push({ node, block });
return true; return true;
} }

@ -6,7 +6,7 @@ import { walk } from 'estree-walker';
import { extract_names, Scope } from 'periscopic'; import { extract_names, Scope } from 'periscopic';
import { invalidate } from './invalidate'; import { invalidate } from './invalidate';
import Block from './Block'; import Block from './Block';
import { ClassDeclaration, FunctionExpression, Node, Statement, ObjectExpression, Expression } from 'estree'; import { ImportDeclaration, ClassDeclaration, FunctionExpression, Node, Statement, ObjectExpression, Expression } from 'estree';
import { apply_preprocessor_sourcemap } from '../../utils/mapped_code'; import { apply_preprocessor_sourcemap } from '../../utils/mapped_code';
import { RawSourceMap, DecodedSourceMap } from '@ampproject/remapping/dist/types/types'; import { RawSourceMap, DecodedSourceMap } from '@ampproject/remapping/dist/types/types';
import { flatten } from '../../utils/flatten'; import { flatten } from '../../utils/flatten';
@ -174,6 +174,46 @@ export default function dom(
} }
}); });
component.instance_exports_from.forEach(exports_from => {
const import_declaration = {
...exports_from,
type: 'ImportDeclaration',
specifiers: [],
source: exports_from.source
};
component.imports.push(import_declaration as ImportDeclaration);
exports_from.specifiers.forEach(specifier => {
if (component.component_options.accessors) {
const name = component.get_unique_name(specifier.exported.name);
import_declaration.specifiers.push({
...specifier,
type: 'ImportSpecifier',
imported: specifier.local,
local: name
});
accessors.push({
type: 'MethodDefinition',
kind: 'get',
key: { type: 'Identifier', name: specifier.exported.name },
value: x`function() {
return ${name}
}`
});
} else if (component.compile_options.dev) {
accessors.push({
type: 'MethodDefinition',
kind: 'get',
key: { type: 'Identifier', name: specifier.exported.name },
value: x`function() {
throw new @_Error("<${component.tag}>: Props cannot be read directly from the component instance unless compiling with 'accessors: true' or '<svelte:options accessors/>'");
}`
});
}
});
});
if (component.compile_options.dev) { if (component.compile_options.dev) {
// checking that expected ones were passed // checking that expected ones were passed
const expected = props.filter(prop => prop.writable && !prop.initialised); const expected = props.filter(prop => prop.writable && !prop.initialised);

@ -760,7 +760,7 @@ export default class ElementWrapper extends Wrapper {
intro_block = b` intro_block = b`
@add_render_callback(() => { @add_render_callback(() => {
if (${outro_name}) ${outro_name}.end(1); if (${outro_name}) ${outro_name}.end(1);
if (!${intro_name}) ${intro_name} = @create_in_transition(${this.var}, ${fn}, ${snippet}); ${intro_name} = @create_in_transition(${this.var}, ${fn}, ${snippet});
${intro_name}.start(); ${intro_name}.start();
}); });
`; `;

@ -107,7 +107,7 @@ export default class SlotWrapper extends Wrapper {
if (spread_dynamic_dependencies.size) { if (spread_dynamic_dependencies.size) {
get_slot_spread_changes_fn = renderer.component.get_unique_name(`get_${sanitize(slot_name)}_slot_spread_changes`); get_slot_spread_changes_fn = renderer.component.get_unique_name(`get_${sanitize(slot_name)}_slot_spread_changes`);
renderer.blocks.push(b` renderer.blocks.push(b`
const ${get_slot_spread_changes_fn} = #dirty => ${renderer.dirty(Array.from(spread_dynamic_dependencies))} > 0 ? -1 : 0; const ${get_slot_spread_changes_fn} = #dirty => ${renderer.dirty(Array.from(spread_dynamic_dependencies))};
`); `);
} }
} else { } else {
@ -168,27 +168,41 @@ export default class SlotWrapper extends Wrapper {
if (block.has_outros) { if (block.has_outros) {
condition = x`!#current || ${condition}`; condition = x`!#current || ${condition}`;
} }
let dirty = x`#dirty`;
if (block.has_outros) { // conditions to treat everything as dirty
dirty = x`!#current ? ${renderer.get_initial_dirty()} : ${dirty}`; const all_dirty_conditions = [
get_slot_spread_changes_fn ? x`${get_slot_spread_changes_fn}(#dirty)` : null,
block.has_outros ? x`!#current` : null
].filter(Boolean);
const all_dirty_condition = all_dirty_conditions.length ? all_dirty_conditions.reduce((condition1, condition2) => x`${condition1} || ${condition2}`) : null;
let slot_update;
if (all_dirty_condition) {
const dirty = x`${all_dirty_condition} ? @get_all_dirty_from_scope(${renderer.reference('$$scope')}) : @get_slot_changes(${slot_definition}, ${renderer.reference('$$scope')}, #dirty, ${get_slot_changes_fn})`;
slot_update = b`
if (${slot}.p && ${condition}) {
@update_slot_base(${slot}, ${slot_definition}, #ctx, ${renderer.reference('$$scope')}, ${dirty}, ${get_slot_context_fn});
}
`;
} else {
slot_update = b`
if (${slot}.p && ${condition}) {
@update_slot(${slot}, ${slot_definition}, #ctx, ${renderer.reference('$$scope')}, #dirty, ${get_slot_changes_fn}, ${get_slot_context_fn});
}
`;
} }
const slot_update = get_slot_spread_changes_fn ? b`
if (${slot}.p && ${condition}) {
@update_slot_spread(${slot}, ${slot_definition}, #ctx, ${renderer.reference('$$scope')}, ${dirty}, ${get_slot_changes_fn}, ${get_slot_spread_changes_fn}, ${get_slot_context_fn});
}
` : b`
if (${slot}.p && ${condition}) {
@update_slot(${slot}, ${slot_definition}, #ctx, ${renderer.reference('$$scope')}, ${dirty}, ${get_slot_changes_fn}, ${get_slot_context_fn});
}
`;
let fallback_condition = renderer.dirty(fallback_dynamic_dependencies); let fallback_condition = renderer.dirty(fallback_dynamic_dependencies);
let fallback_dirty = x`#dirty`;
if (block.has_outros) { if (block.has_outros) {
fallback_condition = x`!#current || ${fallback_condition}`; fallback_condition = x`!#current || ${fallback_condition}`;
fallback_dirty = x`!#current ? ${renderer.get_initial_dirty()} : ${fallback_dirty}`;
} }
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 && ${fallback_condition}) { if (${slot_or_fallback} && ${slot_or_fallback}.p && ${fallback_condition}) {
${slot_or_fallback}.p(#ctx, ${dirty}); ${slot_or_fallback}.p(#ctx, ${fallback_dirty});
} }
`; `;

@ -46,7 +46,7 @@ interface BaseDirective extends BaseNode {
modifiers: string[]; modifiers: string[];
} }
export interface Transition extends BaseDirective{ export interface Transition extends BaseDirective {
type: 'Transition'; type: 'Transition';
intro: boolean; intro: boolean;
outro: boolean; outro: boolean;

@ -134,9 +134,9 @@ export function append_styles(
style_sheet_id: string, style_sheet_id: string,
styles: string styles: string
) { ) {
const append_styles_to = get_root_for_styles(target); const append_styles_to = get_root_for_style(target);
if (!append_styles_to?.getElementById(style_sheet_id)) { if (!append_styles_to.getElementById(style_sheet_id)) {
const style = element('style'); const style = element('style');
style.id = style_sheet_id; style.id = style_sheet_id;
style.textContent = styles; style.textContent = styles;
@ -144,20 +144,19 @@ export function append_styles(
} }
} }
export function get_root_for_node(node: Node) { export function get_root_for_style(node: Node): ShadowRoot | Document {
if (!node) return document; if (!node) return document;
return (node.getRootNode ? node.getRootNode() : node.ownerDocument); // check for getRootNode because IE is still supported const root = node.getRootNode ? node.getRootNode() : node.ownerDocument;
} if ((root as ShadowRoot).host) {
return root as ShadowRoot;
function get_root_for_styles(node: Node) { }
const root = get_root_for_node(node); return document;
return (root as ShadowRoot).host ? root as ShadowRoot : root as Document;
} }
export function append_empty_stylesheet(node: Node) { export function append_empty_stylesheet(node: Node) {
const style_element = element('style') as HTMLStyleElement; const style_element = element('style') as HTMLStyleElement;
append_stylesheet(get_root_for_styles(node), style_element); append_stylesheet(get_root_for_style(node), style_element);
return style_element; return style_element;
} }

@ -1,4 +1,4 @@
import { append_empty_stylesheet, get_root_for_node } from './dom'; import { append_empty_stylesheet, get_root_for_style } from './dom';
import { raf } from './environment'; import { raf } from './environment';
interface ExtendedDoc extends Document { interface ExtendedDoc extends Document {
@ -29,7 +29,7 @@ export function create_rule(node: Element & ElementCSSInlineStyle, a: number, b:
const rule = keyframes + `100% {${fn(b, 1 - b)}}\n}`; const rule = keyframes + `100% {${fn(b, 1 - b)}}\n}`;
const name = `__svelte_${hash(rule)}_${uid}`; const name = `__svelte_${hash(rule)}_${uid}`;
const doc = get_root_for_node(node) as unknown as ExtendedDoc; const doc = get_root_for_style(node) as ExtendedDoc;
active_docs.add(doc); active_docs.add(doc);
const stylesheet = doc.__svelte_stylesheet || (doc.__svelte_stylesheet = append_empty_stylesheet(node).sheet as CSSStyleSheet); const stylesheet = doc.__svelte_stylesheet || (doc.__svelte_stylesheet = append_empty_stylesheet(node).sheet as CSSStyleSheet);
const current_rules = doc.__svelte_rules || (doc.__svelte_rules = {}); const current_rules = doc.__svelte_rules || (doc.__svelte_rules = {});

@ -119,20 +119,28 @@ export function get_slot_changes(definition, $$scope, dirty, fn) {
return $$scope.dirty; return $$scope.dirty;
} }
export function update_slot(slot, slot_definition, ctx, $$scope, dirty, get_slot_changes_fn, get_slot_context_fn) { export function update_slot_base(slot, slot_definition, ctx, $$scope, slot_changes, get_slot_context_fn) {
const slot_changes = get_slot_changes(slot_definition, $$scope, dirty, get_slot_changes_fn);
if (slot_changes) { if (slot_changes) {
const slot_context = get_slot_context(slot_definition, ctx, $$scope, get_slot_context_fn); const slot_context = get_slot_context(slot_definition, ctx, $$scope, get_slot_context_fn);
slot.p(slot_context, slot_changes); slot.p(slot_context, slot_changes);
} }
} }
export function update_slot_spread(slot, slot_definition, ctx, $$scope, dirty, get_slot_changes_fn, get_slot_spread_changes_fn, get_slot_context_fn) { export function update_slot(slot, slot_definition, ctx, $$scope, dirty, get_slot_changes_fn, get_slot_context_fn) {
const slot_changes = get_slot_spread_changes_fn(dirty) | get_slot_changes(slot_definition, $$scope, dirty, get_slot_changes_fn); const slot_changes = get_slot_changes(slot_definition, $$scope, dirty, get_slot_changes_fn);
if (slot_changes) { update_slot_base(slot, slot_definition, ctx, $$scope, slot_changes, get_slot_context_fn);
const slot_context = get_slot_context(slot_definition, ctx, $$scope, get_slot_context_fn); }
slot.p(slot_context, slot_changes);
export function get_all_dirty_from_scope($$scope) {
if ($$scope.ctx.length > 32) {
const dirty = [];
const length = $$scope.ctx.length / 32;
for (let i = 0; i < length; i++) {
dirty[i] = -1;
}
return dirty;
} }
return -1;
} }
export function exclude_internal_props(props) { export function exclude_internal_props(props) {
@ -169,7 +177,7 @@ export function null_to_empty(value) {
return value == null ? '' : value; return value == null ? '' : value;
} }
export function set_store_value(store, ret, value = ret) { export function set_store_value(store, ret, value) {
store.set(value); store.set(value);
return ret; return ret;
} }

@ -0,0 +1,27 @@
export default {
warnings: [
{
code: 'css-unused-selector',
end: {
character: 111,
column: 21,
line: 8
},
frame: `
6: color: red;
7: }
8: a:global(.foo) > div {
^
9: color: red;
10: }
`,
message: 'Unused CSS selector "a:global(.foo) > div"',
pos: 91,
start: {
character: 91,
column: 1,
line: 8
}
}
]
};

@ -0,0 +1 @@
div>div.svelte-xyz.svelte-xyz{color:red}div.svelte-xyz.foo>div.svelte-xyz{color:red}

@ -0,0 +1,3 @@
<div class="svelte-xyz">
<div class="svelte-xyz"></div>
</div>

@ -0,0 +1,15 @@
<style>
:global(div) > div {
color: red;
}
div:global(.foo) > div {
color: red;
}
a:global(.foo) > div {
color: red;
}
</style>
<div>
<div />
</div>

@ -0,0 +1,3 @@
<div class="svelte-xyz">
<div class="svelte-xyz"></div>
</div>

@ -0,0 +1,9 @@
<style>
:global(a) > :global(b) > div {
color: red;
}
</style>
<div>
<div />
</div>

@ -0,0 +1,3 @@
<div class="svelte-xyz">
<div class="svelte-xyz"></div>
</div>

@ -0,0 +1,5 @@
export default {
options: {
accessors: true
}
};

@ -0,0 +1,34 @@
/* generated by Svelte vX.Y.Z */
import { SvelteComponent, init, safe_not_equal } from "svelte/internal";
import { f as f_1, g as g_1 } from './d';
import { h as h_1 } from './e';
import { i as j } from './f';
export { d as e } from './c';
export { c } from './b';
export { a, b } from './a';
class Component extends SvelteComponent {
constructor(options) {
super();
init(this, options, null, null, safe_not_equal, {});
}
get f() {
return f_1;
}
get g() {
return g_1;
}
get h() {
return h_1;
}
get j() {
return j;
}
}
export default Component;

@ -0,0 +1,11 @@
<script context="module">
export { a, b } from './a';
export { c } from './b';
export { d as e } from './c';
</script>
<script>
export { f, g } from './d';
export { h } from './e';
export { i as j } from './f';
</script>

@ -0,0 +1,6 @@
export default {
options: {
accessors: true,
format: 'cjs'
}
};

@ -0,0 +1,36 @@
/* generated by Svelte vX.Y.Z */
"use strict";
const { SvelteComponent, init, safe_not_equal } = require("svelte/internal");
const { f: f_1, g: g_1 } = require("./d");
const { h: h_1 } = require("./e");
const { i: j } = require("./f");
exports.e = require("./c").d;
exports.c = require("./b").c;
exports.a = require("./a").a;
exports.b = require("./a").b;
class Component extends SvelteComponent {
constructor(options) {
super();
init(this, options, null, null, safe_not_equal, {});
}
get f() {
return f_1;
}
get g() {
return g_1;
}
get h() {
return h_1;
}
get j() {
return j;
}
}
exports.default = Component;

@ -0,0 +1,11 @@
<script context="module">
export { a, b } from './a';
export { c } from './b';
export { d as e } from './c';
</script>
<script>
export { f, g } from './d';
export { h } from './e';
export { i as j } from './f';
</script>

@ -0,0 +1,18 @@
/* generated by Svelte vX.Y.Z */
import { SvelteComponent, init, safe_not_equal } from "svelte/internal";
import './d';
import './e';
import './f';
export { d as e } from './c';
export { c } from './b';
export { a, b } from './a';
class Component extends SvelteComponent {
constructor(options) {
super();
init(this, options, null, null, safe_not_equal, {});
}
}
export default Component;

@ -0,0 +1,11 @@
<script context="module">
export { a, b } from './a';
export { c } from './b';
export { d as e } from './c';
</script>
<script>
export { f, g } from './d';
export { h } from './e';
export { i as j } from './f';
</script>

@ -0,0 +1,23 @@
<script context="module">
export { a, b } from './B.svelte';
export { c as d } from './B.svelte';
</script>
<script>
export { d, e } from './B.svelte';
export { f as g } from './B.svelte';
let e = 123;
let b = 234;
function foo() {
e = 456;
b = 567;
}
</script>
a: {typeof a}<br />
b: {typeof b}<br />
c: {typeof c}<br />
d: {typeof d}<br />
e: {typeof e}<br />
f: {typeof f}<br />
g: {typeof g}<br />

@ -0,0 +1,8 @@
<script context="module">
export const a = 'a';
export const b = 'b';
export const c = 'c';
export const d = 'd';
export const e = 'e';
export const f = 'f';
</script>

@ -0,0 +1,28 @@
export default {
html: `
a,b,undefined,c
<br />
a: undefined<br />
b: number<br />
c: undefined<br />
d: undefined<br />
e: number<br />
f: undefined<br />
g: undefined<br />
<br />
{"d":"d","e":"e","g":"f"}
`,
ssrHtml: `
a,b,undefined,c
<br />
a: undefined<br />
b: number<br />
c: undefined<br />
d: undefined<br />
e: number<br />
f: undefined<br />
g: undefined<br />
<br />
{}
`
};

@ -0,0 +1,21 @@
<script>
import A, { a, b, c, d } from './A.svelte';
import {onMount} from 'svelte';
let component;
let props = {};
onMount(() => {
props = {
d: component.d,
e: component.e,
f: component.f,
g: component.g,
};
});
</script>
{a},{b},{c},{d}
<br />
<A bind:this={component} />
<br />
{JSON.stringify(props)}

@ -0,0 +1,11 @@
export default {
html: `
<div>$userName1: user1</div>
<div>$userName2: undefined</div>
<div>$userName3: undefined</div>
<div>$userName4: user4</div>
<div>$userName5: undefined</div>
<div>$userName6: user6</div>
<div>$userName7: undefined</div>
`
};

@ -0,0 +1,34 @@
<script>
import { writable } from 'svelte/store';
let userName1 = writable('init1');
let userName2 = writable('init2');
let userName3 = writable('init3');
let userName4 = writable('init4');
let userName5 = writable('init5');
let userName6 = writable('init6');
let userName7 = writable('init7');
let obj = {
userName1: 'user1',
userName2: 'user2',
userName3: 'user3',
$userName4: 'user4',
userName5: 'user5',
$userName6: 'user6',
userName7: 'user7',
};
({userName1: $userName1, $userName2 } = obj);
({$userName3} = obj);
({$userName4} = obj);
({$userName5, $userName6, $userName7} = obj);
</script>
<div>$userName1: {$userName1}</div>
<div>$userName2: {$userName2}</div>
<div>$userName3: {$userName3}</div>
<div>$userName4: {$userName4}</div>
<div>$userName5: {$userName5}</div>
<div>$userName6: {$userName6}</div>
<div>$userName7: {$userName7}</div>

@ -0,0 +1,11 @@
<script>
let name = 'World';
</script>
<div>Hello {name}</div>
<style>
div {
color: red;
}
</style>

@ -0,0 +1,16 @@
export default {
skip_if_ssr: true,
compileOptions: {
cssHash: () => 'svelte-xyz'
},
async test({ assert, component, target, window }) {
assert.htmlEqual(
window.document.head.innerHTML,
'<style id="svelte-xyz">div.svelte-xyz{color:red}</style>'
);
assert.htmlEqual(
component.div.innerHTML,
'<div class="svelte-xyz">Hello World</div>'
);
}
};

@ -0,0 +1,18 @@
<script>
import App from './App.svelte';
import { onMount } from 'svelte';
export let div;
onMount(() => {
div = document.createElement('div');
const app = new App({
target: div
});
return () => {
app.$destroy();
}
});
</script>

@ -0,0 +1,11 @@
<script>
let name = 'World';
</script>
<div>Hello {name}</div>
<style>
div {
color: red;
}
</style>

@ -0,0 +1,16 @@
export default {
skip_if_ssr: true,
compileOptions: {
cssHash: () => 'svelte-xyz'
},
async test({ assert, component, target, window }) {
assert.htmlEqual(
window.document.head.innerHTML,
'<style id="svelte-xyz">div.svelte-xyz{color:red}</style>'
);
assert.htmlEqual(
component.div.innerHTML,
'<div class="svelte-xyz">Hello World</div>'
);
}
};

@ -0,0 +1,18 @@
<script>
import App from './App.svelte';
import { onMount } from 'svelte';
export let div;
onMount(() => {
const app = new App({
target: div
});
return () => {
app.$destroy();
}
});
</script>
<div bind:this={div} />

@ -0,0 +1,11 @@
<script>
let name = 'World';
</script>
<div>Hello {name}</div>
<style>
div {
color: red;
}
</style>

@ -0,0 +1,13 @@
export default {
skip_if_ssr: true,
compileOptions: {
cssHash: () => 'svelte-xyz'
},
async test({ assert, component, target, window }) {
assert.htmlEqual(window.document.head.innerHTML, '');
assert.htmlEqual(component.div.shadowRoot.innerHTML, `
<style id="svelte-xyz">div.svelte-xyz{color:red}</style>
<div class="svelte-xyz">Hello World</div>
`);
}
};

@ -0,0 +1,19 @@
<script>
import App from './App.svelte';
import { onMount } from 'svelte';
export let div;
onMount(() => {
const root = div.attachShadow({ mode: 'open' });
const app = new App({
target: root
});
return () => {
app.$destroy();
}
});
</script>
<div bind:this={div} />

@ -0,0 +1,21 @@
export default {
test({ assert, component, target, window, raf }) {
component.visible = true;
const div = target.querySelector('div');
// animation duration of `in` should be 10ms.
assert.equal(div.style.animation, '__svelte_1670736059_0 10ms linear 0ms 1 both');
// animation duration of `out` should be 5ms.
component.visible = false;
assert.equal(div.style.animation, '__svelte_1670736059_0 10ms linear 0ms 1 both, __svelte_1998461463_0 5ms linear 0ms 1 both');
// change param
raf.tick(1);
component.param = true;
component.visible = true;
// animation duration of `in` should be 20ms.
assert.equal(div.style.animation, '__svelte_722598827_0 20ms linear 0ms 1 both');
}
};

@ -0,0 +1,26 @@
<script>
export let visible = false;
export let param = false;
function getInParam() {
return {
duration: param ? 20 : 10,
css: t => {
return `opacity: ${t}`;
}
};
}
function getOutParam() {
return {
duration: param ? 15 : 5,
css: t => {
return `opacity: ${t}`;
}
};
}
</script>
{#if visible}
<div in:getInParam out:getOutParam></div>
{/if}

@ -15,6 +15,6 @@ export default {
component.visible = true; component.visible = true;
// reset original styles // reset original styles
assert.equal(div.style.animation, '__svelte_3809512021_1 100ms linear 0ms 1 both'); assert.equal(div.style.animation, '__svelte_3809512021_0 100ms linear 0ms 1 both');
} }
}; };

@ -1,3 +1,4 @@
// cancelled the transition halfway
export default { export default {
html: ` html: `
<div>Foo</div> <div>Foo</div>

@ -0,0 +1,19 @@
<script>
export let visible;
export let slotProps;
function fade(node) {
return {
duration: 100,
tick: t => {
node.foo = t;
}
};
}
</script>
{#if visible}
<div transition:fade>
<slot {slotProps}></slot>
</div>
{/if}

@ -0,0 +1,35 @@
// updated props in the middle of transitions
// and cancelled the transition halfway
export default {
html: `
<div>outside Foo Foo Foo</div>
<div>inside Foo Foo Foo</div>
`,
props: {
props: 'Foo'
},
async test({ assert, component, target, window, raf }) {
await component.hide();
const [, div] = target.querySelectorAll('div');
raf.tick(50);
assert.equal(div.foo, 0.5);
component.props = 'Bar';
assert.htmlEqual(target.innerHTML, `
<div>outside Bar Bar Bar</div>
<div>inside Foo Foo Foo</div>
`);
await component.show();
assert.htmlEqual(target.innerHTML, `
<div>outside Bar Bar Bar</div>
<div>inside Bar Bar Bar</div>
`);
raf.tick(100);
assert.equal(div.foo, 1);
}
};

@ -0,0 +1,22 @@
<script>
import Nested from './Nested.svelte';
let visible = true;
let state = 'Foo';
let slotProps = 'Foo';
export let props;
export function show() {
visible = true;
}
export function hide() {
visible = false;
state = 'Bar';
slotProps = 'Bar';
}
</script>
<div>outside {state} {props} {slotProps}</div>
<Nested {visible} {slotProps} let:slotProps>
inside {state} {props} {slotProps}
</Nested>

@ -0,0 +1,19 @@
<script>
export let visible;
export let slotProps;
function fade(node) {
return {
duration: 100,
tick: t => {
node.foo = t;
}
};
}
</script>
{#if visible}
<div transition:fade>
<slot {slotProps}></slot>
</div>
{/if}

@ -0,0 +1,40 @@
// updated props in the middle of transitions
// and cancelled the transition halfway
// + spreaded props + overflow context
export default {
html: `
<div>outside Foo Foo Foo</div>
<div>inside Foo Foo Foo</div>
0
`,
props: {
props: 'Foo'
},
async test({ assert, component, target, window, raf }) {
await component.hide();
const [, div] = target.querySelectorAll('div');
raf.tick(50);
assert.equal(div.foo, 0.5);
component.props = 'Bar';
assert.htmlEqual(target.innerHTML, `
<div>outside Bar Bar Bar</div>
<div>inside Foo Foo Foo</div>
0
`);
await component.show();
assert.htmlEqual(target.innerHTML, `
<div>outside Bar Bar Bar</div>
<div>inside Bar Bar Bar</div>
0
`);
raf.tick(100);
assert.equal(div.foo, 1);
}
};

@ -0,0 +1,27 @@
<script>
import Nested from './Nested.svelte';
export let a1=0,a2=0,a3=0,a4=0,a5=0,a6=0,a7=0,a8=0,a9=0,a10=0,a11=0, a12=0,a13=0,a14=0,a15=0,a16=0,a17=0,a18=0,a19=0,a20=0,a21=0, a22=0,a23=0,a24=0,a25=0,a26=0,a27=0,a28=0,a29=0,a30=0,a31=0,a32=0,a33=0;
let visible = true;
let state = 'Foo';
let slotProps = 'Foo';
export let props;
export function show() {
visible = true;
}
export function hide() {
visible = false;
state = 'Bar';
slotProps = 'Bar';
}
</script>
<div>outside {state} {props} {slotProps}</div>
<Nested {visible} {slotProps} let:slotProps>
inside {state} {props} {slotProps}
</Nested>
{a1+a2+a3+a4+a5+a6+a7+a8+a9+a10+a11+a12+a13+a14+a15+a16+a17+a18+a19+a20+a21+a22+a23+a24+a25+a26+a27+a28+a29+a30+a31+a32+a33}

@ -0,0 +1,19 @@
<script>
export let visible;
export let slotProps;
function fade(node) {
return {
duration: 100,
tick: t => {
node.foo = t;
}
};
}
</script>
{#if visible}
<div transition:fade>
<slot {...slotProps}></slot>
</div>
{/if}

@ -0,0 +1,19 @@
<script>
export let visible;
let slotProps = { slotProps: 'XXX' };
function fade(node) {
return {
duration: 100,
tick: t => {
node.foo = t;
}
};
}
</script>
{#if visible}
<div transition:fade>
<slot {...slotProps}></slot>
</div>
{/if}

@ -0,0 +1,40 @@
// updated props in the middle of transitions
// and cancelled the transition halfway
// with spreaded props
export default {
html: `
<div>outside Foo Foo Foo</div>
<div>inside Foo Foo Foo</div>
<div>inside Foo Foo XXX</div>
`,
props: {
props: 'Foo'
},
async test({ assert, component, target, window, raf }) {
await component.hide();
const [, div] = target.querySelectorAll('div');
raf.tick(50);
assert.equal(div.foo, 0.5);
component.props = 'Bar';
assert.htmlEqual(target.innerHTML, `
<div>outside Bar Bar Bar</div>
<div>inside Foo Foo Foo</div>
<div>inside Foo Foo XXX</div>
`);
await component.show();
assert.htmlEqual(target.innerHTML, `
<div>outside Bar Bar Bar</div>
<div>inside Bar Bar Bar</div>
<div>inside Bar Bar XXX</div>
`);
raf.tick(100);
assert.equal(div.foo, 1);
}
};

@ -0,0 +1,26 @@
<script>
import Nested from './Nested.svelte';
import Nested2 from './Nested2.svelte';
let visible = true;
let state = 'Foo';
let slotProps = { slotProps: 'Foo' };
export let props;
export function show() {
visible = true;
}
export function hide() {
visible = false;
state = 'Bar';
slotProps = { slotProps: 'Bar' };
}
</script>
<div>outside {state} {props} {slotProps.slotProps}</div>
<Nested {visible} {slotProps} let:slotProps>
inside {state} {props} {slotProps}
</Nested>
<Nested2 {visible} let:slotProps>
inside {state} {props} {slotProps}
</Nested2>

@ -0,0 +1,19 @@
<script>
export let visible;
export let slotProps;
function fade(node) {
return {
duration: 100,
tick: t => {
node.foo = t;
}
};
}
</script>
{#if visible}
<div transition:fade>
<slot {...slotProps}></slot>
</div>
{/if}

@ -0,0 +1,40 @@
// updated props in the middle of transitions
// and cancelled the transition halfway
// + spreaded props + overflow context
export default {
html: `
<div>outside Foo Foo Foo</div>
<div>inside Foo Foo Foo</div>
0
`,
props: {
props: 'Foo'
},
async test({ assert, component, target, window, raf }) {
await component.hide();
const [, div] = target.querySelectorAll('div');
raf.tick(50);
assert.equal(div.foo, 0.5);
component.props = 'Bar';
assert.htmlEqual(target.innerHTML, `
<div>outside Bar Bar Bar</div>
<div>inside Foo Foo Foo</div>
0
`);
await component.show();
assert.htmlEqual(target.innerHTML, `
<div>outside Bar Bar Bar</div>
<div>inside Bar Bar Bar</div>
0
`);
raf.tick(100);
assert.equal(div.foo, 1);
}
};

@ -0,0 +1,27 @@
<script>
import Nested from './Nested.svelte';
export let a1=0,a2=0,a3=0,a4=0,a5=0,a6=0,a7=0,a8=0,a9=0,a10=0,a11=0, a12=0,a13=0,a14=0,a15=0,a16=0,a17=0,a18=0,a19=0,a20=0,a21=0, a22=0,a23=0,a24=0,a25=0,a26=0,a27=0,a28=0,a29=0,a30=0,a31=0,a32=0,a33=0;
let visible = true;
let state = 'Foo';
let slotProps = { slotProps: 'Foo' };
export let props;
export function show() {
visible = true;
}
export function hide() {
visible = false;
state = 'Bar';
slotProps = { slotProps: 'Bar' };
}
</script>
<div>outside {state} {props} {slotProps.slotProps}</div>
<Nested {visible} {slotProps} let:slotProps>
inside {state} {props} {slotProps}
</Nested>
{a1+a2+a3+a4+a5+a6+a7+a8+a9+a10+a11+a12+a13+a14+a15+a16+a17+a18+a19+a20+a21+a22+a23+a24+a25+a26+a27+a28+a29+a30+a31+a32+a33}
Loading…
Cancel
Save