merge master -> snake_case

pull/3094/head
Rich Harris 6 years ago
commit 324be53a70

@ -101,7 +101,8 @@ export default class Component {
reactive_declaration_nodes: Set<Node> = new Set();
has_reactive_assignments = false;
injected_reactive_declaration_vars: Set<string> = new Set();
helpers: Set<string> = new Set();
helpers: Map<string, string> = new Map();
globals: Map<string, string> = new Map();
indirect_dependencies: Map<string, Set<string>> = new Map();
@ -233,8 +234,15 @@ export default class Component {
}
helper(name: string) {
this.helpers.add(name);
return this.alias(name);
const alias = this.alias(name)
this.helpers.set(name, alias);
return alias;
}
global(name: string) {
const alias = this.alias(name);
this.globals.set(name, alias);
return alias;
}
generate(result: string) {
@ -251,23 +259,29 @@ export default class Component {
.replace(/__svelte:self__/g, this.name)
.replace(compile_options.generate === 'ssr' ? /(@+|#+)(\w*(?:-\w*)?)/g : /(@+)(\w*(?:-\w*)?)/g, (_match: string, sigil: string, name: string) => {
if (sigil === '@') {
if (internal_exports.has(name)) {
if (compile_options.dev && internal_exports.has(`${name}Dev`)) name = `${name}Dev`;
this.helpers.add(name);
if (name[0] === '_') {
return this.global(name.slice(1));
}
if (!internal_exports.has(name)) {
throw new Error(`compiler error: this shouldn't happen! generated code is trying to use inexistent internal '${name}'`);
}
if (compile_options.dev && internal_exports.has(`${name}Dev`)) {
name = `${name}Dev`;
}
return this.alias(name);
return this.helper(name);
}
return sigil.slice(1) + name;
});
const imported_helpers = Array.from(this.helpers)
.sort()
.map(name => {
const alias = this.alias(name);
return { name, alias };
});
const referenced_globals = Array.from(this.globals, ([name, alias]) => name !== alias && ({ name, alias })).filter(Boolean);
if (referenced_globals.length) {
this.helper('globals');
}
const imported_helpers = Array.from(this.helpers, ([name, alias]) => ({ name, alias }));
const module = create_module(
result,
@ -276,6 +290,7 @@ export default class Component {
banner,
compile_options.sveltePath,
imported_helpers,
referenced_globals,
this.imports,
this.vars.filter(variable => variable.module && variable.export_name).map(variable => ({
name: variable.name,

@ -17,6 +17,7 @@ export default function create_module(
banner: string,
sveltePath = 'svelte',
helpers: Array<{ name: string; alias: string }>,
globals: Array<{ name: string; alias: string }>,
imports: Node[],
module_exports: Export[],
source: string
@ -24,10 +25,10 @@ export default function create_module(
const internal_path = `${sveltePath}/internal`;
if (format === 'esm') {
return esm(code, name, banner, sveltePath, internal_path, helpers, imports, module_exports, source);
return esm(code, name, banner, sveltePath, internal_path, helpers, globals, imports, module_exports, source);
}
if (format === 'cjs') return cjs(code, name, banner, sveltePath, internal_path, helpers, imports, module_exports);
if (format === 'cjs') return cjs(code, name, banner, sveltePath, internal_path, helpers, globals, imports, module_exports);
throw new Error(`options.format is invalid (must be ${list(Object.keys(wrappers))})`);
}
@ -45,6 +46,7 @@ function esm(
sveltePath: string,
internal_path: string,
helpers: Array<{ name: string; alias: string }>,
globals: Array<{ name: string; alias: string }>,
imports: Node[],
module_exports: Export[],
source: string
@ -52,6 +54,9 @@ function esm(
const internal_imports = helpers.length > 0 && (
`import ${stringify_props(helpers.map(h => h.name === h.alias ? h.name : `${h.name} as ${h.alias}`).sort())} from ${JSON.stringify(internal_path)};`
);
const internal_globals = globals.length > 0 && (
`const ${stringify_props(globals.map(g => `${g.name}: ${g.alias}`).sort())} = ${helpers.find(({ name }) => name === 'globals').alias};`
);
const user_imports = imports.length > 0 && (
imports
@ -70,6 +75,7 @@ function esm(
return deindent`
${banner}
${internal_imports}
${internal_globals}
${user_imports}
${code}
@ -85,6 +91,7 @@ function cjs(
sveltePath: string,
internal_path: string,
helpers: Array<{ name: string; alias: string }>,
globals: Array<{ name: string; alias: string }>,
imports: Node[],
module_exports: Export[]
) {
@ -93,6 +100,9 @@ function cjs(
const internal_imports = helpers.length > 0 && (
`const ${stringify_props(declarations)} = require(${JSON.stringify(internal_path)});\n`
);
const internal_globals = globals.length > 0 && (
`const ${stringify_props(globals.map(g => `${g.name}: ${g.alias}`).sort())} = ${helpers.find(({ name }) => name === 'globals').alias};`
);
const requires = imports.map(node => {
let lhs;
@ -127,6 +137,7 @@ function cjs(
"use strict";
${internal_imports}
${internal_globals}
${requires}
${code}

@ -164,7 +164,7 @@ export default class Block {
if (parent_node) {
this.builders.mount.add_line(`@append(${parent_node}, ${name});`);
if (parent_node === 'document.head' && !no_detach) this.builders.destroy.add_line(`@detach(${name});`);
if (parent_node === '@_document.head' && !no_detach) this.builders.destroy.add_line(`@detach(${name});`);
} else {
this.builders.mount.add_line(`@insert(#target, ${name}, anchor);`);
if (!no_detach) this.builders.destroy.add_conditional('detaching', `@detach(${name});`);

@ -36,13 +36,15 @@ export default function dom(
`${css.code}\n/*# sourceMappingURL=${css.map.toUrl()} */` :
css.code, { only_escape_at_symbol: true });
const add_css = component.get_unique_name('add_css');
if (styles && component.compile_options.css !== false && !options.customElement) {
builder.add_block(deindent`
function @add_css() {
function ${add_css}() {
var style = @element("style");
style.id = '${component.stylesheet.id}-style';
style.textContent = ${styles};
@append(document.head, style);
@append(@_document.head, style);
}
`);
}
@ -57,7 +59,7 @@ export default function dom(
if (options.dev && !options.hydratable) {
block.builders.claim.add_line(
'throw new Error("options.hydrate only works if the component was compiled with the `hydratable: true` option");'
'throw new @_Error("options.hydrate only works if the component was compiled with the `hydratable: true` option");'
);
}
@ -106,7 +108,7 @@ export default function dom(
} else if (component.compile_options.dev) {
body.push(deindent`
get ${x.export_name}() {
throw new Error("<${component.tag}>: Props cannot be read directly from the component instance unless compiling with 'accessors: true' or '<svelte:options accessors/>'");
throw new @_Error("<${component.tag}>: Props cannot be read directly from the component instance unless compiling with 'accessors: true' or '<svelte:options accessors/>'");
}
`);
}
@ -122,14 +124,14 @@ export default function dom(
} else if (component.compile_options.dev) {
body.push(deindent`
set ${x.export_name}(value) {
throw new Error("<${component.tag}>: Cannot set read-only property '${x.export_name}'");
throw new @_Error("<${component.tag}>: Cannot set read-only property '${x.export_name}'");
}
`);
}
} else if (component.compile_options.dev) {
body.push(deindent`
set ${x.export_name}(value) {
throw new Error("<${component.tag}>: Props cannot be set directly on the component instance unless compiling with 'accessors: true' or '<svelte:options accessors/>'");
throw new @_Error("<${component.tag}>: Props cannot be set directly on the component instance unless compiling with 'accessors: true' or '<svelte:options accessors/>'");
}
`);
}
@ -145,7 +147,7 @@ export default function dom(
const props = ${options.customElement ? `this.attributes` : `options.props || {}`};
${expected.map(prop => deindent`
if (ctx.${prop.name} === undefined && !('${prop.export_name}' in props)) {
console.warn("<${component.tag}> was created without expected prop '${prop.export_name}'");
@_console.warn("<${component.tag}> was created without expected prop '${prop.export_name}'");
}`)}
`;
}
@ -402,8 +404,8 @@ export default function dom(
if (component.compile_options.dev && !component.var_lookup.has('$$props') && writable_props.length) {
unknown_props_check = deindent`
const writable_props = [${writable_props.map(prop => `'${prop.export_name}'`).join(', ')}];
Object.keys($$props).forEach(key => {
if (!writable_props.includes(key) && !key.startsWith('$$')) console.warn(\`<${component.tag}> was created with unknown prop '\${key}'\`);
@_Object.keys($$props).forEach(key => {
if (!writable_props.includes(key) && !key.startsWith('$$')) @_console.warn(\`<${component.tag}> was created with unknown prop '\${key}'\`);
});
`;
}
@ -481,7 +483,7 @@ export default function dom(
if (component.tag != null) {
builder.add_block(deindent`
customElements.define("${component.tag}", ${name});
@_customElements.define("${component.tag}", ${name});
`);
}
} else {
@ -491,7 +493,7 @@ export default function dom(
class ${name} extends @${superclass} {
constructor(options) {
super(${options.dev && `options`});
${should_add_css && `if (!document.getElementById("${component.stylesheet.id}-style")) @add_css();`}
${should_add_css && `if (!@_document.getElementById("${component.stylesheet.id}-style")) ${add_css}();`}
@init(this, options, ${definition}, create_fragment, ${not_equal}, ${prop_names});
${dev_props_check}

@ -142,7 +142,7 @@ export default class AwaitBlockWrapper extends Wrapper {
this.catch.block.name && `catch: ${this.catch.block.name}`,
this.then.block.name && `value: '${this.node.value}'`,
this.catch.block.name && `error: '${this.node.error}'`,
this.pending.block.has_outro_method && `blocks: Array(3)`
this.pending.block.has_outro_method && `blocks: [,,,]`
].filter(Boolean);
block.builders.init.add_block(deindent`
@ -230,4 +230,4 @@ export default class AwaitBlockWrapper extends Wrapper {
branch.fragment.render(branch.block, null, 'nodes');
});
}
}
}

@ -11,11 +11,11 @@ export default class BodyWrapper extends Wrapper {
const snippet = handler.render(block);
block.builders.init.add_block(deindent`
document.body.addEventListener("${handler.name}", ${snippet});
@_document.body.addEventListener("${handler.name}", ${snippet});
`);
block.builders.destroy.add_block(deindent`
document.body.removeEventListener("${handler.name}", ${snippet});
@_document.body.removeEventListener("${handler.name}", ${snippet});
`);
});
}

@ -62,7 +62,7 @@ export default class DebugTagWrapper extends Wrapper {
block.builders.update.add_block(deindent`
if (${condition}) {
const { ${ctx_identifiers} } = ctx;
console.${log}({ ${logged_identifiers} });
@_console.${log}({ ${logged_identifiers} });
debugger;
}
`);
@ -70,7 +70,7 @@ export default class DebugTagWrapper extends Wrapper {
block.builders.create.add_block(deindent`
{
const { ${ctx_identifiers} } = ctx;
console.${log}({ ${logged_identifiers} });
@_console.${log}({ ${logged_identifiers} });
debugger;
}
`);

@ -190,7 +190,7 @@ export default class EachBlockWrapper extends Wrapper {
renderer.blocks.push(deindent`
function ${this.vars.get_each_context}(ctx, list, i) {
const child_ctx = Object.create(ctx);
const child_ctx = @_Object.create(ctx);
${this.context_props}
return child_ctx;
}
@ -296,7 +296,7 @@ export default class EachBlockWrapper extends Wrapper {
const lookup = block.get_unique_name(`${this.var}_lookup`);
block.add_variable(iterations, '[]');
block.add_variable(lookup, `new Map()`);
block.add_variable(lookup, `new @_Map()`);
if (this.fragment.nodes[0].is_dom_node()) {
this.block.first = this.fragment.nodes[0].var;
@ -498,7 +498,7 @@ export default class EachBlockWrapper extends Wrapper {
if (this.block.has_outros) {
block.builders.outro.add_block(deindent`
${iterations} = ${iterations}.filter(Boolean);
${iterations} = ${iterations}.filter(@_Boolean);
for (let #i = 0; #i < ${view_length}; #i += 1) @transition_out(${iterations}[#i]);`
);
}

@ -144,7 +144,7 @@ export default class BindingWrapper {
case 'currentTime':
case 'playbackRate':
case 'volume':
update_conditions.push(`!isNaN(${this.snippet})`);
update_conditions.push(`!@_isNaN(${this.snippet})`);
break;
case 'paused':

@ -270,7 +270,7 @@ export default class ElementWrapper extends Wrapper {
`@append(${parent_node}, ${node});`
);
if (parent_node === 'document.head') {
if (parent_node === '@_document.head') {
block.builders.destroy.add_line(`@detach(${node});`);
}
} else {
@ -381,7 +381,7 @@ export default class ElementWrapper extends Wrapper {
}
if (namespace) {
return `document.createElementNS("${namespace}", "${name}")`;
return `@_document.createElementNS("${namespace}", "${name}")`;
}
return `@element("${name}")`;
@ -467,7 +467,7 @@ export default class ElementWrapper extends Wrapper {
block.builders.init.add_block(deindent`
function ${handler}() {
${animation_frame && deindent`
cancelAnimationFrame(${animation_frame});
@_cancelAnimationFrame(${animation_frame});
if (!${this.var}.paused) ${animation_frame} = @raf(${handler});`}
${needs_lock && `${lock} = true;`}
ctx.${handler}.call(${this.var}${contextual_dependencies.size > 0 ? ', ctx' : ''});

@ -30,6 +30,6 @@ export default class HeadWrapper extends Wrapper {
}
render(block: Block, _parent_node: string, _parent_nodes: string) {
this.fragment.render(block, 'document.head', 'nodes');
this.fragment.render(block, '@_document.head', 'nodes');
}
}

@ -154,7 +154,7 @@ export default class IfBlockWrapper extends Wrapper {
const vars = { name, anchor, if_name, has_else, has_transitions };
const detaching = (parent_node && parent_node !== 'document.head') ? '' : 'detaching';
const detaching = (parent_node && parent_node !== '@_document.head') ? '' : 'detaching';
if (this.node.else) {
if (has_outros) {

@ -22,7 +22,7 @@ export default class RawMustacheTagWrapper extends Tag {
render(block: Block, parent_node: string, parent_nodes: string) {
const name = this.var;
const in_head = parent_node === 'document.head';
const in_head = parent_node === '@_document.head';
const needs_anchors = !parent_node || in_head;
// if in head always needs anchors

@ -68,9 +68,9 @@ export default class TitleWrapper extends Wrapper {
const init = this.node.should_cache ? `${last} = ${value}` : value;
block.builders.init.add_line(
`document.title = ${init};`
`@_document.title = ${init};`
);
const updater = `document.title = ${this.node.should_cache ? last : value};`;
const updater = `@_document.title = ${this.node.should_cache ? last : value};`;
if (all_dependencies.size) {
const dependencies = Array.from(all_dependencies);
@ -95,7 +95,7 @@ export default class TitleWrapper extends Wrapper {
? stringify((this.node.children[0] as Text).data)
: '""';
block.builders.hydrate.add_line(`document.title = ${value};`);
block.builders.hydrate.add_line(`@_document.title = ${value};`);
}
}
}

@ -44,8 +44,8 @@ export default class WindowWrapper extends Wrapper {
const events = {};
const bindings: Record<string, string> = {};
add_actions(component, block, 'window', this.node.actions);
add_event_handlers(block, 'window', this.node.handlers);
add_actions(component, block, '@_window', this.node.actions);
add_event_handlers(block, '@_window', this.node.handlers);
this.node.bindings.forEach(binding => {
// in dev mode, throw if read-only values are written to
@ -92,29 +92,29 @@ export default class WindowWrapper extends Wrapper {
renderer.meta_bindings.add_block(deindent`
if (${condition}) {
window.scrollTo(${x || 'window.pageXOffset'}, ${y || 'window.pageYOffset'});
@_scrollTo(${x || '@_window.pageXOffset'}, ${y || '@_window.pageYOffset'});
}
${x && `${x} = window.pageXOffset;`}
${y && `${y} = window.pageYOffset;`}
${x && `${x} = @_window.pageXOffset;`}
${y && `${y} = @_window.pageYOffset;`}
`);
block.event_listeners.push(deindent`
@listen(window, "${event}", () => {
@listen(@_window, "${event}", () => {
${scrolling} = true;
clearTimeout(${scrolling_timeout});
${scrolling_timeout} = setTimeout(${clear_scrolling}, 100);
@_clearTimeout(${scrolling_timeout});
${scrolling_timeout} = @_setTimeout(${clear_scrolling}, 100);
ctx.${handler_name}();
})
`);
} else {
props.forEach(prop => {
renderer.meta_bindings.add_line(
`this._state.${prop.name} = window.${prop.value};`
`this._state.${prop.name} = @_window.${prop.value};`
);
});
block.event_listeners.push(deindent`
@listen(window, "${event}", ctx.${handler_name})
@listen(@_window, "${event}", ctx.${handler_name})
`);
}
@ -126,7 +126,7 @@ export default class WindowWrapper extends Wrapper {
component.partly_hoisted.push(deindent`
function ${handler_name}() {
${props.map(prop => `${prop.name} = window.${prop.value}; $$invalidate('${prop.name}', ${prop.name});`)}
${props.map(prop => `${prop.name} = @_window.${prop.value}; $$invalidate('${prop.name}', ${prop.name});`)}
}
`);
@ -146,13 +146,13 @@ export default class WindowWrapper extends Wrapper {
).join(' || ')
} && !${scrolling}) {
${scrolling} = true;
clearTimeout(${scrolling_timeout});
window.scrollTo(${
bindings.scrollX ? `ctx.${bindings.scrollX}` : `window.pageXOffset`
@_clearTimeout(${scrolling_timeout});
@_scrollTo(${
bindings.scrollX ? `ctx.${bindings.scrollX}` : `@_window.pageXOffset`
}, ${
bindings.scrollY ? `ctx.${bindings.scrollY}` : `window.pageYOffset`
bindings.scrollY ? `ctx.${bindings.scrollY}` : `@_window.pageYOffset`
});
${scrolling_timeout} = setTimeout(${clear_scrolling}, 100);
${scrolling_timeout} = @_setTimeout(${clear_scrolling}, 100);
}
`);
}
@ -170,7 +170,7 @@ export default class WindowWrapper extends Wrapper {
component.partly_hoisted.push(deindent`
function ${handler_name}() {
${name} = navigator.onLine; $$invalidate('${name}', ${name});
${name} = @_navigator.onLine; $$invalidate('${name}', ${name});
}
`);
@ -179,8 +179,8 @@ export default class WindowWrapper extends Wrapper {
`);
block.event_listeners.push(
`@listen(window, "online", ctx.${handler_name})`,
`@listen(window, "offline", ctx.${handler_name})`
`@listen(@_window, "online", ctx.${handler_name})`,
`@listen(@_window, "offline", ctx.${handler_name})`
);
component.has_reactive_assignments = true;

@ -52,7 +52,7 @@ export default function(node: InlineComponent, renderer: Renderer, options: Rend
let props;
if (uses_spread) {
props = `Object.assign(${
props = `@_Object.assign(${
node.attributes
.map(attribute => {
if (attribute.is_spread) {

@ -2,6 +2,7 @@ import { walk } from 'estree-walker';
import is_reference from 'is-reference';
import { Node } from '../../interfaces';
import { Node as ESTreeNode } from 'estree';
import get_object from './get_object';
export function create_scopes(expression: Node) {
const map = new WeakMap();
@ -114,6 +115,10 @@ const extractors = {
nodes.push(param);
},
MemberExpression(nodes: Node[], param: Node) {
nodes.push(get_object(param));
},
ObjectPattern(nodes: Node[], param: Node) {
param.properties.forEach((prop: Node) => {
if (prop.type === 'RestElement') {

@ -0,0 +1,3 @@
declare const global: any;
export const globals = (typeof window !== 'undefined' ? window : global) as unknown as typeof globalThis;

@ -2,6 +2,7 @@ export * from './animations';
export * from './await_block';
export * from './dom';
export * from './environment';
export * from './globals';
export * from './keyed_each';
export * from './lifecycle';
export * from './loop';

@ -28,7 +28,7 @@ export function exists(path) {
export function tryToLoadJson(file) {
try {
return JSON.parse(fs.readFileSync(file));
return JSON.parse(fs.readFileSync(file, 'utf-8'));
} catch (err) {
if (err.code !== 'ENOENT') throw err;
return null;
@ -44,14 +44,21 @@ export function tryToReadFile(file) {
}
}
export const virtualConsole = new jsdom.VirtualConsole();
const { window } = new jsdom.JSDOM('<main></main>', {virtualConsole});
const virtualConsole = new jsdom.VirtualConsole();
virtualConsole.sendTo(console);
global.window = new jsdom.JSDOM('<main></main>', {virtualConsole}).window;
global.document = window.document;
global.getComputedStyle = window.getComputedStyle;
global.navigator = {userAgent: 'fake'};
global.requestAnimationFrame = null; // placeholder, filled in using set_raf
// add missing ecmascript globals to window
for (const key of Object.getOwnPropertyNames(global)) {
window[key] = window[key] || global[key];
}
export function env() {
window._svelteTransitionManager = null;
window.document.title = '';
window.document.body.innerHTML = '<main></main>';
return window;
@ -120,7 +127,7 @@ export function normalizeHtml(window, html) {
.replace(/<!--.*?-->/g, '')
.replace(/>[\s\r\n]+</g, '><')
.trim();
cleanChildren(node, '');
cleanChildren(node);
return node.innerHTML.replace(/<\/?noscript\/?>/g, '');
} catch (err) {
throw new Error(`Failed to normalize HTML:\n${html}`);

@ -42,7 +42,7 @@ function create_fragment(ctx) {
if (changed.y && !scrolling) {
scrolling = true;
clearTimeout(scrolling_timeout);
window.scrollTo(window.pageXOffset, ctx.y);
scrollTo(window.pageXOffset, ctx.y);
scrolling_timeout = setTimeout(clear_scrolling, 100);
}

@ -3,7 +3,7 @@ import * as path from "path";
import * as fs from "fs";
import { rollup } from 'rollup';
import * as virtual from 'rollup-plugin-virtual';
import { clear_loops, set_now, set_raf } from "../../internal";
import { clear_loops, flush, set_now, set_raf } from "../../internal";
import {
showOutput,
@ -20,7 +20,6 @@ let compileOptions = null;
let compile = null;
const sveltePath = process.cwd().split('\\').join('/');
const internal = `${sveltePath}/internal`;
describe("runtime", () => {
before(() => {
@ -47,8 +46,6 @@ describe("runtime", () => {
function runTest(dir, hydrate) {
if (dir[0] === ".") return;
const { flush } = require(internal);
const config = loadConfig(`./runtime/samples/${dir}/_config.js`);
if (hydrate && config.skip_if_hydrate) return;
@ -66,7 +63,6 @@ describe("runtime", () => {
compile = (config.preserveIdentifiers ? svelte : svelte$).compile;
const cwd = path.resolve(`test/runtime/samples/${dir}`);
global.document.title = '';
compileOptions = config.compileOptions || {};
compileOptions.sveltePath = sveltePath;
@ -119,8 +115,6 @@ describe("runtime", () => {
throw err;
}
global.window = window;
if (config.before_test) config.before_test();
// Put things we need on window for testing
@ -221,6 +215,7 @@ describe("runtime", () => {
'main.js': js.code
}),
{
name: 'svelte-packages',
resolveId: (importee, importer) => {
if (importee.startsWith('svelte/')) {
return importee.replace('svelte', process.cwd()) + '/index.mjs';

@ -0,0 +1,14 @@
export default {
preserveIdentifiers: true,
compileOptions: {
name: 'window'
},
html: `
<p>I hereby declare Svelte the bestest framework.</p>
<p>nintendo sixty four</p>
<p>Woops.</p>
<p>42</p>
<p>false</p>
`
};

@ -0,0 +1,20 @@
<script>
const document = 'I hereby declare Svelte the bestest framework.';
const console = 'nintendo sixty four';
const Error = 'Woops.';
const Object = 42;
const Map = false;
const everyone = [document, console, Error, Object, Map];
</script>
<svelte:head>
<title>Cute test</title>
</svelte:head>
<svelte:window on:click></svelte:window>
<svelte:body on:mouseenter></svelte:body>
{#each everyone as someone (someone)}
<p>{someone}</p>
{/each}

@ -0,0 +1,23 @@
export default {
html: `
<ul>
<li>Gruyere</li>
<li>Compté</li>
<li>Beaufort</li>
<li>Abondance</li>
</ul>
`,
async test({ assert, component, target }) {
await component.swap(0, 1);
assert.htmlEqual(target.innerHTML, `
<ul>
<li>Compté</li>
<li>Gruyere</li>
<li>Beaufort</li>
<li>Abondance</li>
</ul>
`);
}
};

@ -0,0 +1,18 @@
<script>
let cheese = [
'Gruyere',
'Compté',
'Beaufort',
'Abondance',
];
export function swap(a, b) {
[cheese[a], cheese[b]] = [cheese[b], cheese[a]];
}
</script>
<ul>
{#each cheese as cheese}
<li>{cheese}</li>
{/each}
</ul>

@ -2,6 +2,10 @@ const glob = require("tiny-glob/sync.js");
require("./setup");
// bind internal to jsdom
require("./helpers");
require("../internal");
glob("*/index.{js,ts}", { cwd: "test" }).forEach((file) => {
require("./" + file);
});

Loading…
Cancel
Save