pull/3539/head
Richard Harris 6 years ago
parent 5d8ca9f07d
commit 93c7e1de11

39
package-lock.json generated

@ -1,6 +1,6 @@
{ {
"name": "svelte", "name": "svelte",
"version": "3.11.0", "version": "3.12.0",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {
@ -330,6 +330,12 @@
"integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==",
"dev": true "dev": true
}, },
"astring": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/astring/-/astring-1.4.1.tgz",
"integrity": "sha512-CXBXWo/KY1AMtcvXm+92K8y8SQqjs35LJJ2/w5Jlm3srsNyzbRoZmgR05T2Z8CYKH/NpojEtuZThpkwSlMEHKg==",
"dev": true
},
"async-limiter": { "async-limiter": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz",
@ -501,6 +507,28 @@
"integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
"dev": true "dev": true
}, },
"code-red": {
"version": "0.0.2",
"resolved": "https://registry.npmjs.org/code-red/-/code-red-0.0.2.tgz",
"integrity": "sha512-rWOFsZAv8XmC14ZP1xZ/t4m9L5Et4sXTpWgghnl0SNWrNxuZKDKMwTlNF7h5XYua/86Di1Oj7F3zOsYkF+Ffaw==",
"dev": true,
"requires": {
"acorn": "^7.0.0",
"astring": "^1.4.1",
"estree-walker": "^0.6.1",
"is-reference": "^1.1.3",
"periscopic": "^1.0.0",
"source-map": "^0.7.3"
},
"dependencies": {
"source-map": {
"version": "0.7.3",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
"integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==",
"dev": true
}
}
},
"codecov": { "codecov": {
"version": "3.5.0", "version": "3.5.0",
"resolved": "https://registry.npmjs.org/codecov/-/codecov-3.5.0.tgz", "resolved": "https://registry.npmjs.org/codecov/-/codecov-3.5.0.tgz",
@ -2705,6 +2733,15 @@
"integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=",
"dev": true "dev": true
}, },
"periscopic": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/periscopic/-/periscopic-1.0.0.tgz",
"integrity": "sha512-ftydZZH2Ca4FdWJXDwQ1Uuz4VEBhh4jXuT1bprR4qg/zM2+FhulluBUxnQXI0olDqADmsQRE1eHLs42iIhNjtA==",
"dev": true,
"requires": {
"is-reference": "^1.1.3"
}
},
"pify": { "pify": {
"version": "4.0.1", "version": "4.0.1",
"resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",

@ -63,6 +63,7 @@
"acorn": "^7.0.0", "acorn": "^7.0.0",
"agadoo": "^1.0.1", "agadoo": "^1.0.1",
"c8": "^5.0.1", "c8": "^5.0.1",
"code-red": "0.0.2",
"codecov": "^3.5.0", "codecov": "^3.5.0",
"css-tree": "1.0.0-alpha22", "css-tree": "1.0.0-alpha22",
"eslint": "^6.3.0", "eslint": "^6.3.0",

@ -30,6 +30,7 @@ import Slot from './nodes/Slot';
import { Node as ESTreeNode } from 'estree'; import { Node as ESTreeNode } 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 } from 'code-red';
interface ComponentOptions { interface ComponentOptions {
namespace?: string; namespace?: string;
@ -286,7 +287,7 @@ export default class Component {
return alias; return alias;
} }
generate(result: string) { generate(result?: Node[]) {
let js = null; let js = null;
let css = null; let css = null;
@ -298,36 +299,39 @@ export default class Component {
this.file ? `${this.file} ` : `` this.file ? `${this.file} ` : ``
}generated by Svelte v${'__VERSION__'} */`; }generated by Svelte v${'__VERSION__'} */`;
result = result // result = result
.replace(/__svelte:self__/g, this.name) // .replace(/__svelte:self__/g, this.name)
.replace( // .replace(
compile_options.generate === 'ssr' // compile_options.generate === 'ssr'
? /(@+|#+)(\w*(?:-\w*)?)/g // ? /(@+|#+)(\w*(?:-\w*)?)/g
: /(@+)(\w*(?:-\w*)?)/g, // : /(@+)(\w*(?:-\w*)?)/g,
(_match: string, sigil: string, name: string) => { // (_match: string, sigil: string, name: string) => {
if (sigil === '@') { // if (sigil === '@') {
if (name[0] === '_') { // if (name[0] === '_') {
return this.global(name.slice(1)); // return this.global(name.slice(1));
} // }
if (!internal_exports.has(name)) { // if (!internal_exports.has(name)) {
throw new Error( // throw new Error(
`compiler error: this shouldn't happen! generated code is trying to use inexistent internal '${name}'` // `compiler error: this shouldn't happen! generated code is trying to use inexistent internal '${name}'`
); // );
} // }
if (compile_options.dev) { // if (compile_options.dev) {
if (internal_exports.has(`${name}_dev`)) name = `${name}_dev`; // if (internal_exports.has(`${name}_dev`)) name = `${name}_dev`;
else if (internal_exports.has(`${name}Dev`)) // else if (internal_exports.has(`${name}Dev`))
name = `${name}Dev`; // name = `${name}Dev`;
} // }
return this.helper(name); // return this.helper(name);
} // }
return sigil.slice(1) + name; // return sigil.slice(1) + name;
} // }
); // );
const printed = print({ type: 'Program', body: result } as any);
console.log(printed);
const referenced_globals = Array.from( const referenced_globals = Array.from(
this.globals, this.globals,
@ -342,7 +346,7 @@ export default class Component {
})); }));
const module = create_module( const module = create_module(
result, printed.code,
format, format,
name, name,
banner, banner,

@ -1,11 +1,11 @@
import Component from '../../Component'; import Component from '../../Component';
import { walk } from 'estree-walker'; import { walk } from 'estree-walker';
import is_reference from 'is-reference'; import is_reference from 'is-reference';
import { b } from 'code-red';
import flatten_reference from '../../utils/flatten_reference'; import flatten_reference from '../../utils/flatten_reference';
import { create_scopes, Scope, extract_names } from '../../utils/scope'; import { create_scopes, Scope, extract_names } from '../../utils/scope';
import { Node } from '../../../interfaces'; import { Node } from '../../../interfaces';
import { globals , sanitize } from '../../../utils/names'; import { globals , sanitize } from '../../../utils/names';
import deindent from '../../utils/deindent';
import Wrapper from '../../render_dom/wrappers/shared/Wrapper'; import Wrapper from '../../render_dom/wrappers/shared/Wrapper';
import TemplateScope from './TemplateScope'; import TemplateScope from './TemplateScope';
import get_object from '../../utils/get_object'; import get_object from '../../utils/get_object';
@ -79,7 +79,7 @@ export default class Expression {
scope_map: WeakMap<Node, Scope>; scope_map: WeakMap<Node, Scope>;
is_synthetic: boolean; is_synthetic: boolean;
declarations: string[] = []; declarations: Node[] = [];
uses_context = false; uses_context = false;
rendered: string; rendered: string;
@ -364,7 +364,7 @@ export default class Expression {
referenced: true referenced: true
}); });
declarations.push(deindent` declarations.push(b`
function ${name}(${original_params ? '...args' : ''}) { function ${name}(${original_params ? '...args' : ''}) {
return ctx.${name}(ctx${original_params ? ', ...args' : ''}); return ctx.${name}(ctx${original_params ? ', ...args' : ''});
} }
@ -407,7 +407,7 @@ export default class Expression {
if (declarations.length > 0) { if (declarations.length > 0) {
block.maintain_context = true; block.maintain_context = true;
declarations.forEach(declaration => { declarations.forEach(declaration => {
block.builders.init.add_block(declaration); block.chunks.init.push(declaration);
}); });
} }

@ -1,8 +1,8 @@
import CodeBuilder from '../utils/CodeBuilder';
import deindent from '../utils/deindent';
import Renderer from './Renderer'; import Renderer from './Renderer';
import Wrapper from './wrappers/shared/Wrapper'; import Wrapper from './wrappers/shared/Wrapper';
import { escape } from '../utils/stringify'; import { escape } from '../utils/stringify';
import { b, x } from 'code-red';
import { Node } from '../../interfaces';
export interface BlockOptions { export interface BlockOptions {
parent?: Block; parent?: Block;
@ -31,19 +31,19 @@ export default class Block {
bindings: Map<string, { object: string; property: string; snippet: string; store: string; tail: string }>; bindings: Map<string, { object: string; property: string; snippet: string; store: string; tail: string }>;
builders: { chunks: {
init: CodeBuilder; init: Node[];
create: CodeBuilder; create: Node[];
claim: CodeBuilder; claim: Node[];
hydrate: CodeBuilder; hydrate: Node[];
mount: CodeBuilder; mount: Node[];
measure: CodeBuilder; measure: Node[];
fix: CodeBuilder; fix: Node[];
animate: CodeBuilder; animate: Node[];
intro: CodeBuilder; intro: Node[];
update: CodeBuilder; update: Node[];
outro: CodeBuilder; outro: Node[];
destroy: CodeBuilder; destroy: Node[];
}; };
event_listeners: string[] = []; event_listeners: string[] = [];
@ -80,19 +80,19 @@ export default class Block {
this.bindings = options.bindings; this.bindings = options.bindings;
this.builders = { this.chunks = {
init: new CodeBuilder(), init: [],
create: new CodeBuilder(), create: [],
claim: new CodeBuilder(), claim: [],
hydrate: new CodeBuilder(), hydrate: [],
mount: new CodeBuilder(), mount: [],
measure: new CodeBuilder(), measure: [],
fix: new CodeBuilder(), fix: [],
animate: new CodeBuilder(), animate: [],
intro: new CodeBuilder(), intro: [],
update: new CodeBuilder(), update: [],
outro: new CodeBuilder(), outro: [],
destroy: new CodeBuilder(), destroy: [],
}; };
this.has_animation = false; this.has_animation = false;
@ -160,18 +160,18 @@ export default class Block {
no_detach?: boolean no_detach?: boolean
) { ) {
this.add_variable(name); this.add_variable(name);
this.builders.create.add_line(`${name} = ${render_statement};`); this.chunks.create.push(b`${name} = ${render_statement};`);
if (this.renderer.options.hydratable) { if (this.renderer.options.hydratable) {
this.builders.claim.add_line(`${name} = ${claim_statement || render_statement};`); this.chunks.claim.push(b`${name} = ${claim_statement || render_statement};`);
} }
if (parent_node) { if (parent_node) {
this.builders.mount.add_line(`@append(${parent_node}, ${name});`); this.chunks.mount.push(b`@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.chunks.destroy.push(b`@detach(${name});`);
} else { } else {
this.builders.mount.add_line(`@insert(#target, ${name}, anchor);`); this.chunks.mount.push(b`@insert(#target, ${name}, anchor);`);
if (!no_detach) this.builders.destroy.add_conditional('detaching', `@detach(${name});`); if (!no_detach) this.chunks.destroy.push(b`if (detaching) @detach(${name});`);
} }
} }
@ -216,215 +216,222 @@ export default class Block {
return new Block(Object.assign({}, this, { key: null }, options, { parent: this })); return new Block(Object.assign({}, this, { key: null }, options, { parent: this }));
} }
get_contents(local_key?: string) { get_contents(key?: any) {
const { dev } = this.renderer.options; const { dev } = this.renderer.options;
if (this.has_outros) { if (this.has_outros) {
this.add_variable('#current'); this.add_variable('#current');
if (!this.builders.intro.is_empty()) { if (this.chunks.intro.length > 0) {
this.builders.intro.add_line(`#current = true;`); this.chunks.intro.push(b`#current = true;`);
this.builders.mount.add_line(`#current = true;`); this.chunks.mount.push(b`#current = true;`);
} }
if (!this.builders.outro.is_empty()) { if (this.chunks.outro.length > 0) {
this.builders.outro.add_line(`#current = false;`); this.chunks.outro.push(b`#current = false;`);
} }
} }
if (this.autofocus) { if (this.autofocus) {
this.builders.mount.add_line(`${this.autofocus}.focus();`); this.chunks.mount.push(b`${this.autofocus}.focus();`);
} }
this.render_listeners(); this.render_listeners();
const properties = new CodeBuilder(); const properties: Record<string, any> = {};
const method_name = (short: string, long: string) => dev ? `${short}: function ${this.get_unique_name(long)}` : short; const noop = x`noop`;
if (local_key) { properties.key = key
properties.add_block(`key: ${local_key},`); properties.first = this.first;
}
if (this.first) {
properties.add_block(`first: null,`);
this.builders.hydrate.add_line(`this.first = ${this.first};`);
}
if (this.builders.create.is_empty() && this.builders.hydrate.is_empty()) { if (this.chunks.create.length === 0 && this.chunks.hydrate.length === 0) {
properties.add_line(`c: @noop,`); properties.create = noop;
} else { } else {
const hydrate = !this.builders.hydrate.is_empty() && ( const hydrate = this.chunks.hydrate.length > 0 && (
this.renderer.options.hydratable this.renderer.options.hydratable
? `this.h()` ? b`this.h();`
: this.builders.hydrate : this.chunks.hydrate
); );
properties.add_block(deindent` properties.create = b`function create() {
${method_name('c', 'create')}() { ${this.chunks.create}
${this.builders.create}
${hydrate} ${hydrate}
}, }`;
`);
} }
if (this.renderer.options.hydratable || !this.builders.claim.is_empty()) { if (this.renderer.options.hydratable || this.chunks.claim.length > 0) {
if (this.builders.claim.is_empty() && this.builders.hydrate.is_empty()) { if (this.chunks.claim.length === 0 && this.chunks.hydrate.length === 0) {
properties.add_line(`l: @noop,`); properties.claim = noop;
} else { } else {
properties.add_block(deindent` properties.claim = x`function claim(#nodes) {
${method_name('l', 'claim')}(nodes) { ${this.chunks.claim}
${this.builders.claim} ${this.renderer.options.hydratable && this.chunks.hydrate.length > 0 && b`this.h();`}
${this.renderer.options.hydratable && !this.builders.hydrate.is_empty() && `this.h();`} }`;
},
`);
} }
} }
if (this.renderer.options.hydratable && !this.builders.hydrate.is_empty()) { if (this.renderer.options.hydratable && this.chunks.hydrate.length > 0) {
properties.add_block(deindent` properties.hydrate = x`function hydrate() {
${method_name('h', 'hydrate')}() { ${this.chunks.hydrate}
${this.builders.hydrate} }`;
},
`);
} }
if (this.builders.mount.is_empty()) { if (this.chunks.mount.length === 0) {
properties.add_line(`m: @noop,`); properties.mount = noop;
} else { } else {
properties.add_block(deindent` properties.mount = x`function mount(#target, anchor) {
${method_name('m', 'mount')}(#target, anchor) { ${this.chunks.mount}
${this.builders.mount} }`;
},
`);
} }
if (this.has_update_method || this.maintain_context) { if (this.has_update_method || this.maintain_context) {
if (this.builders.update.is_empty() && !this.maintain_context) { if (this.chunks.update.length === 0 && !this.maintain_context) {
properties.add_line(`p: @noop,`); properties.update = noop;
} else { } else {
properties.add_block(deindent` const ctx = this.maintain_context ? x`new_ctx` : x`ctx`;
${method_name('p', 'update')}(changed, ${this.maintain_context ? 'new_ctx' : 'ctx'}) { properties.update = x`function update(#changed, ${ctx}) {
${this.maintain_context && `ctx = new_ctx;`} ${this.maintain_context && b`ctx = ${ctx};`}
${this.builders.update} ${this.chunks.update}
}, }`;
`);
} }
} }
if (this.has_animation) { if (this.has_animation) {
properties.add_block(deindent` properties.measure = x`function measure() {
${method_name('r', 'measure')}() { ${this.chunks.measure}
${this.builders.measure} }`;
},
properties.fix = x`function fix() {
${method_name('f', 'fix')}() { ${this.chunks.fix}
${this.builders.fix} }`;
},
properties.animate = x`function animate() {
${method_name('a', 'animate')}() { ${this.chunks.animate}
${this.builders.animate} }`;
},
`);
} }
if (this.has_intro_method || this.has_outro_method) { if (this.has_intro_method || this.has_outro_method) {
if (this.builders.intro.is_empty()) { if (this.chunks.intro.length === 0) {
properties.add_line(`i: @noop,`); properties.intro = noop;
} else { } else {
properties.add_block(deindent` properties.intro = x`function intro(#local) {
${method_name('i', 'intro')}(#local) { ${this.has_outros && b`if (#current) return;`}
${this.has_outros && `if (#current) return;`} ${this.chunks.intro}
${this.builders.intro} }`;
},
`);
} }
if (this.builders.outro.is_empty()) { if (this.chunks.outro.length === 0) {
properties.add_line(`o: @noop,`); properties.outro = noop;
} else { } else {
properties.add_block(deindent` properties.outro = x`function outro(#local) {
${method_name('o', 'outro')}(#local) { ${this.chunks.outro}
${this.builders.outro} }`;
},
`);
} }
} }
if (this.builders.destroy.is_empty()) { if (this.chunks.destroy.length === 0) {
properties.add_line(`d: @noop`); properties.destroy = noop;
} else { } else {
properties.add_block(deindent` properties.destroy = x`function destroy(detaching) {
${method_name('d', 'destroy')}(detaching) { ${this.chunks.destroy}
${this.builders.destroy} }`;
} }
`);
} const return_value = x`{
key: ${properties.key},
first: ${properties.first},
c: ${properties.create},
l: ${properties.claim},
h: ${properties.hydrate},
m: ${properties.mount},
p: ${properties.update},
r: ${properties.measure},
f: ${properties.fix},
a: ${properties.animate},
i: ${properties.intro},
o: ${properties.outro},
d: ${properties.destroy}
}`;
/* eslint-disable @typescript-eslint/indent,indent */ /* eslint-disable @typescript-eslint/indent,indent */
return deindent` return b`
${this.variables.size > 0 && ${Array.from(this.variables.entries()).map(([init, id]) => {
`var ${Array.from(this.variables.keys()) const id_node = { type: 'Identifier', name: id };
.map(key => { const init_node = { type: 'Identifier', name: init };
const init = this.variables.get(key);
return init !== undefined ? `${key} = ${init}` : key;
})
.join(', ')};`}
${!this.builders.init.is_empty() && this.builders.init} return b`let ${id_node} = ${init_node}`;
})}
${this.chunks.init}
${dev ${dev
? deindent` ? b`
const block = { const block = ${return_value};
${properties}
};
@dispatch_dev("SvelteRegisterBlock", { block, id: ${this.name || 'create_fragment'}.name, type: "${this.type}", source: "${this.comment ? this.comment.replace(/"/g, '\\"') : ''}", ctx }); @dispatch_dev("SvelteRegisterBlock", { block, id: ${this.name || 'create_fragment'}.name, type: "${this.type}", source: "${this.comment ? this.comment.replace(/"/g, '\\"') : ''}", ctx });
return block;` return block;`
: deindent` : b`
return { return ${return_value};`
${properties}
};`
} }
`.replace(/([^{])(#+)(\w*)/g, (_match: string, pre: string, sigil: string, name: string) => { `;
return pre + (sigil === '#' ? this.alias(name) : sigil.slice(1) + name);
});
/* eslint-enable @typescript-eslint/indent,indent */ /* eslint-enable @typescript-eslint/indent,indent */
} }
render() {
const key = this.key && { type: 'Identifier', name: this.get_unique_name('key') };
const id = { type: 'Identifier', name: this.name };
const args: any[] = [x`ctx`];
if (key) args.unshift(key);
// TODO include this.comment
return b`
${this.comment && `// ${escape(this.comment, { only_escape_at_symbol: true })}`}
function ${id}(${args}) {
${this.get_contents(key)}
}
`;
}
render_listeners(chunk: string = '') { render_listeners(chunk: string = '') {
if (this.event_listeners.length > 0) { if (this.event_listeners.length > 0) {
this.add_variable(`#dispose${chunk}`); const name = `#dispose${chunk}`
this.add_variable(name);
const dispose = { type: 'Identifier', name };
if (this.event_listeners.length === 1) { if (this.event_listeners.length === 1) {
this.builders.hydrate.add_line( this.chunks.hydrate.push(
`#dispose${chunk} = ${this.event_listeners[0]};` b`${dispose} = ${this.event_listeners[0]};`
); );
this.builders.destroy.add_line( this.chunks.destroy.push(
`#dispose${chunk}();` b`${dispose}();`
); );
} else { } else {
this.builders.hydrate.add_block(deindent` this.chunks.hydrate.push(b`
#dispose${chunk} = [ ${dispose} = [
${this.event_listeners.join(',\n')} ${this.event_listeners.join(',\n')}
]; ];
`); `);
this.builders.destroy.add_line( this.chunks.destroy.push(
`@run_all(#dispose${chunk});` b`@run_all(${dispose});`
); );
} }
} }
} }
toString() { // toString() {
const local_key = this.key && this.get_unique_name('key'); // const local_key = this.key && this.get_unique_name('key');
return deindent` // return deindent`
${this.comment && `// ${escape(this.comment, { only_escape_at_symbol: true })}`} // ${this.comment && `// ${escape(this.comment, { only_escape_at_symbol: true })}`}
function ${this.name}(${this.key ? `${local_key}, ` : ''}ctx) { // function ${this.name}(${this.key ? `${local_key}, ` : ''}ctx) {
${this.get_contents(local_key)} // ${this.get_contents(local_key)}
} // }
`; // `;
} // }
} }

@ -1,8 +1,7 @@
import Block from './Block'; import Block from './Block';
import { CompileOptions } from '../../interfaces'; import { CompileOptions, Node } from '../../interfaces';
import Component from '../Component'; import Component from '../Component';
import FragmentWrapper from './wrappers/Fragment'; import FragmentWrapper from './wrappers/Fragment';
import CodeBuilder from '../utils/CodeBuilder';
export default class Renderer { export default class Renderer {
component: Component; // TODO Maybe Renderer shouldn't know about Component? component: Component; // TODO Maybe Renderer shouldn't know about Component?
@ -10,7 +9,7 @@ export default class Renderer {
blocks: Array<Block | string> = []; blocks: Array<Block | string> = [];
readonly: Set<string> = new Set(); readonly: Set<string> = new Set();
meta_bindings: CodeBuilder = new CodeBuilder(); // initial values for e.g. window.innerWidth, if there's a <svelte:window> meta tag meta_bindings: Node[] = []; // initial values for e.g. window.innerWidth, if there's a <svelte:window> meta tag
binding_groups: string[] = []; binding_groups: string[] = [];
block: Block; block: Block;

@ -1,6 +1,6 @@
import { b, x } from 'code-red';
import deindent from '../utils/deindent'; import deindent from '../utils/deindent';
import { stringify, escape } from '../utils/stringify'; import { stringify, escape } from '../utils/stringify';
import CodeBuilder from '../utils/CodeBuilder';
import Component from '../Component'; import Component from '../Component';
import Renderer from './Renderer'; import Renderer from './Renderer';
import { CompileOptions } from '../../interfaces'; import { CompileOptions } from '../../interfaces';
@ -22,12 +22,12 @@ export default function dom(
block.has_outro_method = true; block.has_outro_method = true;
// prevent fragment being created twice (#1063) // prevent fragment being created twice (#1063)
if (options.customElement) block.builders.create.add_line(`this.c = @noop;`); if (options.customElement) block.chunks.create.push(b`this.c = @noop;`);
const builder = new CodeBuilder(); const body = [];
if (component.compile_options.dev) { if (component.compile_options.dev) {
builder.add_line(`const ${renderer.file_var} = ${component.file && stringify(component.file, { only_escape_at_symbol: true })};`); body.push(b`const ${renderer.file_var} = ${component.file && stringify(component.file, { only_escape_at_symbol: true })};`);
} }
const css = component.stylesheet.render(options.filename, !options.customElement); const css = component.stylesheet.render(options.filename, !options.customElement);
@ -38,7 +38,7 @@ export default function dom(
const add_css = component.get_unique_name('add_css'); const add_css = component.get_unique_name('add_css');
if (styles && component.compile_options.css !== false && !options.customElement) { if (styles && component.compile_options.css !== false && !options.customElement) {
builder.add_block(deindent` body.push(b`
function ${add_css}() { function ${add_css}() {
var style = @element("style"); var style = @element("style");
style.id = '${component.stylesheet.id}-style'; style.id = '${component.stylesheet.id}-style';
@ -52,13 +52,11 @@ export default function dom(
// TODO the deconflicted names of blocks are reversed... should set them here // TODO the deconflicted names of blocks are reversed... should set them here
const blocks = renderer.blocks.slice().reverse(); const blocks = renderer.blocks.slice().reverse();
blocks.forEach(block => { body.push(...blocks);
builder.add_block(block.toString());
});
if (options.dev && !options.hydratable) { if (options.dev && !options.hydratable) {
block.builders.claim.add_line( block.chunks.claim.push(
'throw new @_Error("options.hydrate only works if the component was compiled with the `hydratable: true` option");' b`throw new @_Error("options.hydrate only works if the component was compiled with the \`hydratable: true\` option");`
); );
} }
@ -77,7 +75,7 @@ export default function dom(
/* eslint-disable @typescript-eslint/indent,indent */ /* eslint-disable @typescript-eslint/indent,indent */
const set = (uses_props || writable_props.length > 0 || component.slots.size > 0) const set = (uses_props || writable_props.length > 0 || component.slots.size > 0)
? deindent` ? x`
${$$props} => { ${$$props} => {
${uses_props && component.invalidate('$$props', `$$props = @assign(@assign({}, $$props), $$new_props)`)} ${uses_props && component.invalidate('$$props', `$$props = @assign(@assign({}, $$props), $$new_props)`)}
${writable_props.map(prop => ${writable_props.map(prop =>
@ -90,7 +88,7 @@ export default function dom(
: null; : null;
/* eslint-enable @typescript-eslint/indent,indent */ /* eslint-enable @typescript-eslint/indent,indent */
const body = []; const accessors = [];
const not_equal = component.component_options.immutable ? `@not_equal` : `@safe_not_equal`; const not_equal = component.component_options.immutable ? `@not_equal` : `@safe_not_equal`;
let dev_props_check; let inject_state; let capture_state; let dev_props_check; let inject_state; let capture_state;
@ -99,13 +97,13 @@ export default function dom(
const variable = component.var_lookup.get(x.name); const variable = component.var_lookup.get(x.name);
if (!variable.writable || component.component_options.accessors) { if (!variable.writable || component.component_options.accessors) {
body.push(deindent` accessors.push(deindent`
get ${x.export_name}() { get ${x.export_name}() {
return ${x.hoistable ? x.name : 'this.$$.ctx.' + x.name}; return ${x.hoistable ? x.name : 'this.$$.ctx.' + x.name};
} }
`); `);
} else if (component.compile_options.dev) { } else if (component.compile_options.dev) {
body.push(deindent` accessors.push(deindent`
get ${x.export_name}() { 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/>'");
} }
@ -114,21 +112,21 @@ export default function dom(
if (component.component_options.accessors) { if (component.component_options.accessors) {
if (variable.writable && !renderer.readonly.has(x.name)) { if (variable.writable && !renderer.readonly.has(x.name)) {
body.push(deindent` accessors.push(deindent`
set ${x.export_name}(${x.name}) { set ${x.export_name}(${x.name}) {
this.$set({ ${x.name === x.export_name ? x.name : `${x.export_name}: ${x.name}`} }); this.$set({ ${x.name === x.export_name ? x.name : `${x.export_name}: ${x.name}`} });
@flush(); @flush();
} }
`); `);
} else if (component.compile_options.dev) { } else if (component.compile_options.dev) {
body.push(deindent` accessors.push(deindent`
set ${x.export_name}(value) { 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) { } else if (component.compile_options.dev) {
body.push(deindent` accessors.push(deindent`
set ${x.export_name}(value) { 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/>'");
} }
@ -141,35 +139,35 @@ export default function dom(
const expected = props.filter(prop => !prop.initialised); const expected = props.filter(prop => !prop.initialised);
if (expected.length) { if (expected.length) {
dev_props_check = deindent` dev_props_check = b`
const { ctx } = this.$$; const { ctx } = this.$$;
const props = ${options.customElement ? `this.attributes` : `options.props || {}`}; const props = ${options.customElement ? `this.attributes` : `options.props || {}`};
${expected.map(prop => deindent` ${expected.map(prop => b`
if (ctx.${prop.name} === undefined && !('${prop.export_name}' in props)) { 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}'");
}`)} }`)}
`; `;
} }
capture_state = (uses_props || writable_props.length > 0) ? deindent` capture_state = (uses_props || writable_props.length > 0) ? x`
() => { () => {
return { ${component.vars.filter(prop => prop.writable).map(prop => prop.name).join(", ")} }; return { ${component.vars.filter(prop => prop.writable).map(prop => prop.name).join(", ")} };
} }
` : deindent` ` : x`
() => { () => {
return {}; return {};
} }
`; `;
const writable_vars = component.vars.filter(variable => !variable.module && variable.writable); const writable_vars = component.vars.filter(variable => !variable.module && variable.writable);
inject_state = (uses_props || writable_vars.length > 0) ? deindent` inject_state = (uses_props || writable_vars.length > 0) ? x`
${$$props} => { ${$$props} => {
${uses_props && component.invalidate('$$props', `$$props = @assign(@assign({}, $$props), $$new_props)`)} ${uses_props && component.invalidate('$$props', `$$props = @assign(@assign({}, $$props), $$new_props)`)}
${writable_vars.map(prop => deindent` ${writable_vars.map(prop => b`
if ('${prop.name}' in $$props) ${component.invalidate(prop.name, `${prop.name} = ${$$props}.${prop.name}`)}; if ('${prop.name}' in $$props) ${component.invalidate(prop.name, `${prop.name} = ${$$props}.${prop.name}`)};
`)} `)}
} }
` : deindent` ` : x`
${$$props} => {} ${$$props} => {}
`; `;
} }
@ -231,7 +229,7 @@ export default function dom(
args.push('$$props', '$$invalidate'); args.push('$$props', '$$invalidate');
} }
builder.add_block(deindent` body.push(b`
function create_fragment(ctx) { function create_fragment(ctx) {
${block.get_contents()} ${block.get_contents()}
} }
@ -288,7 +286,7 @@ export default function dom(
const variable = component.var_lookup.get(store.name.slice(1)); const variable = component.var_lookup.get(store.name.slice(1));
return !variable || variable.hoistable; return !variable || variable.hoistable;
}) })
.map(({ name }) => deindent` .map(({ name }) => b`
${component.compile_options.dev && `@validate_store(${name.slice(1)}, '${name.slice(1)}');`} ${component.compile_options.dev && `@validate_store(${name.slice(1)}, '${name.slice(1)}');`}
@component_subscribe($$self, ${name.slice(1)}, $$value => { ${name} = $$value; $$invalidate('${name}', ${name}); }); @component_subscribe($$self, ${name.slice(1)}, $$value => { ${name} = $$value; $$invalidate('${name}', ${name}); });
`); `);
@ -345,7 +343,7 @@ export default function dom(
let unknown_props_check; let unknown_props_check;
if (component.compile_options.dev && !component.var_lookup.has('$$props') && writable_props.length) { if (component.compile_options.dev && !component.var_lookup.has('$$props') && writable_props.length) {
unknown_props_check = deindent` unknown_props_check = b`
const writable_props = [${writable_props.map(prop => `'${prop.export_name}'`).join(', ')}]; const writable_props = [${writable_props.map(prop => `'${prop.export_name}'`).join(', ')}];
@_Object.keys($$props).forEach(key => { @_Object.keys($$props).forEach(key => {
if (!writable_props.includes(key) && !key.startsWith('$$')) @_console.warn(\`<${component.tag}> was created with unknown prop '\${key}'\`); if (!writable_props.includes(key) && !key.startsWith('$$')) @_console.warn(\`<${component.tag}> was created with unknown prop '\${key}'\`);
@ -353,7 +351,7 @@ export default function dom(
`; `;
} }
builder.add_block(deindent` body.push(b`
function ${definition}(${args.join(', ')}) { function ${definition}(${args.join(', ')}) {
${reactive_store_declarations.length > 0 && `let ${reactive_store_declarations.join(', ')};`} ${reactive_store_declarations.length > 0 && `let ${reactive_store_declarations.join(', ')};`}
@ -379,7 +377,7 @@ export default function dom(
${injected.length && `let ${injected.join(', ')};`} ${injected.length && `let ${injected.join(', ')};`}
${reactive_declarations.length > 0 && deindent` ${reactive_declarations.length > 0 && b`
$$self.$$.update = ($$dirty = { ${Array.from(all_reactive_dependencies).map(n => `${n}: 1`).join(', ')} }) => { $$self.$$.update = ($$dirty = { ${Array.from(all_reactive_dependencies).map(n => `${n}: 1`).join(', ')} }) => {
${reactive_declarations} ${reactive_declarations}
}; };
@ -395,7 +393,7 @@ export default function dom(
const prop_names = `[${props.map(v => JSON.stringify(v.export_name)).join(', ')}]`; const prop_names = `[${props.map(v => JSON.stringify(v.export_name)).join(', ')}]`;
if (options.customElement) { if (options.customElement) {
builder.add_block(deindent` body.push(b`
class ${name} extends @SvelteElement { class ${name} extends @SvelteElement {
constructor(options) { constructor(options) {
super(); super();
@ -411,7 +409,7 @@ export default function dom(
@insert(options.target, this, options.anchor); @insert(options.target, this, options.anchor);
} }
${(props.length > 0 || uses_props) && deindent` ${(props.length > 0 || uses_props) && b`
if (options.props) { if (options.props) {
this.$set(options.props); this.$set(options.props);
@flush(); @flush();
@ -429,14 +427,16 @@ export default function dom(
`); `);
if (component.tag != null) { if (component.tag != null) {
builder.add_block(deindent` body.push(b`
@_customElements.define("${component.tag}", ${name}); @_customElements.define("${component.tag}", ${name});
`); `);
} }
} else { } else {
const superclass = options.dev ? 'SvelteComponentDev' : 'SvelteComponent'; const superclass = options.dev ? 'SvelteComponentDev' : 'SvelteComponent';
builder.add_block(deindent` // TODO add accessors
body.push(b`
class ${name} extends @${superclass} { class ${name} extends @${superclass} {
constructor(options) { constructor(options) {
super(${options.dev && `options`}); super(${options.dev && `options`});
@ -446,11 +446,9 @@ export default function dom(
${dev_props_check} ${dev_props_check}
} }
${body.length > 0 && body.join('\n\n')}
} }
`); `);
} }
return builder.toString(); return body;
} }

@ -3,7 +3,7 @@ import Renderer from '../Renderer';
import Block from '../Block'; import Block from '../Block';
import AwaitBlock from '../../nodes/AwaitBlock'; import AwaitBlock from '../../nodes/AwaitBlock';
import create_debugging_comment from './shared/create_debugging_comment'; import create_debugging_comment from './shared/create_debugging_comment';
import deindent from '../../utils/deindent'; import { b } from 'code-red';
import FragmentWrapper from './Fragment'; import FragmentWrapper from './Fragment';
import PendingBlock from '../../nodes/PendingBlock'; import PendingBlock from '../../nodes/PendingBlock';
import ThenBlock from '../../nodes/ThenBlock'; import ThenBlock from '../../nodes/ThenBlock';
@ -147,22 +147,22 @@ export default class AwaitBlockWrapper extends Wrapper {
this.pending.block.has_outro_method && `blocks: [,,,]` this.pending.block.has_outro_method && `blocks: [,,,]`
].filter(Boolean); ].filter(Boolean);
block.builders.init.add_block(deindent` block.chunks.init.push(b`
let ${info} = { let ${info} = {
${info_props.join(',\n')} ${info_props.join(',\n')}
}; };
`); `);
block.builders.init.add_block(deindent` block.chunks.init.push(b`
@handle_promise(${promise} = ${snippet}, ${info}); @handle_promise(${promise} = ${snippet}, ${info});
`); `);
block.builders.create.add_block(deindent` block.chunks.create.push(b`
${info}.block.c(); ${info}.block.c();
`); `);
if (parent_nodes && this.renderer.options.hydratable) { if (parent_nodes && this.renderer.options.hydratable) {
block.builders.claim.add_block(deindent` block.chunks.claim.push(b`
${info}.block.l(${parent_nodes}); ${info}.block.l(${parent_nodes});
`); `);
} }
@ -172,14 +172,14 @@ export default class AwaitBlockWrapper extends Wrapper {
const has_transitions = this.pending.block.has_intro_method || this.pending.block.has_outro_method; const has_transitions = this.pending.block.has_intro_method || this.pending.block.has_outro_method;
block.builders.mount.add_block(deindent` block.chunks.mount.push(b`
${info}.block.m(${initial_mount_node}, ${info}.anchor = ${anchor_node}); ${info}.block.m(${initial_mount_node}, ${info}.anchor = ${anchor_node});
${info}.mount = () => ${update_mount_node}; ${info}.mount = () => ${update_mount_node};
${info}.anchor = ${anchor}; ${info}.anchor = ${anchor};
`); `);
if (has_transitions) { if (has_transitions) {
block.builders.intro.add_line(`@transition_in(${info}.block);`); block.chunks.intro.push(b`@transition_in(${info}.block);`);
} }
const conditions = []; const conditions = [];
@ -195,12 +195,12 @@ export default class AwaitBlockWrapper extends Wrapper {
`@handle_promise(${promise}, ${info})` `@handle_promise(${promise}, ${info})`
); );
block.builders.update.add_line( block.chunks.update.push(
`${info}.ctx = ctx;` b`${info}.ctx = ctx;`
); );
if (this.pending.block.has_update_method) { if (this.pending.block.has_update_method) {
block.builders.update.add_block(deindent` block.chunks.update.push(b`
if (${conditions.join(' && ')}) { if (${conditions.join(' && ')}) {
// nothing // nothing
} else { } else {
@ -208,20 +208,20 @@ export default class AwaitBlockWrapper extends Wrapper {
} }
`); `);
} else { } else {
block.builders.update.add_block(deindent` block.chunks.update.push(b`
${conditions.join(' && ')} ${conditions.join(' && ')}
`); `);
} }
} else { } else {
if (this.pending.block.has_update_method) { if (this.pending.block.has_update_method) {
block.builders.update.add_block(deindent` block.chunks.update.push(b`
${info}.block.p(changed, @assign(@assign({}, ctx), ${info}.resolved)); ${info}.block.p(changed, @assign(@assign({}, ctx), ${info}.resolved));
`); `);
} }
} }
if (this.pending.block.has_outro_method) { if (this.pending.block.has_outro_method) {
block.builders.outro.add_block(deindent` block.chunks.outro.push(b`
for (let #i = 0; #i < 3; #i += 1) { for (let #i = 0; #i < 3; #i += 1) {
const block = ${info}.blocks[#i]; const block = ${info}.blocks[#i];
@transition_out(block); @transition_out(block);
@ -229,7 +229,7 @@ export default class AwaitBlockWrapper extends Wrapper {
`); `);
} }
block.builders.destroy.add_block(deindent` block.chunks.destroy.push(b`
${info}.block.d(${parent_node ? '' : 'detaching'}); ${info}.block.d(${parent_node ? '' : 'detaching'});
${info}.token = null; ${info}.token = null;
${info} = null; ${info} = null;

@ -1,6 +1,6 @@
import Block from '../Block'; import Block from '../Block';
import Wrapper from './shared/Wrapper'; import Wrapper from './shared/Wrapper';
import deindent from '../../utils/deindent'; import { b } from 'code-red';
import Body from '../../nodes/Body'; import Body from '../../nodes/Body';
export default class BodyWrapper extends Wrapper { export default class BodyWrapper extends Wrapper {
@ -10,11 +10,11 @@ export default class BodyWrapper extends Wrapper {
this.node.handlers.forEach(handler => { this.node.handlers.forEach(handler => {
const snippet = handler.render(block); const snippet = handler.render(block);
block.builders.init.add_block(deindent` block.chunks.init.push(b`
@_document.body.addEventListener("${handler.name}", ${snippet}); @_document.body.addEventListener("${handler.name}", ${snippet});
`); `);
block.builders.destroy.add_block(deindent` block.chunks.destroy.push(b`
@_document.body.removeEventListener("${handler.name}", ${snippet}); @_document.body.removeEventListener("${handler.name}", ${snippet});
`); `);
}); });

@ -3,7 +3,7 @@ import Wrapper from './shared/Wrapper';
import Block from '../Block'; import Block from '../Block';
import DebugTag from '../../nodes/DebugTag'; import DebugTag from '../../nodes/DebugTag';
import add_to_set from '../../utils/add_to_set'; import add_to_set from '../../utils/add_to_set';
import deindent from '../../utils/deindent'; import { b } from 'code-red';
export default class DebugTagWrapper extends Wrapper { export default class DebugTagWrapper extends Wrapper {
node: DebugTag; node: DebugTag;
@ -25,17 +25,17 @@ export default class DebugTagWrapper extends Wrapper {
if (!renderer.options.dev) return; if (!renderer.options.dev) return;
const { code, var_lookup } = component; const { var_lookup } = component;
if (this.node.expressions.length === 0) { if (this.node.expressions.length === 0) {
// Debug all // Debug all
code.overwrite(this.node.start + 1, this.node.start + 7, 'debugger', { // code.overwrite(this.node.start + 1, this.node.start + 7, 'debugger', {
storeName: true // storeName: true
}); // });
const statement = `[✂${this.node.start + 1}-${this.node.start + 7}✂];`; // const statement = `[✂${this.node.start + 1}-${this.node.start + 7}✂];`;
block.builders.create.add_line(statement); block.chunks.create.push(b`debugger`);
block.builders.update.add_line(statement); block.chunks.update.push(b`debugger`);
} else { } else {
const { code } = component; const { code } = component;
code.overwrite(this.node.start + 1, this.node.start + 7, 'log', { code.overwrite(this.node.start + 1, this.node.start + 7, 'log', {
@ -59,7 +59,7 @@ export default class DebugTagWrapper extends Wrapper {
.join(', '); .join(', ');
const logged_identifiers = this.node.expressions.map(e => e.node.name).join(', '); const logged_identifiers = this.node.expressions.map(e => e.node.name).join(', ');
block.builders.update.add_block(deindent` block.chunks.update.push(b`
if (${condition}) { if (${condition}) {
const { ${ctx_identifiers} } = ctx; const { ${ctx_identifiers} } = ctx;
@_console.${log}({ ${logged_identifiers} }); @_console.${log}({ ${logged_identifiers} });
@ -67,7 +67,7 @@ export default class DebugTagWrapper extends Wrapper {
} }
`); `);
block.builders.create.add_block(deindent` block.chunks.create.push(b`
{ {
const { ${ctx_identifiers} } = ctx; const { ${ctx_identifiers} } = ctx;
@_console.${log}({ ${logged_identifiers} }); @_console.${log}({ ${logged_identifiers} });

@ -4,7 +4,7 @@ import Wrapper from './shared/Wrapper';
import create_debugging_comment from './shared/create_debugging_comment'; import create_debugging_comment from './shared/create_debugging_comment';
import EachBlock from '../../nodes/EachBlock'; import EachBlock from '../../nodes/EachBlock';
import FragmentWrapper from './Fragment'; import FragmentWrapper from './Fragment';
import deindent from '../../utils/deindent'; import { b } from 'code-red';
import ElseBlock from '../../nodes/ElseBlock'; import ElseBlock from '../../nodes/ElseBlock';
import { attach_head } from '../../utils/tail'; import { attach_head } from '../../utils/tail';
@ -188,9 +188,9 @@ export default class EachBlockWrapper extends Wrapper {
const snippet = this.node.expression.render(block); const snippet = this.node.expression.render(block);
block.builders.init.add_line(`let ${this.vars.each_block_value} = ${snippet};`); block.chunks.init.push(b`let ${this.vars.each_block_value} = ${snippet};`);
renderer.blocks.push(deindent` renderer.blocks.push(b`
function ${this.vars.get_each_context}(ctx, list, i) { function ${this.vars.get_each_context}(ctx, list, i) {
const child_ctx = @_Object.create(ctx); const child_ctx = @_Object.create(ctx);
${this.context_props} ${this.context_props}
@ -223,7 +223,7 @@ export default class EachBlockWrapper extends Wrapper {
} }
if (this.block.has_intro_method || this.block.has_outro_method) { if (this.block.has_intro_method || this.block.has_outro_method) {
block.builders.intro.add_block(deindent` block.chunks.intro.push(b`
for (let #i = 0; #i < ${this.vars.data_length}; #i += 1) { for (let #i = 0; #i < ${this.vars.data_length}; #i += 1) {
@transition_in(${this.vars.iterations}[#i]); @transition_in(${this.vars.iterations}[#i]);
} }
@ -242,24 +242,24 @@ export default class EachBlockWrapper extends Wrapper {
if (this.else) { if (this.else) {
const each_block_else = component.get_unique_name(`${this.var}_else`); const each_block_else = component.get_unique_name(`${this.var}_else`);
block.builders.init.add_line(`let ${each_block_else} = null;`); block.chunks.init.push(b`let ${each_block_else} = null;`);
// TODO neaten this up... will end up with an empty line in the block // TODO neaten this up... will end up with an empty line in the block
block.builders.init.add_block(deindent` block.chunks.init.push(b`
if (!${this.vars.data_length}) { if (!${this.vars.data_length}) {
${each_block_else} = ${this.else.block.name}(ctx); ${each_block_else} = ${this.else.block.name}(ctx);
${each_block_else}.c(); ${each_block_else}.c();
} }
`); `);
block.builders.mount.add_block(deindent` block.chunks.mount.push(b`
if (${each_block_else}) { if (${each_block_else}) {
${each_block_else}.m(${initial_mount_node}, ${initial_anchor_node}); ${each_block_else}.m(${initial_mount_node}, ${initial_anchor_node});
} }
`); `);
if (this.else.block.has_update_method) { if (this.else.block.has_update_method) {
block.builders.update.add_block(deindent` block.chunks.update.push(b`
if (!${this.vars.data_length} && ${each_block_else}) { if (!${this.vars.data_length} && ${each_block_else}) {
${each_block_else}.p(changed, ctx); ${each_block_else}.p(changed, ctx);
} else if (!${this.vars.data_length}) { } else if (!${this.vars.data_length}) {
@ -272,7 +272,7 @@ export default class EachBlockWrapper extends Wrapper {
} }
`); `);
} else { } else {
block.builders.update.add_block(deindent` block.chunks.update.push(b`
if (${this.vars.data_length}) { if (${this.vars.data_length}) {
if (${each_block_else}) { if (${each_block_else}) {
${each_block_else}.d(1); ${each_block_else}.d(1);
@ -286,7 +286,7 @@ export default class EachBlockWrapper extends Wrapper {
`); `);
} }
block.builders.destroy.add_block(deindent` block.chunks.destroy.push(b`
if (${each_block_else}) ${each_block_else}.d(${parent_node ? '' : 'detaching'}); if (${each_block_else}) ${each_block_else}.d(${parent_node ? '' : 'detaching'});
`); `);
} }
@ -342,7 +342,7 @@ export default class EachBlockWrapper extends Wrapper {
); );
} }
block.builders.init.add_block(deindent` block.chunks.init.push(b`
const ${get_key} = ctx => ${ const ${get_key} = ctx => ${
// @ts-ignore todo: probably error // @ts-ignore todo: probably error
this.node.key.render()}; this.node.key.render()};
@ -354,21 +354,21 @@ export default class EachBlockWrapper extends Wrapper {
} }
`); `);
block.builders.create.add_block(deindent` block.chunks.create.push(b`
for (let #i = 0; #i < ${view_length}; #i += 1) { for (let #i = 0; #i < ${view_length}; #i += 1) {
${iterations}[#i].c(); ${iterations}[#i].c();
} }
`); `);
if (parent_nodes && this.renderer.options.hydratable) { if (parent_nodes && this.renderer.options.hydratable) {
block.builders.claim.add_block(deindent` block.chunks.claim.push(b`
for (let #i = 0; #i < ${view_length}; #i += 1) { for (let #i = 0; #i < ${view_length}; #i += 1) {
${iterations}[#i].l(${parent_nodes}); ${iterations}[#i].l(${parent_nodes});
} }
`); `);
} }
block.builders.mount.add_block(deindent` block.chunks.mount.push(b`
for (let #i = 0; #i < ${view_length}; #i += 1) { for (let #i = 0; #i < ${view_length}; #i += 1) {
${iterations}[#i].m(${initial_mount_node}, ${initial_anchor_node}); ${iterations}[#i].m(${initial_mount_node}, ${initial_anchor_node});
} }
@ -384,7 +384,7 @@ export default class EachBlockWrapper extends Wrapper {
? `@outro_and_destroy_block` ? `@outro_and_destroy_block`
: `@destroy_block`; : `@destroy_block`;
block.builders.update.add_block(deindent` block.chunks.update.push(b`
const ${this.vars.each_block_value} = ${snippet}; const ${this.vars.each_block_value} = ${snippet};
${this.block.has_outros && `@group_outros();`} ${this.block.has_outros && `@group_outros();`}
@ -395,14 +395,14 @@ export default class EachBlockWrapper extends Wrapper {
`); `);
if (this.block.has_outros) { if (this.block.has_outros) {
block.builders.outro.add_block(deindent` block.chunks.outro.push(b`
for (let #i = 0; #i < ${view_length}; #i += 1) { for (let #i = 0; #i < ${view_length}; #i += 1) {
@transition_out(${iterations}[#i]); @transition_out(${iterations}[#i]);
} }
`); `);
} }
block.builders.destroy.add_block(deindent` block.chunks.destroy.push(b`
for (let #i = 0; #i < ${view_length}; #i += 1) { for (let #i = 0; #i < ${view_length}; #i += 1) {
${iterations}[#i].d(${parent_node ? '' : 'detaching'}); ${iterations}[#i].d(${parent_node ? '' : 'detaching'});
} }
@ -435,7 +435,7 @@ export default class EachBlockWrapper extends Wrapper {
view_length view_length
} = this.vars; } = this.vars;
block.builders.init.add_block(deindent` block.chunks.init.push(b`
let ${iterations} = []; let ${iterations} = [];
for (let #i = 0; #i < ${data_length}; #i += 1) { for (let #i = 0; #i < ${data_length}; #i += 1) {
@ -443,21 +443,21 @@ export default class EachBlockWrapper extends Wrapper {
} }
`); `);
block.builders.create.add_block(deindent` block.chunks.create.push(b`
for (let #i = 0; #i < ${view_length}; #i += 1) { for (let #i = 0; #i < ${view_length}; #i += 1) {
${iterations}[#i].c(); ${iterations}[#i].c();
} }
`); `);
if (parent_nodes && this.renderer.options.hydratable) { if (parent_nodes && this.renderer.options.hydratable) {
block.builders.claim.add_block(deindent` block.chunks.claim.push(b`
for (let #i = 0; #i < ${view_length}; #i += 1) { for (let #i = 0; #i < ${view_length}; #i += 1) {
${iterations}[#i].l(${parent_nodes}); ${iterations}[#i].l(${parent_nodes});
} }
`); `);
} }
block.builders.mount.add_block(deindent` block.chunks.mount.push(b`
for (let #i = 0; #i < ${view_length}; #i += 1) { for (let #i = 0; #i < ${view_length}; #i += 1) {
${iterations}[#i].m(${initial_mount_node}, ${initial_anchor_node}); ${iterations}[#i].m(${initial_mount_node}, ${initial_anchor_node});
} }
@ -477,7 +477,7 @@ export default class EachBlockWrapper extends Wrapper {
if (condition !== '') { if (condition !== '') {
const for_loop_body = this.block.has_update_method const for_loop_body = this.block.has_update_method
? deindent` ? b`
if (${iterations}[#i]) { if (${iterations}[#i]) {
${iterations}[#i].p(changed, child_ctx); ${iterations}[#i].p(changed, child_ctx);
${has_transitions && `@transition_in(${this.vars.iterations}[#i], 1);`} ${has_transitions && `@transition_in(${this.vars.iterations}[#i], 1);`}
@ -489,7 +489,7 @@ export default class EachBlockWrapper extends Wrapper {
} }
` `
: has_transitions : has_transitions
? deindent` ? b`
if (${iterations}[#i]) { if (${iterations}[#i]) {
@transition_in(${this.vars.iterations}[#i], 1); @transition_in(${this.vars.iterations}[#i], 1);
} else { } else {
@ -499,7 +499,7 @@ export default class EachBlockWrapper extends Wrapper {
${iterations}[#i].m(${update_mount_node}, ${update_anchor_node}); ${iterations}[#i].m(${update_mount_node}, ${update_anchor_node});
} }
` `
: deindent` : b`
if (!${iterations}[#i]) { if (!${iterations}[#i]) {
${iterations}[#i] = ${create_each_block}(child_ctx); ${iterations}[#i] = ${create_each_block}(child_ctx);
${iterations}[#i].c(); ${iterations}[#i].c();
@ -514,12 +514,12 @@ export default class EachBlockWrapper extends Wrapper {
if (this.block.has_outros) { if (this.block.has_outros) {
const out = block.get_unique_name('out'); const out = block.get_unique_name('out');
block.builders.init.add_block(deindent` block.chunks.init.push(b`
const ${out} = i => @transition_out(${iterations}[i], 1, 1, () => { const ${out} = i => @transition_out(${iterations}[i], 1, 1, () => {
${iterations}[i] = null; ${iterations}[i] = null;
}); });
`); `);
remove_old_blocks = deindent` remove_old_blocks = b`
@group_outros(); @group_outros();
for (#i = ${this.vars.each_block_value}.${length}; #i < ${view_length}; #i += 1) { for (#i = ${this.vars.each_block_value}.${length}; #i < ${view_length}; #i += 1) {
${out}(#i); ${out}(#i);
@ -527,7 +527,7 @@ export default class EachBlockWrapper extends Wrapper {
@check_outros(); @check_outros();
`; `;
} else { } else {
remove_old_blocks = deindent` remove_old_blocks = b`
for (${this.block.has_update_method ? `` : `#i = ${this.vars.each_block_value}.${length}`}; #i < ${this.block.has_update_method ? view_length : '#old_length'}; #i += 1) { for (${this.block.has_update_method ? `` : `#i = ${this.vars.each_block_value}.${length}`}; #i < ${this.block.has_update_method ? view_length : '#old_length'}; #i += 1) {
${iterations}[#i].d(1); ${iterations}[#i].d(1);
} }
@ -537,7 +537,7 @@ export default class EachBlockWrapper extends Wrapper {
// We declare `i` as block scoped here, as the `remove_old_blocks` code // We declare `i` as block scoped here, as the `remove_old_blocks` code
// may rely on continuing where this iteration stopped. // may rely on continuing where this iteration stopped.
const update = deindent` const update = b`
${!this.block.has_update_method && `const #old_length = ${this.vars.each_block_value}.length;`} ${!this.block.has_update_method && `const #old_length = ${this.vars.each_block_value}.length;`}
${this.vars.each_block_value} = ${snippet}; ${this.vars.each_block_value} = ${snippet};
@ -551,7 +551,7 @@ export default class EachBlockWrapper extends Wrapper {
${remove_old_blocks} ${remove_old_blocks}
`; `;
block.builders.update.add_block(deindent` block.chunks.update.push(b`
if (${condition}) { if (${condition}) {
${update} ${update}
} }
@ -559,7 +559,7 @@ export default class EachBlockWrapper extends Wrapper {
} }
if (this.block.has_outros) { if (this.block.has_outros) {
block.builders.outro.add_block(deindent` block.chunks.outro.push(b`
${iterations} = ${iterations}.filter(@_Boolean); ${iterations} = ${iterations}.filter(@_Boolean);
for (let #i = 0; #i < ${view_length}; #i += 1) { for (let #i = 0; #i < ${view_length}; #i += 1) {
@transition_out(${iterations}[#i]); @transition_out(${iterations}[#i]);
@ -567,6 +567,6 @@ export default class EachBlockWrapper extends Wrapper {
`); `);
} }
block.builders.destroy.add_block(`@destroy_each(${iterations}, detaching);`); block.chunks.destroy.push(b`@destroy_each(${iterations}, detaching);`);
} }
} }

@ -3,7 +3,7 @@ import Block from '../../Block';
import fix_attribute_casing from './fix_attribute_casing'; import fix_attribute_casing from './fix_attribute_casing';
import ElementWrapper from './index'; import ElementWrapper from './index';
import { stringify } from '../../../utils/stringify'; import { stringify } from '../../../utils/stringify';
import deindent from '../../../utils/deindent'; import { b } from 'code-red';
import Expression from '../../../nodes/shared/Expression'; import Expression from '../../../nodes/shared/Expression';
import Text from '../../../nodes/Text'; import Text from '../../../nodes/Text';
@ -105,8 +105,8 @@ export default class AttributeWrapper {
const init = should_cache ? `${last} = ${value}` : value; const init = should_cache ? `${last} = ${value}` : value;
if (is_legacy_input_type) { if (is_legacy_input_type) {
block.builders.hydrate.add_line( block.chunks.hydrate.push(
`@set_input_type(${element.var}, ${init});` b`@set_input_type(${element.var}, ${init});`
); );
updater = `@set_input_type(${element.var}, ${should_cache ? last : value});`; updater = `@set_input_type(${element.var}, ${should_cache ? last : value});`;
} else if (is_select_value_attribute) { } else if (is_select_value_attribute) {
@ -116,15 +116,15 @@ export default class AttributeWrapper {
const option = block.get_unique_name('option'); const option = block.get_unique_name('option');
const if_statement = is_multiple_select const if_statement = is_multiple_select
? deindent` ? b`
${option}.selected = ~${last}.indexOf(${option}.__value);` ${option}.selected = ~${last}.indexOf(${option}.__value);`
: deindent` : b`
if (${option}.__value === ${last}) { if (${option}.__value === ${last}) {
${option}.selected = true; ${option}.selected = true;
break; break;
}`; }`;
updater = deindent` updater = b`
for (var ${i} = 0; ${i} < ${element.var}.options.length; ${i} += 1) { for (var ${i} = 0; ${i} < ${element.var}.options.length; ${i} += 1) {
var ${option} = ${element.var}.options[${i}]; var ${option} = ${element.var}.options[${i}];
@ -132,20 +132,20 @@ export default class AttributeWrapper {
} }
`; `;
block.builders.mount.add_block(deindent` block.chunks.mount.push(b`
${last} = ${value}; ${last} = ${value};
${updater} ${updater}
`); `);
} else if (property_name) { } else if (property_name) {
block.builders.hydrate.add_line( block.chunks.hydrate.push(
`${element.var}.${property_name} = ${init};` b`${element.var}.${property_name} = ${init};`
); );
updater = block.renderer.options.dev updater = block.renderer.options.dev
? `@prop_dev(${element.var}, "${property_name}", ${should_cache ? last : value});` ? `@prop_dev(${element.var}, "${property_name}", ${should_cache ? last : value});`
: `${element.var}.${property_name} = ${should_cache ? last : value};`; : `${element.var}.${property_name} = ${should_cache ? last : value};`;
} else { } else {
block.builders.hydrate.add_line( block.chunks.hydrate.push(
`${method}(${element.var}, "${name}", ${init});` b`${method}(${element.var}, "${name}", ${init});`
); );
updater = `${method}(${element.var}, "${name}", ${should_cache ? last : value});`; updater = `${method}(${element.var}, "${name}", ${should_cache ? last : value});`;
} }
@ -161,22 +161,19 @@ export default class AttributeWrapper {
? (dependencies.length ? `(${changed_check}) && ${update_cached_value}` : update_cached_value) ? (dependencies.length ? `(${changed_check}) && ${update_cached_value}` : update_cached_value)
: changed_check; : changed_check;
block.builders.update.add_conditional( block.chunks.update.push(b`if (${condition}) ${updater}`);
condition,
updater
);
} else { } else {
const value = this.node.get_value(block); const value = this.node.get_value(block);
const statement = ( const statement = (
is_legacy_input_type is_legacy_input_type
? `@set_input_type(${element.var}, ${value});` ? b`@set_input_type(${element.var}, ${value});`
: property_name : property_name
? `${element.var}.${property_name} = ${value};` ? b`${element.var}.${property_name} = ${value};`
: `${method}(${element.var}, "${name}", ${value === true ? '""' : value});` : b`${method}(${element.var}, "${name}", ${value === true ? '""' : value});`
); );
block.builders.hydrate.add_line(statement); block.chunks.hydrate.push(statement);
// special case autofocus. has to be handled in a bit of a weird way // special case autofocus. has to be handled in a bit of a weird way
if (this.node.is_true && name === 'autofocus') { if (this.node.is_true && name === 'autofocus') {
@ -185,10 +182,10 @@ export default class AttributeWrapper {
} }
if (is_indirectly_bound_value) { if (is_indirectly_bound_value) {
const update_value = `${element.var}.value = ${element.var}.__value;`; const update_value = b`${element.var}.value = ${element.var}.__value;`;
block.builders.hydrate.add_line(update_value); block.chunks.hydrate.push(update_value);
if (this.node.get_dependencies().length > 0) block.builders.update.add_line(update_value); if (this.node.get_dependencies().length > 0) block.chunks.update.push(update_value);
} }
} }

@ -1,3 +1,4 @@
import { b } from 'code-red';
import Binding from '../../../nodes/Binding'; import Binding from '../../../nodes/Binding';
import ElementWrapper from '../Element'; import ElementWrapper from '../Element';
import get_object from '../../../utils/get_object'; import get_object from '../../../utils/get_object';
@ -123,12 +124,12 @@ export default class BindingWrapper {
{ {
const binding_group = get_binding_group(parent.renderer, this.node.expression.node); const binding_group = get_binding_group(parent.renderer, this.node.expression.node);
block.builders.hydrate.add_line( block.chunks.hydrate.push(
`ctx.$$binding_groups[${binding_group}].push(${parent.var});` b`ctx.$$binding_groups[${binding_group}].push(${parent.var});`
); );
block.builders.destroy.add_line( block.chunks.destroy.push(
`ctx.$$binding_groups[${binding_group}].splice(ctx.$$binding_groups[${binding_group}].indexOf(${parent.var}), 1);` b`ctx.$$binding_groups[${binding_group}].splice(ctx.$$binding_groups[${binding_group}].indexOf(${parent.var}), 1);`
); );
break; break;
} }
@ -154,7 +155,7 @@ export default class BindingWrapper {
block.add_variable(last, 'true'); block.add_variable(last, 'true');
update_conditions.push(`${last} !== (${last} = ${this.snippet})`); update_conditions.push(`${last} !== (${last} = ${this.snippet})`);
update_dom = `${parent.var}[${last} ? "pause" : "play"]();`; update_dom = b`${parent.var}[${last} ? "pause" : "play"]();`;
break; break;
} }
@ -165,15 +166,15 @@ export default class BindingWrapper {
} }
if (update_dom) { if (update_dom) {
block.builders.update.add_line( block.chunks.update.push(
update_conditions.length ? `if (${update_conditions.join(' && ')}) ${update_dom}` : update_dom update_conditions.length ? b`if (${update_conditions.join(' && ')}) ${update_dom}` : update_dom
); );
} }
if (this.node.name === 'innerHTML' || this.node.name === 'textContent') { if (this.node.name === 'innerHTML' || this.node.name === 'textContent') {
block.builders.mount.add_block(`if (${this.snippet} !== void 0) ${update_dom}`); block.chunks.mount.push(b`if (${this.snippet} !== void 0) ${update_dom}`);
} else if (!/(currentTime|paused)/.test(this.node.name)) { } else if (!/(currentTime|paused)/.test(this.node.name)) {
block.builders.mount.add_block(update_dom); block.chunks.mount.push(update_dom);
} }
} }
} }
@ -194,25 +195,25 @@ function get_dom_updater(
if (node.name === 'select') { if (node.name === 'select') {
return node.get_static_attribute_value('multiple') === true ? return node.get_static_attribute_value('multiple') === true ?
`@select_options(${element.var}, ${binding.snippet})` : b`@select_options(${element.var}, ${binding.snippet})` :
`@select_option(${element.var}, ${binding.snippet})`; b`@select_option(${element.var}, ${binding.snippet})`;
} }
if (binding.node.name === 'group') { if (binding.node.name === 'group') {
const type = node.get_static_attribute_value('type'); const type = node.get_static_attribute_value('type');
const condition = type === 'checkbox' const condition = type === 'checkbox'
? `~${binding.snippet}.indexOf(${element.var}.__value)` ? b`~${binding.snippet}.indexOf(${element.var}.__value)`
: `${element.var}.__value === ${binding.snippet}`; : b`${element.var}.__value === ${binding.snippet}`;
return `${element.var}.checked = ${condition};`; return `${element.var}.checked = ${condition};`;
} }
if (binding.node.name === 'value') { if (binding.node.name === 'value') {
return `@set_input_value(${element.var}, ${binding.snippet});`; return b`@set_input_value(${element.var}, ${binding.snippet});`;
} }
return `${element.var}.${binding.node.name} = ${binding.snippet};`; return b`${element.var}.${binding.node.name} = ${binding.snippet};`;
} }
function get_binding_group(renderer: Renderer, value: Node) { function get_binding_group(renderer: Renderer, value: Node) {

@ -1,3 +1,4 @@
import { b } from 'code-red';
import Attribute from '../../../nodes/Attribute'; import Attribute from '../../../nodes/Attribute';
import Block from '../../Block'; import Block from '../../Block';
import AttributeWrapper from './Attribute'; import AttributeWrapper from './Attribute';
@ -49,17 +50,18 @@ export default class StyleAttributeWrapper extends AttributeWrapper {
dependencies.map(dependency => `changed.${dependency}`).join(' || ') dependencies.map(dependency => `changed.${dependency}`).join(' || ')
); );
block.builders.update.add_conditional( block.chunks.update.push(
condition, b`if (${condition}) {
`@set_style(${this.parent.var}, "${prop.key}", ${value}${prop.important ? ', 1' : ''});` @set_style(${this.parent.var}, "${prop.key}", ${value}${prop.important ? ', 1' : ''});
}`
); );
} }
} else { } else {
value = stringify((prop.value[0] as Text).data); value = stringify((prop.value[0] as Text).data);
} }
block.builders.hydrate.add_line( block.chunks.hydrate.push(
`@set_style(${this.parent.var}, "${prop.key}", ${value}${prop.important ? ', 1' : ''});` b`@set_style(${this.parent.var}, "${prop.key}", ${value}${prop.important ? ', 1' : ''});`
); );
}); });
} }

@ -7,7 +7,7 @@ import FragmentWrapper from '../Fragment';
import { stringify, escape_html, escape } from '../../../utils/stringify'; import { stringify, escape_html, escape } from '../../../utils/stringify';
import TextWrapper from '../Text'; import TextWrapper from '../Text';
import fix_attribute_casing from './fix_attribute_casing'; import fix_attribute_casing from './fix_attribute_casing';
import deindent from '../../../utils/deindent'; import { b, x } from 'code-red';
import { namespaces } from '../../../../utils/namespaces'; import { namespaces } from '../../../../utils/namespaces';
import AttributeWrapper from './Attribute'; import AttributeWrapper from './Attribute';
import StyleAttributeWrapper from './StyleAttribute'; import StyleAttributeWrapper from './StyleAttribute';
@ -250,45 +250,45 @@ export default class ElementWrapper extends Wrapper {
block.add_variable(node); block.add_variable(node);
const render_statement = this.get_render_statement(); const render_statement = this.get_render_statement();
block.builders.create.add_line( block.chunks.create.push(
`${node} = ${render_statement};` b`${node} = ${render_statement};`
); );
if (renderer.options.hydratable) { if (renderer.options.hydratable) {
if (parent_nodes) { if (parent_nodes) {
block.builders.claim.add_block(deindent` block.chunks.claim.push(b`
${node} = ${this.get_claim_statement(parent_nodes)}; ${node} = ${this.get_claim_statement(parent_nodes)};
var ${nodes} = @children(${this.node.name === 'template' ? `${node}.content` : node}); var ${nodes} = @children(${this.node.name === 'template' ? `${node}.content` : node});
`); `);
} else { } else {
block.builders.claim.add_line( block.chunks.claim.push(
`${node} = ${render_statement};` b`${node} = ${render_statement};`
); );
} }
} }
if (parent_node) { if (parent_node) {
block.builders.mount.add_line( block.chunks.mount.push(
`@append(${parent_node}, ${node});` b`@append(${parent_node}, ${node});`
); );
if (parent_node === '@_document.head') { if (parent_node === '@_document.head') {
block.builders.destroy.add_line(`@detach(${node});`); block.chunks.destroy.push(b`@detach(${node});`);
} }
} else { } else {
block.builders.mount.add_line(`@insert(#target, ${node}, anchor);`); block.chunks.mount.push(b`@insert(#target, ${node}, anchor);`);
// TODO we eventually need to consider what happens to elements // TODO we eventually need to consider what happens to elements
// that belong to the same outgroup as an outroing element... // that belong to the same outgroup as an outroing element...
block.builders.destroy.add_conditional('detaching', `@detach(${node});`); block.chunks.destroy.push(b`if (detaching) @detach(${node});`);
} }
// insert static children with textContent or innerHTML // insert static children with textContent or innerHTML
if (!this.node.namespace && this.can_use_innerhtml && this.fragment.nodes.length > 0) { if (!this.node.namespace && this.can_use_innerhtml && this.fragment.nodes.length > 0) {
if (this.fragment.nodes.length === 1 && this.fragment.nodes[0].node.type === 'Text') { if (this.fragment.nodes.length === 1 && this.fragment.nodes[0].node.type === 'Text') {
block.builders.create.add_line( block.chunks.create.push(
// @ts-ignore todo: should it be this.fragment.nodes[0].node.data instead? // @ts-ignore todo: should it be this.fragment.nodes[0].node.data instead?
`${node}.textContent = ${stringify(this.fragment.nodes[0].data)};` b`${node}.textContent = ${stringify(this.fragment.nodes[0].data)};`
); );
} else { } else {
const inner_html = escape( const inner_html = escape(
@ -297,8 +297,8 @@ export default class ElementWrapper extends Wrapper {
.join('') .join('')
); );
block.builders.create.add_line( block.chunks.create.push(
`${node}.innerHTML = \`${inner_html}\`;` b`${node}.innerHTML = \`${inner_html}\`;`
); );
} }
} else { } else {
@ -330,8 +330,8 @@ export default class ElementWrapper extends Wrapper {
this.add_classes(block); this.add_classes(block);
if (nodes && this.renderer.options.hydratable) { if (nodes && this.renderer.options.hydratable) {
block.builders.claim.add_line( block.chunks.claim.push(
`${nodes}.forEach(@detach);` b`${nodes}.forEach(@detach);`
); );
} }
@ -367,8 +367,8 @@ export default class ElementWrapper extends Wrapper {
if (renderer.options.dev) { if (renderer.options.dev) {
const loc = renderer.locate(this.node.start); const loc = renderer.locate(this.node.start);
block.builders.hydrate.add_line( block.chunks.hydrate.push(
`@add_location(${this.var}, ${renderer.file_var}, ${loc.line}, ${loc.column}, ${this.node.start});` b`@add_location(${this.var}, ${renderer.file_var}, ${loc.line}, ${loc.column}, ${this.node.start});`
); );
} }
} }
@ -470,7 +470,7 @@ export default class ElementWrapper extends Wrapper {
if (has_local_function) { if (has_local_function) {
// need to create a block-local function that calls an instance-level function // need to create a block-local function that calls an instance-level function
if (animation_frame) { if (animation_frame) {
block.builders.init.add_block(deindent` block.chunks.init.push(b`
function ${handler}() { function ${handler}() {
@_cancelAnimationFrame(${animation_frame}); @_cancelAnimationFrame(${animation_frame});
if (!${this.var}.paused) { if (!${this.var}.paused) {
@ -481,7 +481,7 @@ export default class ElementWrapper extends Wrapper {
} }
`); `);
} else { } else {
block.builders.init.add_block(deindent` block.chunks.init.push(b`
function ${handler}() { function ${handler}() {
${needs_lock && `${lock} = true;`} ${needs_lock && `${lock} = true;`}
ctx.${handler}.call(${this.var}${contextual_dependencies.size > 0 ? ', ctx' : ''}); ctx.${handler}.call(${this.var}${contextual_dependencies.size > 0 ? ', ctx' : ''});
@ -494,7 +494,7 @@ export default class ElementWrapper extends Wrapper {
callee = `ctx.${handler}`; callee = `ctx.${handler}`;
} }
this.renderer.component.partly_hoisted.push(deindent` this.renderer.component.partly_hoisted.push(b`
function ${handler}(${contextual_dependencies.size > 0 ? `{ ${Array.from(contextual_dependencies).join(', ')} }` : ``}) { function ${handler}(${contextual_dependencies.size > 0 ? `{ ${Array.from(contextual_dependencies).join(', ')} }` : ``}) {
${group.bindings.map(b => b.handler.mutation)} ${group.bindings.map(b => b.handler.mutation)}
${Array.from(dependencies).filter(dep => dep[0] !== '$').map(dep => `${this.renderer.component.invalidate(dep)};`)} ${Array.from(dependencies).filter(dep => dep[0] !== '$').map(dep => `${this.renderer.component.invalidate(dep)};`)}
@ -507,12 +507,12 @@ export default class ElementWrapper extends Wrapper {
const resize_listener = block.get_unique_name(`${this.var}_resize_listener`); const resize_listener = block.get_unique_name(`${this.var}_resize_listener`);
block.add_variable(resize_listener); block.add_variable(resize_listener);
block.builders.mount.add_line( block.chunks.mount.push(
`${resize_listener} = @add_resize_listener(${this.var}, ${callee}.bind(${this.var}));` b`${resize_listener} = @add_resize_listener(${this.var}, ${callee}.bind(${this.var}));`
); );
block.builders.destroy.add_line( block.chunks.destroy.push(
`${resize_listener}.cancel();` b`${resize_listener}.cancel();`
); );
} else { } else {
block.event_listeners.push( block.event_listeners.push(
@ -539,27 +539,27 @@ export default class ElementWrapper extends Wrapper {
if (should_initialise) { if (should_initialise) {
const callback = has_local_function ? handler : `() => ${callee}.call(${this.var})`; const callback = has_local_function ? handler : `() => ${callee}.call(${this.var})`;
block.builders.hydrate.add_line( block.chunks.hydrate.push(
`if (${some_initial_state_is_undefined}) @add_render_callback(${callback});` b`if (${some_initial_state_is_undefined}) @add_render_callback(${callback});`
); );
} }
if (group.events[0] === 'resize') { if (group.events[0] === 'resize') {
block.builders.hydrate.add_line( block.chunks.hydrate.push(
`@add_render_callback(() => ${callee}.call(${this.var}));` b`@add_render_callback(() => ${callee}.call(${this.var}));`
); );
} }
}); });
if (lock) { if (lock) {
block.builders.update.add_line(`${lock} = false;`); block.chunks.update.push(b`${lock} = false;`);
} }
const this_binding = this.bindings.find(b => b.node.name === 'this'); const this_binding = this.bindings.find(b => b.node.name === 'this');
if (this_binding) { if (this_binding) {
const binding_callback = bind_this(renderer.component, block, this_binding.node, this.var); const binding_callback = bind_this(renderer.component, block, this_binding.node, this.var);
block.builders.mount.add_line(binding_callback); block.chunks.mount.push(binding_callback);
} }
} }
@ -611,7 +611,7 @@ export default class ElementWrapper extends Wrapper {
} }
}); });
block.builders.init.add_block(deindent` block.chunks.init.push(b`
var ${levels} = [ var ${levels} = [
${initial_props.join(',\n')} ${initial_props.join(',\n')}
]; ];
@ -622,14 +622,14 @@ export default class ElementWrapper extends Wrapper {
} }
`); `);
const fn = this.node.namespace === namespaces.svg ? `set_svg_attributes` : `set_attributes`; const fn = this.node.namespace === namespaces.svg ? x`@set_svg_attributes` : x`@set_attributes`;
block.builders.hydrate.add_line( block.chunks.hydrate.push(
`@${fn}(${this.var}, ${data});` b`${fn}(${this.var}, ${data});`
); );
block.builders.update.add_block(deindent` block.chunks.update.push(b`
@${fn}(${this.var}, @get_spread_update(${levels}, [ ${fn}(${this.var}, @get_spread_update(${levels}, [
${updates.join(',\n')} ${updates.join(',\n')}
])); ]));
`); `);
@ -658,36 +658,36 @@ export default class ElementWrapper extends Wrapper {
const fn = component.qualify(intro.name); const fn = component.qualify(intro.name);
const intro_block = deindent` const intro_block = b`
@add_render_callback(() => { @add_render_callback(() => {
if (!${name}) ${name} = @create_bidirectional_transition(${this.var}, ${fn}, ${snippet}, true); if (!${name}) ${name} = @create_bidirectional_transition(${this.var}, ${fn}, ${snippet}, true);
${name}.run(1); ${name}.run(1);
}); });
`; `;
const outro_block = deindent` const outro_block = b`
if (!${name}) ${name} = @create_bidirectional_transition(${this.var}, ${fn}, ${snippet}, false); if (!${name}) ${name} = @create_bidirectional_transition(${this.var}, ${fn}, ${snippet}, false);
${name}.run(0); ${name}.run(0);
`; `;
if (intro.is_local) { if (intro.is_local) {
block.builders.intro.add_block(deindent` block.chunks.intro.push(b`
if (#local) { if (#local) {
${intro_block} ${intro_block}
} }
`); `);
block.builders.outro.add_block(deindent` block.chunks.outro.push(b`
if (#local) { if (#local) {
${outro_block} ${outro_block}
} }
`); `);
} else { } else {
block.builders.intro.add_block(intro_block); block.chunks.intro.push(intro_block);
block.builders.outro.add_block(outro_block); block.chunks.outro.push(outro_block);
} }
block.builders.destroy.add_conditional('detaching', `if (${name}) ${name}.end();`); block.chunks.destroy.push(b`if (detaching && ${name}) ${name}.end();`);
} }
else { else {
@ -705,7 +705,7 @@ export default class ElementWrapper extends Wrapper {
let intro_block; let intro_block;
if (outro) { if (outro) {
intro_block = deindent` 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}); if (!${intro_name}) ${intro_name} = @create_in_transition(${this.var}, ${fn}, ${snippet});
@ -713,9 +713,9 @@ export default class ElementWrapper extends Wrapper {
}); });
`; `;
block.builders.outro.add_line(`if (${intro_name}) ${intro_name}.invalidate();`); block.chunks.outro.push(b`if (${intro_name}) ${intro_name}.invalidate();`);
} else { } else {
intro_block = deindent` intro_block = b`
if (!${intro_name}) { if (!${intro_name}) {
@add_render_callback(() => { @add_render_callback(() => {
${intro_name} = @create_in_transition(${this.var}, ${fn}, ${snippet}); ${intro_name} = @create_in_transition(${this.var}, ${fn}, ${snippet});
@ -726,14 +726,14 @@ export default class ElementWrapper extends Wrapper {
} }
if (intro.is_local) { if (intro.is_local) {
intro_block = deindent` intro_block = b`
if (#local) { if (#local) {
${intro_block} ${intro_block}
} }
`; `;
} }
block.builders.intro.add_block(intro_block); block.chunks.intro.push(intro_block);
} }
if (outro) { if (outro) {
@ -745,28 +745,28 @@ export default class ElementWrapper extends Wrapper {
const fn = component.qualify(outro.name); const fn = component.qualify(outro.name);
if (!intro) { if (!intro) {
block.builders.intro.add_block(deindent` block.chunks.intro.push(b`
if (${outro_name}) ${outro_name}.end(1); if (${outro_name}) ${outro_name}.end(1);
`); `);
} }
// TODO hide elements that have outro'd (unless they belong to a still-outroing // TODO hide elements that have outro'd (unless they belong to a still-outroing
// group) prior to their removal from the DOM // group) prior to their removal from the DOM
let outro_block = deindent` let outro_block = b`
${outro_name} = @create_out_transition(${this.var}, ${fn}, ${snippet}); ${outro_name} = @create_out_transition(${this.var}, ${fn}, ${snippet});
`; `;
if (outro.is_local) { if (outro.is_local) {
outro_block = deindent` outro_block = b`
if (#local) { if (#local) {
${outro_block} ${outro_block}
} }
`; `;
} }
block.builders.outro.add_block(outro_block); block.chunks.outro.push(outro_block);
block.builders.destroy.add_conditional('detaching', `if (${outro_name}) ${outro_name}.end();`); block.chunks.destroy.push(b`if (detaching && ${outro_name}) ${outro_name}.end();`);
} }
} }
} }
@ -783,11 +783,11 @@ export default class ElementWrapper extends Wrapper {
block.add_variable(rect); block.add_variable(rect);
block.add_variable(stop_animation, '@noop'); block.add_variable(stop_animation, '@noop');
block.builders.measure.add_block(deindent` block.chunks.measure.push(b`
${rect} = ${this.var}.getBoundingClientRect(); ${rect} = ${this.var}.getBoundingClientRect();
`); `);
block.builders.fix.add_block(deindent` block.chunks.fix.push(b`
@fix_position(${this.var}); @fix_position(${this.var});
${stop_animation}(); ${stop_animation}();
${outro && `@add_transform(${this.var}, ${rect});`} ${outro && `@add_transform(${this.var}, ${rect});`}
@ -797,7 +797,7 @@ export default class ElementWrapper extends Wrapper {
const name = component.qualify(this.node.animation.name); const name = component.qualify(this.node.animation.name);
block.builders.animate.add_block(deindent` block.chunks.animate.push(b`
${stop_animation}(); ${stop_animation}();
${stop_animation} = @create_animation(${this.var}, ${rect}, ${name}, ${params}); ${stop_animation} = @create_animation(${this.var}, ${rect}, ${name}, ${params});
`); `);
@ -819,19 +819,16 @@ export default class ElementWrapper extends Wrapper {
snippet = `${quote_prop_if_necessary(name)}`; snippet = `${quote_prop_if_necessary(name)}`;
dependencies = new Set([name]); dependencies = new Set([name]);
} }
const updater = `@toggle_class(${this.var}, "${name}", ${snippet});`; const updater = b`@toggle_class(${this.var}, "${name}", ${snippet});`;
block.builders.hydrate.add_line(updater); block.chunks.hydrate.push(updater);
if ((dependencies && dependencies.size > 0) || this.class_dependencies.length) { if ((dependencies && dependencies.size > 0) || this.class_dependencies.length) {
const all_dependencies = this.class_dependencies.concat(...dependencies); const all_dependencies = this.class_dependencies.concat(...dependencies);
const deps = all_dependencies.map(dependency => `changed${quote_prop_if_necessary(dependency)}`).join(' || '); const deps = all_dependencies.map(dependency => `changed${quote_prop_if_necessary(dependency)}`).join(' || ');
const condition = all_dependencies.length > 1 ? `(${deps})` : deps; const condition = all_dependencies.length > 1 ? `(${deps})` : deps;
block.builders.update.add_conditional( block.chunks.update.push(b`if (${condition}) ${updater}`);
condition,
updater
);
} }
}); });
} }

@ -6,7 +6,7 @@ import IfBlock from '../../nodes/IfBlock';
import create_debugging_comment from './shared/create_debugging_comment'; import create_debugging_comment from './shared/create_debugging_comment';
import ElseBlock from '../../nodes/ElseBlock'; import ElseBlock from '../../nodes/ElseBlock';
import FragmentWrapper from './Fragment'; import FragmentWrapper from './Fragment';
import deindent from '../../utils/deindent'; import { b } from 'code-red';
import { walk } from 'estree-walker'; import { walk } from 'estree-walker';
function is_else_if(node: ElseBlock) { function is_else_if(node: ElseBlock) {
@ -198,7 +198,7 @@ export default class IfBlockWrapper extends Wrapper {
if (has_outros) { if (has_outros) {
this.render_compound_with_outros(block, parent_node, parent_nodes, dynamic, vars, detaching); this.render_compound_with_outros(block, parent_node, parent_nodes, dynamic, vars, detaching);
block.builders.outro.add_line(`@transition_out(${name});`); block.chunks.outro.push(b`@transition_out(${name});`);
} else { } else {
this.render_compound(block, parent_node, parent_nodes, dynamic, vars, detaching); this.render_compound(block, parent_node, parent_nodes, dynamic, vars, detaching);
} }
@ -206,20 +206,20 @@ export default class IfBlockWrapper extends Wrapper {
this.render_simple(block, parent_node, parent_nodes, dynamic, vars, detaching); this.render_simple(block, parent_node, parent_nodes, dynamic, vars, detaching);
if (has_outros) { if (has_outros) {
block.builders.outro.add_line(`@transition_out(${name});`); block.chunks.outro.push(b`@transition_out(${name});`);
} }
} }
block.builders.create.add_line(`${if_name}${name}.c();`); block.chunks.create.push(b`${if_name}${name}.c();`);
if (parent_nodes && this.renderer.options.hydratable) { if (parent_nodes && this.renderer.options.hydratable) {
block.builders.claim.add_line( block.chunks.claim.push(
`${if_name}${name}.l(${parent_nodes});` b`${if_name}${name}.l(${parent_nodes});`
); );
} }
if (has_intros || has_outros) { if (has_intros || has_outros) {
block.builders.intro.add_line(`@transition_in(${name});`); block.chunks.intro.push(b`@transition_in(${name});`);
} }
if (needs_anchor) { if (needs_anchor) {
@ -250,10 +250,10 @@ export default class IfBlockWrapper extends Wrapper {
/* eslint-disable @typescript-eslint/indent,indent */ /* eslint-disable @typescript-eslint/indent,indent */
if (this.needs_update) { if (this.needs_update) {
block.builders.init.add_block(deindent` block.chunks.init.push(b`
function ${select_block_type}(changed, ctx) { function ${select_block_type}(changed, ctx) {
${this.branches.map(({ dependencies, condition, snippet, block }) => condition ${this.branches.map(({ dependencies, condition, snippet, block }) => condition
? deindent` ? b`
${snippet && ( ${snippet && (
dependencies.length > 0 dependencies.length > 0
? `if ((${condition} == null) || ${dependencies.map(n => `changed.${n}`).join(' || ')}) ${condition} = !!(${snippet})` ? `if ((${condition} == null) || ${dependencies.map(n => `changed.${n}`).join(' || ')}) ${condition} = !!(${snippet})`
@ -264,7 +264,7 @@ export default class IfBlockWrapper extends Wrapper {
} }
`); `);
} else { } else {
block.builders.init.add_block(deindent` block.chunks.init.push(b`
function ${select_block_type}(changed, ctx) { function ${select_block_type}(changed, ctx) {
${this.branches.map(({ condition, snippet, block }) => condition ${this.branches.map(({ condition, snippet, block }) => condition
? `if (${snippet || condition}) return ${block.name};` ? `if (${snippet || condition}) return ${block.name};`
@ -274,21 +274,21 @@ export default class IfBlockWrapper extends Wrapper {
} }
/* eslint-enable @typescript-eslint/indent,indent */ /* eslint-enable @typescript-eslint/indent,indent */
block.builders.init.add_block(deindent` block.chunks.init.push(b`
var ${current_block_type} = ${select_block_type}(null, ctx); var ${current_block_type} = ${select_block_type}(null, ctx);
var ${name} = ${current_block_type_and}${current_block_type}(ctx); var ${name} = ${current_block_type_and}${current_block_type}(ctx);
`); `);
const initial_mount_node = parent_node || '#target'; const initial_mount_node = parent_node || '#target';
const anchor_node = parent_node ? 'null' : 'anchor'; const anchor_node = parent_node ? 'null' : 'anchor';
block.builders.mount.add_line( block.chunks.mount.push(
`${if_name}${name}.m(${initial_mount_node}, ${anchor_node});` b`${if_name}${name}.m(${initial_mount_node}, ${anchor_node});`
); );
if (this.needs_update) { if (this.needs_update) {
const update_mount_node = this.get_update_mount_node(anchor); const update_mount_node = this.get_update_mount_node(anchor);
const change_block = deindent` const change_block = b`
${if_name}${name}.d(1); ${if_name}${name}.d(1);
${name} = ${current_block_type_and}${current_block_type}(ctx); ${name} = ${current_block_type_and}${current_block_type}(ctx);
if (${name}) { if (${name}) {
@ -299,7 +299,7 @@ export default class IfBlockWrapper extends Wrapper {
`; `;
if (dynamic) { if (dynamic) {
block.builders.update.add_block(deindent` block.chunks.update.push(b`
if (${current_block_type} === (${current_block_type} = ${select_block_type}(changed, ctx)) && ${name}) { if (${current_block_type} === (${current_block_type} = ${select_block_type}(changed, ctx)) && ${name}) {
${name}.p(changed, ctx); ${name}.p(changed, ctx);
} else { } else {
@ -307,17 +307,17 @@ export default class IfBlockWrapper extends Wrapper {
} }
`); `);
} else { } else {
block.builders.update.add_block(deindent` block.chunks.update.push(b`
if (${current_block_type} !== (${current_block_type} = ${select_block_type}(changed, ctx))) { if (${current_block_type} !== (${current_block_type} = ${select_block_type}(changed, ctx))) {
${change_block} ${change_block}
} }
`); `);
} }
} else if (dynamic) { } else if (dynamic) {
block.builders.update.add_line(`${name}.p(changed, ctx);`); block.chunks.update.push(b`${name}.p(changed, ctx);`);
} }
block.builders.destroy.add_line(`${if_name}${name}.d(${detaching});`); block.chunks.destroy.push(b`${if_name}${name}.d(${detaching});`);
} }
// if any of the siblings have outros, we need to keep references to the blocks // if any of the siblings have outros, we need to keep references to the blocks
@ -344,7 +344,7 @@ export default class IfBlockWrapper extends Wrapper {
block.add_variable(name); block.add_variable(name);
/* eslint-disable @typescript-eslint/indent,indent */ /* eslint-disable @typescript-eslint/indent,indent */
block.builders.init.add_block(deindent` block.chunks.init.push(b`
var ${if_block_creators} = [ var ${if_block_creators} = [
${this.branches.map(branch => branch.block.name).join(',\n')} ${this.branches.map(branch => branch.block.name).join(',\n')}
]; ];
@ -352,17 +352,17 @@ export default class IfBlockWrapper extends Wrapper {
var ${if_blocks} = []; var ${if_blocks} = [];
${this.needs_update ${this.needs_update
? deindent` ? b`
function ${select_block_type}(changed, ctx) { function ${select_block_type}(changed, ctx) {
${this.branches.map(({ dependencies, condition, snippet }, i) => condition ${this.branches.map(({ dependencies, condition, snippet }, i) => condition
? deindent` ? b`
${snippet && `if ((${condition} == null) || ${dependencies.map(n => `changed.${n}`).join(' || ')}) ${condition} = !!(${snippet})`} ${snippet && `if ((${condition} == null) || ${dependencies.map(n => `changed.${n}`).join(' || ')}) ${condition} = !!(${snippet})`}
if (${condition}) return ${String(i)};` if (${condition}) return ${String(i)};`
: `return ${i};`)} : `return ${i};`)}
${!has_else && `return -1;`} ${!has_else && `return -1;`}
} }
` `
: deindent` : b`
function ${select_block_type}(changed, ctx) { function ${select_block_type}(changed, ctx) {
${this.branches.map(({ condition, snippet }, i) => condition ${this.branches.map(({ condition, snippet }, i) => condition
? `if (${snippet || condition}) return ${String(i)};` ? `if (${snippet || condition}) return ${String(i)};`
@ -374,12 +374,12 @@ export default class IfBlockWrapper extends Wrapper {
/* eslint-enable @typescript-eslint/indent,indent */ /* eslint-enable @typescript-eslint/indent,indent */
if (has_else) { if (has_else) {
block.builders.init.add_block(deindent` block.chunks.init.push(b`
${current_block_type_index} = ${select_block_type}(null, ctx); ${current_block_type_index} = ${select_block_type}(null, ctx);
${name} = ${if_blocks}[${current_block_type_index}] = ${if_block_creators}[${current_block_type_index}](ctx); ${name} = ${if_blocks}[${current_block_type_index}] = ${if_block_creators}[${current_block_type_index}](ctx);
`); `);
} else { } else {
block.builders.init.add_block(deindent` block.chunks.init.push(b`
if (~(${current_block_type_index} = ${select_block_type}(null, ctx))) { if (~(${current_block_type_index} = ${select_block_type}(null, ctx))) {
${name} = ${if_blocks}[${current_block_type_index}] = ${if_block_creators}[${current_block_type_index}](ctx); ${name} = ${if_blocks}[${current_block_type_index}] = ${if_block_creators}[${current_block_type_index}](ctx);
} }
@ -389,14 +389,14 @@ export default class IfBlockWrapper extends Wrapper {
const initial_mount_node = parent_node || '#target'; const initial_mount_node = parent_node || '#target';
const anchor_node = parent_node ? 'null' : 'anchor'; const anchor_node = parent_node ? 'null' : 'anchor';
block.builders.mount.add_line( block.chunks.mount.push(
`${if_current_block_type_index}${if_blocks}[${current_block_type_index}].m(${initial_mount_node}, ${anchor_node});` b`${if_current_block_type_index}${if_blocks}[${current_block_type_index}].m(${initial_mount_node}, ${anchor_node});`
); );
if (this.needs_update) { if (this.needs_update) {
const update_mount_node = this.get_update_mount_node(anchor); const update_mount_node = this.get_update_mount_node(anchor);
const destroy_old_block = deindent` const destroy_old_block = b`
@group_outros(); @group_outros();
@transition_out(${if_blocks}[${previous_block_index}], 1, 1, () => { @transition_out(${if_blocks}[${previous_block_index}], 1, 1, () => {
${if_blocks}[${previous_block_index}] = null; ${if_blocks}[${previous_block_index}] = null;
@ -404,7 +404,7 @@ export default class IfBlockWrapper extends Wrapper {
@check_outros(); @check_outros();
`; `;
const create_new_block = deindent` const create_new_block = b`
${name} = ${if_blocks}[${current_block_type_index}]; ${name} = ${if_blocks}[${current_block_type_index}];
if (!${name}) { if (!${name}) {
${name} = ${if_blocks}[${current_block_type_index}] = ${if_block_creators}[${current_block_type_index}](ctx); ${name} = ${if_blocks}[${current_block_type_index}] = ${if_block_creators}[${current_block_type_index}](ctx);
@ -415,12 +415,12 @@ export default class IfBlockWrapper extends Wrapper {
`; `;
const change_block = has_else const change_block = has_else
? deindent` ? b`
${destroy_old_block} ${destroy_old_block}
${create_new_block} ${create_new_block}
` `
: deindent` : b`
if (${name}) { if (${name}) {
${destroy_old_block} ${destroy_old_block}
} }
@ -433,7 +433,7 @@ export default class IfBlockWrapper extends Wrapper {
`; `;
if (dynamic) { if (dynamic) {
block.builders.update.add_block(deindent` block.chunks.update.push(b`
var ${previous_block_index} = ${current_block_type_index}; var ${previous_block_index} = ${current_block_type_index};
${current_block_type_index} = ${select_block_type}(changed, ctx); ${current_block_type_index} = ${select_block_type}(changed, ctx);
if (${current_block_type_index} === ${previous_block_index}) { if (${current_block_type_index} === ${previous_block_index}) {
@ -443,7 +443,7 @@ export default class IfBlockWrapper extends Wrapper {
} }
`); `);
} else { } else {
block.builders.update.add_block(deindent` block.chunks.update.push(b`
var ${previous_block_index} = ${current_block_type_index}; var ${previous_block_index} = ${current_block_type_index};
${current_block_type_index} = ${select_block_type}(changed, ctx); ${current_block_type_index} = ${select_block_type}(changed, ctx);
if (${current_block_type_index} !== ${previous_block_index}) { if (${current_block_type_index} !== ${previous_block_index}) {
@ -452,10 +452,10 @@ export default class IfBlockWrapper extends Wrapper {
`); `);
} }
} else if (dynamic) { } else if (dynamic) {
block.builders.update.add_line(`${name}.p(changed, ctx);`); block.chunks.update.push(b`${name}.p(changed, ctx);`);
} }
block.builders.destroy.add_line(deindent` block.chunks.destroy.push(b`
${if_current_block_type_index}${if_blocks}[${current_block_type_index}].d(${detaching}); ${if_current_block_type_index}${if_blocks}[${current_block_type_index}].d(${detaching});
`); `);
} }
@ -472,22 +472,22 @@ export default class IfBlockWrapper extends Wrapper {
if (branch.snippet) block.add_variable(branch.condition, branch.snippet); if (branch.snippet) block.add_variable(branch.condition, branch.snippet);
block.builders.init.add_block(deindent` block.chunks.init.push(b`
var ${name} = (${branch.condition}) && ${branch.block.name}(ctx); var ${name} = (${branch.condition}) && ${branch.block.name}(ctx);
`); `);
const initial_mount_node = parent_node || '#target'; const initial_mount_node = parent_node || '#target';
const anchor_node = parent_node ? 'null' : 'anchor'; const anchor_node = parent_node ? 'null' : 'anchor';
block.builders.mount.add_line( block.chunks.mount.push(
`if (${name}) ${name}.m(${initial_mount_node}, ${anchor_node});` b`if (${name}) ${name}.m(${initial_mount_node}, ${anchor_node});`
); );
if (branch.dependencies.length > 0) { if (branch.dependencies.length > 0) {
const update_mount_node = this.get_update_mount_node(anchor); const update_mount_node = this.get_update_mount_node(anchor);
const enter = dynamic const enter = dynamic
? deindent` ? b`
if (${name}) { if (${name}) {
${name}.p(changed, ctx); ${name}.p(changed, ctx);
${has_transitions && `@transition_in(${name}, 1);`} ${has_transitions && `@transition_in(${name}, 1);`}
@ -498,7 +498,7 @@ export default class IfBlockWrapper extends Wrapper {
${name}.m(${update_mount_node}, ${anchor}); ${name}.m(${update_mount_node}, ${anchor});
} }
` `
: deindent` : b`
if (!${name}) { if (!${name}) {
${name} = ${branch.block.name}(ctx); ${name} = ${branch.block.name}(ctx);
${name}.c(); ${name}.c();
@ -508,13 +508,13 @@ export default class IfBlockWrapper extends Wrapper {
`; `;
if (branch.snippet) { if (branch.snippet) {
block.builders.update.add_block(`if (${branch.dependencies.map(n => `changed.${n}`).join(' || ')}) ${branch.condition} = ${branch.snippet}`); block.chunks.update.push(b`if (${branch.dependencies.map(n => `changed.${n}`).join(' || ')}) ${branch.condition} = ${branch.snippet}`);
} }
// no `p()` here — we don't want to update outroing nodes, // no `p()` here — we don't want to update outroing nodes,
// as that will typically result in glitching // as that will typically result in glitching
if (branch.block.has_outro_method) { if (branch.block.has_outro_method) {
block.builders.update.add_block(deindent` block.chunks.update.push(b`
if (${branch.condition}) { if (${branch.condition}) {
${enter} ${enter}
} else if (${name}) { } else if (${name}) {
@ -526,7 +526,7 @@ export default class IfBlockWrapper extends Wrapper {
} }
`); `);
} else { } else {
block.builders.update.add_block(deindent` block.chunks.update.push(b`
if (${branch.condition}) { if (${branch.condition}) {
${enter} ${enter}
} else if (${name}) { } else if (${name}) {
@ -536,11 +536,11 @@ export default class IfBlockWrapper extends Wrapper {
`); `);
} }
} else if (dynamic) { } else if (dynamic) {
block.builders.update.add_block( block.chunks.update.push(
`if (${branch.condition}) ${name}.p(changed, ctx);` b`if (${branch.condition}) ${name}.p(changed, ctx);`
); );
} }
block.builders.destroy.add_line(`${if_name}${name}.d(${detaching});`); block.chunks.destroy.push(b`${if_name}${name}.d(${detaching});`);
} }
} }

@ -6,7 +6,7 @@ import FragmentWrapper from '../Fragment';
import { quote_name_if_necessary, quote_prop_if_necessary, sanitize } from '../../../../utils/names'; import { quote_name_if_necessary, quote_prop_if_necessary, sanitize } from '../../../../utils/names';
import { stringify_props } from '../../../utils/stringify_props'; import { stringify_props } from '../../../utils/stringify_props';
import add_to_set from '../../../utils/add_to_set'; import add_to_set from '../../../utils/add_to_set';
import deindent from '../../../utils/deindent'; import { b } from 'code-red';
import Attribute from '../../../nodes/Attribute'; import Attribute from '../../../nodes/Attribute';
import get_object from '../../../utils/get_object'; import get_object from '../../../utils/get_object';
import create_debugging_comment from '../shared/create_debugging_comment'; import create_debugging_comment from '../shared/create_debugging_comment';
@ -212,13 +212,13 @@ export default class InlineComponentWrapper extends Wrapper {
} }
}); });
block.builders.init.add_block(deindent` block.chunks.init.push(b`
var ${levels} = [ var ${levels} = [
${initial_props.join(',\n')} ${initial_props.join(',\n')}
]; ];
`); `);
statements.push(deindent` statements.push(b`
for (var #i = 0; #i < ${levels}.length; #i += 1) { for (var #i = 0; #i < ${levels}.length; #i += 1) {
${props} = @assign(${props}, ${levels}[#i]); ${props} = @assign(${props}, ${levels}[#i]);
} }
@ -226,7 +226,7 @@ export default class InlineComponentWrapper extends Wrapper {
const conditions = Array.from(all_dependencies).map(dep => `changed.${dep}`).join(' || '); const conditions = Array.from(all_dependencies).map(dep => `changed.${dep}`).join(' || ');
updates.push(deindent` updates.push(b`
var ${name_changes} = ${conditions ? `(${conditions}) ? @get_spread_update(${levels}, [ var ${name_changes} = ${conditions ? `(${conditions}) ? @get_spread_update(${levels}, [
${changes.join(',\n')} ${changes.join(',\n')}
]) : {}` : '{}'}; ]) : {}` : '{}'};
@ -237,7 +237,7 @@ export default class InlineComponentWrapper extends Wrapper {
if (dependencies.length > 0) { if (dependencies.length > 0) {
const condition = dependencies.map(dependency => `changed.${dependency}`).join(' || '); const condition = dependencies.map(dependency => `changed.${dependency}`).join(' || ');
updates.push(deindent` updates.push(b`
if (${condition}) ${name_changes}${quote_prop_if_necessary(attribute.name)} = ${attribute.get_value(block)}; if (${condition}) ${name_changes}${quote_prop_if_necessary(attribute.name)} = ${attribute.get_value(block)};
`); `);
} }
@ -269,13 +269,13 @@ export default class InlineComponentWrapper extends Wrapper {
const snippet = binding.expression.render(block); const snippet = binding.expression.render(block);
statements.push(deindent` statements.push(b`
if (${snippet} !== void 0) { if (${snippet} !== void 0) {
${props}${quote_prop_if_necessary(binding.name)} = ${snippet}; ${props}${quote_prop_if_necessary(binding.name)} = ${snippet};
}` }`
); );
updates.push(deindent` updates.push(b`
if (!${updating} && ${[...binding.expression.dependencies].map((dependency: string) => `changed.${dependency}`).join(' || ')}) { if (!${updating} && ${[...binding.expression.dependencies].map((dependency: string) => `changed.${dependency}`).join(' || ')}) {
${name_changes}${quote_prop_if_necessary(binding.name)} = ${snippet}; ${name_changes}${quote_prop_if_necessary(binding.name)} = ${snippet};
} }
@ -300,7 +300,7 @@ export default class InlineComponentWrapper extends Wrapper {
if (contextual_dependencies.length > 0) { if (contextual_dependencies.length > 0) {
args.push(`{ ${contextual_dependencies.join(', ')} }`); args.push(`{ ${contextual_dependencies.join(', ')} }`);
block.builders.init.add_block(deindent` block.chunks.init.push(b`
function ${name}(${value}) { function ${name}(${value}) {
ctx.${name}.call(null, ${value}, ctx); ctx.${name}.call(null, ${value}, ctx);
${updating} = true; ${updating} = true;
@ -310,7 +310,7 @@ export default class InlineComponentWrapper extends Wrapper {
block.maintain_context = true; // TODO put this somewhere more logical block.maintain_context = true; // TODO put this somewhere more logical
} else { } else {
block.builders.init.add_block(deindent` block.chunks.init.push(b`
function ${name}(${value}) { function ${name}(${value}) {
ctx.${name}.call(null, ${value}); ctx.${name}.call(null, ${value});
${updating} = true; ${updating} = true;
@ -319,7 +319,7 @@ export default class InlineComponentWrapper extends Wrapper {
`); `);
} }
const body = deindent` const body = b`
function ${name}(${args.join(', ')}) { function ${name}(${args.join(', ')}) {
${lhs} = ${value}; ${lhs} = ${value};
${component.invalidate(dependencies[0])}; ${component.invalidate(dependencies[0])};
@ -344,11 +344,11 @@ export default class InlineComponentWrapper extends Wrapper {
const snippet = this.node.expression.render(block); const snippet = this.node.expression.render(block);
block.builders.init.add_block(deindent` block.chunks.init.push(b`
var ${switch_value} = ${snippet}; var ${switch_value} = ${snippet};
function ${switch_props}(ctx) { function ${switch_props}(ctx) {
${(this.node.attributes.length || this.node.bindings.length) && deindent` ${(this.node.attributes.length || this.node.bindings.length) && b`
${props && `let ${props} = ${attribute_object};`}`} ${props && `let ${props} = ${attribute_object};`}`}
${statements} ${statements}
return ${stringify_props(component_opts)}; return ${stringify_props(component_opts)};
@ -362,17 +362,17 @@ export default class InlineComponentWrapper extends Wrapper {
} }
`); `);
block.builders.create.add_line( block.chunks.create.push(
`if (${name}) ${name}.$$.fragment.c();` b`if (${name}) ${name}.$$.fragment.c();`
); );
if (parent_nodes && this.renderer.options.hydratable) { if (parent_nodes && this.renderer.options.hydratable) {
block.builders.claim.add_line( block.chunks.claim.push(
`if (${name}) ${name}.$$.fragment.l(${parent_nodes});` b`if (${name}) ${name}.$$.fragment.l(${parent_nodes});`
); );
} }
block.builders.mount.add_block(deindent` block.chunks.mount.push(b`
if (${name}) { if (${name}) {
@mount_component(${name}, ${parent_node || '#target'}, ${parent_node ? 'null' : 'anchor'}); @mount_component(${name}, ${parent_node || '#target'}, ${parent_node ? 'null' : 'anchor'});
} }
@ -382,12 +382,12 @@ export default class InlineComponentWrapper extends Wrapper {
const update_mount_node = this.get_update_mount_node(anchor); const update_mount_node = this.get_update_mount_node(anchor);
if (updates.length) { if (updates.length) {
block.builders.update.add_block(deindent` block.chunks.update.push(b`
${updates} ${updates}
`); `);
} }
block.builders.update.add_block(deindent` block.chunks.update.push(b`
if (${switch_value} !== (${switch_value} = ${snippet})) { if (${switch_value} !== (${switch_value} = ${snippet})) {
if (${name}) { if (${name}) {
@group_outros(); @group_outros();
@ -413,30 +413,30 @@ export default class InlineComponentWrapper extends Wrapper {
} }
`); `);
block.builders.intro.add_block(deindent` block.chunks.intro.push(b`
if (${name}) @transition_in(${name}.$$.fragment, #local); if (${name}) @transition_in(${name}.$$.fragment, #local);
`); `);
if (updates.length) { if (updates.length) {
block.builders.update.add_block(deindent` block.chunks.update.push(b`
else if (${switch_value}) { else if (${switch_value}) {
${name}.$set(${name_changes}); ${name}.$set(${name_changes});
} }
`); `);
} }
block.builders.outro.add_line( block.chunks.outro.push(
`if (${name}) @transition_out(${name}.$$.fragment, #local);` b`if (${name}) @transition_out(${name}.$$.fragment, #local);`
); );
block.builders.destroy.add_line(`if (${name}) @destroy_component(${name}${parent_node ? '' : ', detaching'});`); block.chunks.destroy.push(b`if (${name}) @destroy_component(${name}${parent_node ? '' : ', detaching'});`);
} else { } else {
const expression = this.node.name === 'svelte:self' const expression = this.node.name === 'svelte:self'
? '__svelte:self__' // TODO conflict-proof this ? '__svelte:self__' // TODO conflict-proof this
: component.qualify(this.node.name); : component.qualify(this.node.name);
block.builders.init.add_block(deindent` block.chunks.init.push(b`
${(this.node.attributes.length || this.node.bindings.length) && deindent` ${(this.node.attributes.length || this.node.bindings.length) && b`
${props && `let ${props} = ${attribute_object};`}`} ${props && `let ${props} = ${attribute_object};`}`}
${statements} ${statements}
var ${name} = new ${expression}(${stringify_props(component_opts)}); var ${name} = new ${expression}(${stringify_props(component_opts)});
@ -445,35 +445,35 @@ export default class InlineComponentWrapper extends Wrapper {
${munged_handlers} ${munged_handlers}
`); `);
block.builders.create.add_line(`${name}.$$.fragment.c();`); block.chunks.create.push(b`${name}.$$.fragment.c();`);
if (parent_nodes && this.renderer.options.hydratable) { if (parent_nodes && this.renderer.options.hydratable) {
block.builders.claim.add_line( block.chunks.claim.push(
`${name}.$$.fragment.l(${parent_nodes});` b`${name}.$$.fragment.l(${parent_nodes});`
); );
} }
block.builders.mount.add_line( block.chunks.mount.push(
`@mount_component(${name}, ${parent_node || '#target'}, ${parent_node ? 'null' : 'anchor'});` b`@mount_component(${name}, ${parent_node || '#target'}, ${parent_node ? 'null' : 'anchor'});`
); );
block.builders.intro.add_block(deindent` block.chunks.intro.push(b`
@transition_in(${name}.$$.fragment, #local); @transition_in(${name}.$$.fragment, #local);
`); `);
if (updates.length) { if (updates.length) {
block.builders.update.add_block(deindent` block.chunks.update.push(b`
${updates} ${updates}
${name}.$set(${name_changes}); ${name}.$set(${name_changes});
`); `);
} }
block.builders.destroy.add_block(deindent` block.chunks.destroy.push(b`
@destroy_component(${name}${parent_node ? '' : ', detaching'}); @destroy_component(${name}${parent_node ? '' : ', detaching'});
`); `);
block.builders.outro.add_line( block.chunks.outro.push(
`@transition_out(${name}.$$.fragment, #local);` b`@transition_out(${name}.$$.fragment, #local);`
); );
} }
} }

@ -1,3 +1,4 @@
import { b } from 'code-red';
import Renderer from '../Renderer'; import Renderer from '../Renderer';
import Block from '../Block'; import Block from '../Block';
import Tag from './shared/Tag'; import Tag from './shared/Tag';
@ -24,14 +25,14 @@ export default class RawMustacheTagWrapper extends Tag {
const can_use_innerhtml = !in_head && parent_node && !this.prev && !this.next; const can_use_innerhtml = !in_head && parent_node && !this.prev && !this.next;
if (can_use_innerhtml) { if (can_use_innerhtml) {
const insert = content => `${parent_node}.innerHTML = ${content};`; const insert = content => b`${parent_node}.innerHTML = ${content};`;
const { init } = this.rename_this_method( const { init } = this.rename_this_method(
block, block,
content => insert(content) content => insert(content)
); );
block.builders.mount.add_line(insert(init)); block.chunks.mount.push(insert(init));
} }
else { else {
@ -49,15 +50,15 @@ export default class RawMustacheTagWrapper extends Tag {
const update_anchor = in_head ? 'null' : needs_anchor ? html_anchor : this.next ? this.next.var : 'null'; const update_anchor = in_head ? 'null' : needs_anchor ? html_anchor : this.next ? this.next.var : 'null';
block.builders.hydrate.add_line(`${html_tag} = new @HtmlTag(${init}, ${update_anchor});`); block.chunks.hydrate.push(b`${html_tag} = new @HtmlTag(${init}, ${update_anchor});`);
block.builders.mount.add_line(`${html_tag}.m(${parent_node || '#target'}${parent_node ? '' : ', anchor'});`); block.chunks.mount.push(b`${html_tag}.m(${parent_node || '#target'}${parent_node ? '' : ', anchor'});`);
if (needs_anchor) { if (needs_anchor) {
block.add_element(html_anchor, '@empty()', '@empty()', parent_node); block.add_element(html_anchor, '@empty()', '@empty()', parent_node);
} }
if (!parent_node || in_head) { if (!parent_node || in_head) {
block.builders.destroy.add_conditional('detaching', `${html_tag}.d();`); block.chunks.destroy.push(b`if (detaching) ${html_tag}.d();`);
} }
} }
} }

@ -3,7 +3,7 @@ import Renderer from '../Renderer';
import Block from '../Block'; import Block from '../Block';
import Slot from '../../nodes/Slot'; import Slot from '../../nodes/Slot';
import FragmentWrapper from './Fragment'; import FragmentWrapper from './Fragment';
import deindent from '../../utils/deindent'; import { b } from 'code-red';
import { sanitize, quote_prop_if_necessary } from '../../../utils/names'; import { sanitize, quote_prop_if_necessary } from '../../../utils/names';
import add_to_set from '../../utils/add_to_set'; import add_to_set from '../../utils/add_to_set';
import get_slot_data from '../../utils/get_slot_data'; import get_slot_data from '../../utils/get_slot_data';
@ -96,7 +96,7 @@ export default class SlotWrapper extends Wrapper {
const arg = dependencies.size > 0 ? `{ ${Array.from(dependencies).join(', ')} }` : ''; const arg = dependencies.size > 0 ? `{ ${Array.from(dependencies).join(', ')} }` : '';
renderer.blocks.push(deindent` renderer.blocks.push(b`
const ${get_slot_changes} = (${arg}) => (${stringify_props(changes_props)}); const ${get_slot_changes} = (${arg}) => (${stringify_props(changes_props)});
const ${get_slot_context} = (${arg}) => (${stringify_props(context_props)}); const ${get_slot_context} = (${arg}) => (${stringify_props(context_props)});
`); `);
@ -108,19 +108,19 @@ export default class SlotWrapper extends Wrapper {
const slot = block.get_unique_name(`${sanitize(slot_name)}_slot`); const slot = block.get_unique_name(`${sanitize(slot_name)}_slot`);
const slot_definition = block.get_unique_name(`${sanitize(slot_name)}_slot_template`); const slot_definition = block.get_unique_name(`${sanitize(slot_name)}_slot_template`);
block.builders.init.add_block(deindent` block.chunks.init.push(b`
const ${slot_definition} = ctx.$$slots${quote_prop_if_necessary(slot_name)}; const ${slot_definition} = ctx.$$slots${quote_prop_if_necessary(slot_name)};
const ${slot} = @create_slot(${slot_definition}, ctx, ${get_slot_context}); const ${slot} = @create_slot(${slot_definition}, ctx, ${get_slot_context});
`); `);
const mount_before = block.builders.mount.toString(); const mount_before = block.chunks.mount.slice();
block.builders.create.push_condition(`!${slot}`); // block.builders.create.push_condition(`!${slot}`);
block.builders.claim.push_condition(`!${slot}`); // block.builders.claim.push_condition(`!${slot}`);
block.builders.hydrate.push_condition(`!${slot}`); // block.builders.hydrate.push_condition(`!${slot}`);
block.builders.mount.push_condition(`!${slot}`); // block.builders.mount.push_condition(`!${slot}`);
block.builders.update.push_condition(`!${slot}`); // block.builders.update.push_condition(`!${slot}`);
block.builders.destroy.push_condition(`!${slot}`); // block.builders.destroy.push_condition(`!${slot}`);
const listeners = block.event_listeners; const listeners = block.event_listeners;
block.event_listeners = []; block.event_listeners = [];
@ -128,37 +128,37 @@ export default class SlotWrapper extends Wrapper {
block.render_listeners(`_${slot}`); block.render_listeners(`_${slot}`);
block.event_listeners = listeners; block.event_listeners = listeners;
block.builders.create.pop_condition(); // block.builders.create.pop_condition();
block.builders.claim.pop_condition(); // block.builders.claim.pop_condition();
block.builders.hydrate.pop_condition(); // block.builders.hydrate.pop_condition();
block.builders.mount.pop_condition(); // block.builders.mount.pop_condition();
block.builders.update.pop_condition(); // block.builders.update.pop_condition();
block.builders.destroy.pop_condition(); // block.builders.destroy.pop_condition();
block.builders.create.add_line( block.chunks.create.push(
`if (${slot}) ${slot}.c();` b`if (${slot}) ${slot}.c();`
); );
block.builders.claim.add_line( block.chunks.claim.push(
`if (${slot}) ${slot}.l(${parent_nodes});` b`if (${slot}) ${slot}.l(${parent_nodes});`
); );
const mount_leadin = block.builders.mount.toString() !== mount_before const mount_leadin = block.chunks.mount.length !== mount_before.length
? `else` ? `else`
: `if (${slot})`; : `if (${slot})`;
block.builders.mount.add_block(deindent` block.chunks.mount.push(b`
${mount_leadin} { ${mount_leadin} {
${slot}.m(${parent_node || '#target'}, ${parent_node ? 'null' : 'anchor'}); ${slot}.m(${parent_node || '#target'}, ${parent_node ? 'null' : 'anchor'});
} }
`); `);
block.builders.intro.add_line( block.chunks.intro.push(
`@transition_in(${slot}, #local);` b`@transition_in(${slot}, #local);`
); );
block.builders.outro.add_line( block.chunks.outro.push(
`@transition_out(${slot}, #local);` b`@transition_out(${slot}, #local);`
); );
const dynamic_dependencies = Array.from(this.dependencies).filter(name => { const dynamic_dependencies = Array.from(this.dependencies).filter(name => {
@ -171,7 +171,7 @@ export default class SlotWrapper extends Wrapper {
let update_conditions = dynamic_dependencies.map(name => `changed.${name}`).join(' || '); let update_conditions = dynamic_dependencies.map(name => `changed.${name}`).join(' || ');
if (dynamic_dependencies.length > 1) update_conditions = `(${update_conditions})`; if (dynamic_dependencies.length > 1) update_conditions = `(${update_conditions})`;
block.builders.update.add_block(deindent` block.chunks.update.push(b`
if (${slot} && ${slot}.p && ${update_conditions}) { if (${slot} && ${slot}.p && ${update_conditions}) {
${slot}.p( ${slot}.p(
@get_slot_changes(${slot_definition}, ctx, changed, ${get_slot_changes}), @get_slot_changes(${slot_definition}, ctx, changed, ${get_slot_changes}),
@ -180,8 +180,8 @@ export default class SlotWrapper extends Wrapper {
} }
`); `);
block.builders.destroy.add_line( block.chunks.destroy.push(
`if (${slot}) ${slot}.d(detaching);` b`if (${slot}) ${slot}.d(detaching);`
); );
} }
} }

@ -1,3 +1,4 @@
import { b } from 'code-red';
import Wrapper from './shared/Wrapper'; import Wrapper from './shared/Wrapper';
import Renderer from '../Renderer'; import Renderer from '../Renderer';
import Block from '../Block'; import Block from '../Block';
@ -67,8 +68,8 @@ export default class TitleWrapper extends Wrapper {
const init = this.node.should_cache ? `${last} = ${value}` : value; const init = this.node.should_cache ? `${last} = ${value}` : value;
block.builders.init.add_line( block.chunks.init.push(
`@_document.title = ${init};` b`@_document.title = ${init};`
); );
const updater = `@_document.title = ${this.node.should_cache ? last : value};`; const updater = `@_document.title = ${this.node.should_cache ? last : value};`;
@ -85,17 +86,14 @@ export default class TitleWrapper extends Wrapper {
(dependencies.length ? `(${changed_check}) && ${update_cached_value}` : update_cached_value) : (dependencies.length ? `(${changed_check}) && ${update_cached_value}` : update_cached_value) :
changed_check; changed_check;
block.builders.update.add_conditional( block.chunks.update.push(b`if (${condition}) ${updater}`);
condition,
updater
);
} }
} else { } else {
const value = this.node.children.length > 0 const value = this.node.children.length > 0
? stringify((this.node.children[0] as Text).data) ? stringify((this.node.children[0] as Text).data)
: '""'; : '""';
block.builders.hydrate.add_line(`@_document.title = ${value};`); block.chunks.hydrate.push(b`@_document.title = ${value};`);
} }
} }
} }

@ -1,7 +1,7 @@
import Renderer from '../Renderer'; import Renderer from '../Renderer';
import Block from '../Block'; import Block from '../Block';
import Wrapper from './shared/Wrapper'; import Wrapper from './shared/Wrapper';
import deindent from '../../utils/deindent'; import { b } from 'code-red';
import add_event_handlers from './shared/add_event_handlers'; import add_event_handlers from './shared/add_event_handlers';
import Window from '../../nodes/Window'; import Window from '../../nodes/Window';
import add_actions from './shared/add_actions'; import add_actions from './shared/add_actions';
@ -90,7 +90,7 @@ export default class WindowWrapper extends Wrapper {
const x = bindings.scrollX && `this._state.${bindings.scrollX}`; const x = bindings.scrollX && `this._state.${bindings.scrollX}`;
const y = bindings.scrollY && `this._state.${bindings.scrollY}`; const y = bindings.scrollY && `this._state.${bindings.scrollY}`;
renderer.meta_bindings.add_block(deindent` renderer.meta_bindings.push(b`
if (${condition}) { if (${condition}) {
@_scrollTo(${x || '@_window.pageXOffset'}, ${y || '@_window.pageYOffset'}); @_scrollTo(${x || '@_window.pageXOffset'}, ${y || '@_window.pageYOffset'});
} }
@ -98,7 +98,7 @@ export default class WindowWrapper extends Wrapper {
${y && `${y} = @_window.pageYOffset;`} ${y && `${y} = @_window.pageYOffset;`}
`); `);
block.event_listeners.push(deindent` block.event_listeners.push(b`
@listen(@_window, "${event}", () => { @listen(@_window, "${event}", () => {
${scrolling} = true; ${scrolling} = true;
@_clearTimeout(${scrolling_timeout}); @_clearTimeout(${scrolling_timeout});
@ -108,12 +108,12 @@ export default class WindowWrapper extends Wrapper {
`); `);
} else { } else {
props.forEach(prop => { props.forEach(prop => {
renderer.meta_bindings.add_line( renderer.meta_bindings.push(
`this._state.${prop.name} = @_window.${prop.value};` b`this._state.${prop.name} = @_window.${prop.value};`
); );
}); });
block.event_listeners.push(deindent` block.event_listeners.push(b`
@listen(@_window, "${event}", ctx.${handler_name}) @listen(@_window, "${event}", ctx.${handler_name})
`); `);
} }
@ -124,13 +124,13 @@ export default class WindowWrapper extends Wrapper {
referenced: true referenced: true
}); });
component.partly_hoisted.push(deindent` component.partly_hoisted.push(b`
function ${handler_name}() { 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});`)}
} }
`); `);
block.builders.init.add_block(deindent` block.chunks.init.push(b`
@add_render_callback(ctx.${handler_name}); @add_render_callback(ctx.${handler_name});
`); `);
@ -139,7 +139,7 @@ export default class WindowWrapper extends Wrapper {
// special case... might need to abstract this out if we add more special cases // special case... might need to abstract this out if we add more special cases
if (bindings.scrollX || bindings.scrollY) { if (bindings.scrollX || bindings.scrollY) {
block.builders.update.add_block(deindent` block.chunks.update.push(b`
if (${ if (${
[bindings.scrollX, bindings.scrollY].filter(Boolean).map( [bindings.scrollX, bindings.scrollY].filter(Boolean).map(
b => `changed.${b}` b => `changed.${b}`
@ -168,13 +168,13 @@ export default class WindowWrapper extends Wrapper {
referenced: true referenced: true
}); });
component.partly_hoisted.push(deindent` component.partly_hoisted.push(b`
function ${handler_name}() { function ${handler_name}() {
${name} = @_navigator.onLine; $$invalidate('${name}', ${name}); ${name} = @_navigator.onLine; $$invalidate('${name}', ${name});
} }
`); `);
block.builders.init.add_block(deindent` block.chunks.init.push(b`
@add_render_callback(ctx.${handler_name}); @add_render_callback(ctx.${handler_name});
`); `);

@ -1,3 +1,4 @@
import { b } from 'code-red';
import Wrapper from './Wrapper'; import Wrapper from './Wrapper';
import Renderer from '../../Renderer'; import Renderer from '../../Renderer';
import Block from '../../Block'; import Block from '../../Block';
@ -38,10 +39,7 @@ export default class Tag extends Wrapper {
? `(${changed_check}) && ${update_cached_value}` ? `(${changed_check}) && ${update_cached_value}`
: changed_check; : changed_check;
block.builders.update.add_conditional( block.chunks.update.push(b`if (${condition}) ${update(content)}`);
condition,
update(content)
);
} }
return { init: content }; return { init: content };

@ -1,3 +1,4 @@
import { b } from 'code-red';
import Block from '../../Block'; import Block from '../../Block';
import Action from '../../../nodes/Action'; import Action from '../../../nodes/Action';
import Component from '../../../Component'; import Component from '../../../Component';
@ -26,8 +27,8 @@ export default function add_actions(
const fn = component.qualify(action.name); const fn = component.qualify(action.name);
block.builders.mount.add_line( block.chunks.mount.push(
`${name} = ${fn}.call(null, ${target}${snippet ? `, ${snippet}` : ''}) || {};` b`${name} = ${fn}.call(null, ${target}${snippet ? `, ${snippet}` : ''}) || {};`
); );
if (dependencies && dependencies.length > 0) { if (dependencies && dependencies.length > 0) {
@ -35,14 +36,13 @@ export default function add_actions(
const deps = dependencies.map(dependency => `changed.${dependency}`).join(' || '); const deps = dependencies.map(dependency => `changed.${dependency}`).join(' || ');
conditional += dependencies.length > 1 ? `(${deps})` : deps; conditional += dependencies.length > 1 ? `(${deps})` : deps;
block.builders.update.add_conditional( block.chunks.update.push(
conditional, b`if (${conditional}) ${name}.update.call(null, ${snippet});`
`${name}.update.call(null, ${snippet});`
); );
} }
block.builders.destroy.add_line( block.chunks.destroy.push(
`if (${name} && typeof ${name}.destroy === 'function') ${name}.destroy();` b`if (${name} && typeof ${name}.destroy === 'function') ${name}.destroy();`
); );
}); });
} }

@ -1,5 +1,5 @@
import flatten_reference from '../../../utils/flatten_reference'; import flatten_reference from '../../../utils/flatten_reference';
import deindent from '../../../utils/deindent'; import { b } from 'code-red';
import Component from '../../../Component'; import Component from '../../../Component';
import Block from '../../Block'; import Block from '../../Block';
import Binding from '../../../nodes/Binding'; import Binding from '../../../nodes/Binding';
@ -30,10 +30,10 @@ export default function bind_this(component: Component, block: Block, binding: B
lhs = component.source.slice(binding.expression.node.start, binding.expression.node.end).trim(); lhs = component.source.slice(binding.expression.node.start, binding.expression.node.end).trim();
body = binding.expression.node.type === 'Identifier' body = binding.expression.node.type === 'Identifier'
? deindent` ? b`
${component.invalidate(object, `${lhs} = $$value`)}; ${component.invalidate(object, `${lhs} = $$value`)};
` `
: deindent` : b`
${lhs} = $$value; ${lhs} = $$value;
${component.invalidate(object)}; ${component.invalidate(object)};
`; `;
@ -42,7 +42,7 @@ export default function bind_this(component: Component, block: Block, binding: B
const contextual_dependencies = Array.from(binding.expression.contextual_dependencies); const contextual_dependencies = Array.from(binding.expression.contextual_dependencies);
if (contextual_dependencies.length) { if (contextual_dependencies.length) {
component.partly_hoisted.push(deindent` component.partly_hoisted.push(b`
function ${fn}(${['$$value', ...contextual_dependencies].join(', ')}) { function ${fn}(${['$$value', ...contextual_dependencies].join(', ')}) {
if (${lhs} === $$value) return; if (${lhs} === $$value) return;
@binding_callbacks[$$value ? 'unshift' : 'push'](() => { @binding_callbacks[$$value ? 'unshift' : 'push'](() => {
@ -60,7 +60,7 @@ export default function bind_this(component: Component, block: Block, binding: B
const assign = block.get_unique_name(`assign_${variable}`); const assign = block.get_unique_name(`assign_${variable}`);
const unassign = block.get_unique_name(`unassign_${variable}`); const unassign = block.get_unique_name(`unassign_${variable}`);
block.builders.init.add_block(deindent` block.chunks.init.push(b`
const ${assign} = () => ctx.${fn}(${[variable].concat(args).join(', ')}); const ${assign} = () => ctx.${fn}(${[variable].concat(args).join(', ')});
const ${unassign} = () => ctx.${fn}(${['null'].concat(args).join(', ')}); const ${unassign} = () => ctx.${fn}(${['null'].concat(args).join(', ')});
`); `);
@ -70,7 +70,7 @@ export default function bind_this(component: Component, block: Block, binding: B
// we push unassign and unshift assign so that references are // we push unassign and unshift assign so that references are
// nulled out before they're created, to avoid glitches // nulled out before they're created, to avoid glitches
// with shifting indices // with shifting indices
block.builders.update.add_line(deindent` block.chunks.update.push(b`
if (${condition}) { if (${condition}) {
${unassign}(); ${unassign}();
${args.map(a => `${a} = ctx.${a}`).join(', ')}; ${args.map(a => `${a} = ctx.${a}`).join(', ')};
@ -78,11 +78,11 @@ export default function bind_this(component: Component, block: Block, binding: B
}` }`
); );
block.builders.destroy.add_line(`${unassign}();`); block.chunks.destroy.push(b`${unassign}();`);
return `${assign}();`; return `${assign}();`;
} }
component.partly_hoisted.push(deindent` component.partly_hoisted.push(b`
function ${fn}($$value) { function ${fn}($$value) {
@binding_callbacks[$$value ? 'unshift' : 'push'](() => { @binding_callbacks[$$value ? 'unshift' : 'push'](() => {
${body} ${body}
@ -90,6 +90,6 @@ export default function bind_this(component: Component, block: Block, binding: B
} }
`); `);
block.builders.destroy.add_line(`ctx.${fn}(null);`); block.chunks.destroy.push(b`ctx.${fn}(null);`);
return `ctx.${fn}(${variable});`; return b`ctx.${fn}(${variable});`;
} }

@ -1,4 +1,4 @@
import deindent from '../utils/deindent'; import { b } from 'code-red';
import Component from '../Component'; import Component from '../Component';
import { CompileOptions } from '../../interfaces'; import { CompileOptions } from '../../interfaces';
import { stringify } from '../utils/stringify'; import { stringify } from '../utils/stringify';
@ -95,7 +95,7 @@ export default function ssr(
}); });
const main = renderer.has_bindings const main = renderer.has_bindings
? deindent` ? b`
let $$settled; let $$settled;
let $$rendered; let $$rendered;
@ -111,7 +111,7 @@ export default function ssr(
return $$rendered; return $$rendered;
` `
: deindent` : b`
${reactive_store_values} ${reactive_store_values}
${reactive_declarations} ${reactive_declarations}
@ -136,8 +136,8 @@ export default function ssr(
main main
].filter(Boolean); ].filter(Boolean);
return (deindent` return b`
${css.code && deindent` ${css.code && b`
const #css = { const #css = {
code: ${css.code ? stringify(css.code) : `''`}, code: ${css.code ? stringify(css.code) : `''`},
map: ${css.map ? stringify(css.map.toString()) : 'null'} map: ${css.map ? stringify(css.map.toString()) : 'null'}
@ -150,7 +150,7 @@ export default function ssr(
const ${name} = @create_ssr_component(($$result, $$props, $$bindings, $$slots) => { const ${name} = @create_ssr_component(($$result, $$props, $$bindings, $$slots) => {
${blocks.join('\n\n')} ${blocks.join('\n\n')}
}); });
`).trim(); `;
} }
function trim(nodes: INode[]) { function trim(nodes: INode[]) {

@ -1,103 +0,0 @@
import repeat from '../../utils/repeat';
const whitespace = /^\s+$/;
interface Chunk {
parent?: BlockChunk;
type: 'root'|'line'|'condition';
children?: Chunk[];
line?: string;
block?: boolean;
condition?: string;
}
interface BlockChunk extends Chunk {
type: 'root'|'condition';
children: Chunk[];
parent: BlockChunk;
}
export default class CodeBuilder {
root: BlockChunk = { type: 'root', children: [], parent: null };
last: Chunk;
current: BlockChunk;
constructor(str = '') {
this.current = this.last = this.root;
this.add_line(str);
}
add_conditional(condition: string, body: string) {
if (this.last.type === 'condition' && this.last.condition === condition) {
if (body && !whitespace.test(body)) this.last.children.push({ type: 'line', line: body });
} else {
const next = this.last = { type: 'condition', condition, parent: this.current, children: [] };
this.current.children.push(next);
if (body && !whitespace.test(body)) next.children.push({ type: 'line', line: body });
}
}
add_line(line: string) {
if (line && !whitespace.test(line)) this.current.children.push(this.last = { type: 'line', line });
}
add_block(block: string) {
if (block && !whitespace.test(block)) this.current.children.push(this.last = { type: 'line', line: block, block: true });
}
is_empty() { return !find_line(this.root); }
push_condition(condition: string) {
if (this.last.type === 'condition' && this.last.condition === condition) {
this.current = this.last as BlockChunk;
} else {
const next = this.last = { type: 'condition', condition, parent: this.current, children: [] };
this.current.children.push(next);
this.current = next;
}
}
pop_condition() {
if (!this.current.parent) throw new Error(`Popping a condition that maybe wasn't pushed.`);
this.current = this.current.parent;
}
toString() {
return chunk_to_string(this.root);
}
}
function find_line(chunk: BlockChunk) {
for (const c of chunk.children) {
if (c.type === 'line' || find_line(c as BlockChunk)) return true;
}
return false;
}
function chunk_to_string(chunk: Chunk, level: number = 0, last_block?: boolean, first?: boolean): string {
if (chunk.type === 'line') {
return `${last_block || (!first && chunk.block) ? '\n' : ''}${chunk.line.replace(/^/gm, repeat('\t', level))}`;
} else if (chunk.type === 'condition') {
let t = false;
const lines = chunk.children.map((c, i) => {
const str = chunk_to_string(c, level + 1, t, i === 0);
t = c.type !== 'line' || c.block;
return str;
}).filter(l => !!l);
if (!lines.length) return '';
return `${last_block || (!first) ? '\n' : ''}${repeat('\t', level)}if (${chunk.condition}) {\n${lines.join('\n')}\n${repeat('\t', level)}}`;
} else if (chunk.type === 'root') {
let t = false;
const lines = chunk.children.map((c, i) => {
const str = chunk_to_string(c, 0, t, i === 0);
t = c.type !== 'line' || c.block;
return str;
}).filter(l => !!l);
if (!lines.length) return '';
return lines.join('\n');
}
}

@ -1,171 +1,6 @@
import * as assert from 'assert'; import * as assert from 'assert';
import deindent from './deindent';
import CodeBuilder from './CodeBuilder';
import get_name_from_filename from './get_name_from_filename'; import get_name_from_filename from './get_name_from_filename';
describe('deindent', () => {
it('deindents a simple string', () => {
const deindented = deindent`
deindent me please
`;
assert.equal(deindented, `deindent me please`);
});
it('deindents a multiline string', () => {
const deindented = deindent`
deindent me please
and me as well
`;
assert.equal(deindented, `deindent me please\nand me as well`);
});
it('preserves indentation of inserted values', () => {
const insert = deindent`
line one
line two
`;
const deindented = deindent`
before
${insert}
after
`;
assert.equal(deindented, `before\n\tline one\n\tline two\nafter`);
});
it('removes newlines before an empty expression', () => {
const deindented = deindent`
{
some text
${null}
}`;
assert.equal(deindented, `{\n\tsome text\n}`);
});
it('removes newlines after an empty expression', () => {
const deindented = deindent`
{
${null}
some text
}`;
assert.equal(deindented, `{\n\tsome text\n}`);
});
it('removes newlines around empty expressions', () => {
const deindented = deindent`
{
${null}
some text
${null}
some text
${null}
}`;
assert.equal(deindented, `{\n\tsome text\n\n\tsome text\n}`);
});
});
describe('CodeBuilder', () => {
it('creates an empty block', () => {
const builder = new CodeBuilder();
assert.equal(builder.toString(), '');
});
it('creates a block with a line', () => {
const builder = new CodeBuilder();
builder.add_line('var answer = 42;');
assert.equal(builder.toString(), 'var answer = 42;');
});
it('creates a block with two lines', () => {
const builder = new CodeBuilder();
builder.add_line('var problems = 99;');
builder.add_line('var answer = 42;');
assert.equal(builder.toString(), 'var problems = 99;\nvar answer = 42;');
});
it('adds newlines around blocks', () => {
const builder = new CodeBuilder();
builder.add_line('// line 1');
builder.add_line('// line 2');
builder.add_block(deindent`
if (foo) {
bar();
}
`);
builder.add_line('// line 3');
builder.add_line('// line 4');
assert.equal(
builder.toString(),
deindent`
// line 1
// line 2
if (foo) {
bar();
}
// line 3
// line 4
`
);
});
it('nests codebuilders with correct indentation', () => {
const child = new CodeBuilder();
child.add_block(deindent`
var obj = {
answer: 42
};
`);
const builder = new CodeBuilder();
builder.add_line('// line 1');
builder.add_line('// line 2');
builder.add_block(deindent`
if (foo) {
${child}
}
`);
builder.add_line('// line 3');
builder.add_line('// line 4');
assert.equal(
builder.toString(),
deindent`
// line 1
// line 2
if (foo) {
var obj = {
answer: 42
};
}
// line 3
// line 4
`
);
});
});
describe('get_name_from_filename', () => { describe('get_name_from_filename', () => {
it('uses the basename', () => { it('uses the basename', () => {
assert.equal(get_name_from_filename('path/to/Widget.svelte'), 'Widget'); assert.equal(get_name_from_filename('path/to/Widget.svelte'), 'Widget');

Loading…
Cancel
Save