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

39
package-lock.json generated

@ -1,6 +1,6 @@
{
"name": "svelte",
"version": "3.11.0",
"version": "3.12.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@ -330,6 +330,12 @@
"integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==",
"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": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz",
@ -501,6 +507,28 @@
"integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
"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": {
"version": "3.5.0",
"resolved": "https://registry.npmjs.org/codecov/-/codecov-3.5.0.tgz",
@ -2705,6 +2733,15 @@
"integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=",
"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": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",

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

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

@ -1,11 +1,11 @@
import Component from '../../Component';
import { walk } from 'estree-walker';
import is_reference from 'is-reference';
import { b } from 'code-red';
import flatten_reference from '../../utils/flatten_reference';
import { create_scopes, Scope, extract_names } from '../../utils/scope';
import { Node } from '../../../interfaces';
import { globals , sanitize } from '../../../utils/names';
import deindent from '../../utils/deindent';
import Wrapper from '../../render_dom/wrappers/shared/Wrapper';
import TemplateScope from './TemplateScope';
import get_object from '../../utils/get_object';
@ -79,7 +79,7 @@ export default class Expression {
scope_map: WeakMap<Node, Scope>;
is_synthetic: boolean;
declarations: string[] = [];
declarations: Node[] = [];
uses_context = false;
rendered: string;
@ -364,7 +364,7 @@ export default class Expression {
referenced: true
});
declarations.push(deindent`
declarations.push(b`
function ${name}(${original_params ? '...args' : ''}) {
return ctx.${name}(ctx${original_params ? ', ...args' : ''});
}
@ -407,7 +407,7 @@ export default class Expression {
if (declarations.length > 0) {
block.maintain_context = true;
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 Wrapper from './wrappers/shared/Wrapper';
import { escape } from '../utils/stringify';
import { b, x } from 'code-red';
import { Node } from '../../interfaces';
export interface BlockOptions {
parent?: Block;
@ -31,19 +31,19 @@ export default class Block {
bindings: Map<string, { object: string; property: string; snippet: string; store: string; tail: string }>;
builders: {
init: CodeBuilder;
create: CodeBuilder;
claim: CodeBuilder;
hydrate: CodeBuilder;
mount: CodeBuilder;
measure: CodeBuilder;
fix: CodeBuilder;
animate: CodeBuilder;
intro: CodeBuilder;
update: CodeBuilder;
outro: CodeBuilder;
destroy: CodeBuilder;
chunks: {
init: Node[];
create: Node[];
claim: Node[];
hydrate: Node[];
mount: Node[];
measure: Node[];
fix: Node[];
animate: Node[];
intro: Node[];
update: Node[];
outro: Node[];
destroy: Node[];
};
event_listeners: string[] = [];
@ -80,19 +80,19 @@ export default class Block {
this.bindings = options.bindings;
this.builders = {
init: new CodeBuilder(),
create: new CodeBuilder(),
claim: new CodeBuilder(),
hydrate: new CodeBuilder(),
mount: new CodeBuilder(),
measure: new CodeBuilder(),
fix: new CodeBuilder(),
animate: new CodeBuilder(),
intro: new CodeBuilder(),
update: new CodeBuilder(),
outro: new CodeBuilder(),
destroy: new CodeBuilder(),
this.chunks = {
init: [],
create: [],
claim: [],
hydrate: [],
mount: [],
measure: [],
fix: [],
animate: [],
intro: [],
update: [],
outro: [],
destroy: [],
};
this.has_animation = false;
@ -160,18 +160,18 @@ export default class Block {
no_detach?: boolean
) {
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) {
this.builders.claim.add_line(`${name} = ${claim_statement || render_statement};`);
this.chunks.claim.push(b`${name} = ${claim_statement || render_statement};`);
}
if (parent_node) {
this.builders.mount.add_line(`@append(${parent_node}, ${name});`);
if (parent_node === '@_document.head' && !no_detach) this.builders.destroy.add_line(`@detach(${name});`);
this.chunks.mount.push(b`@append(${parent_node}, ${name});`);
if (parent_node === '@_document.head' && !no_detach) this.chunks.destroy.push(b`@detach(${name});`);
} else {
this.builders.mount.add_line(`@insert(#target, ${name}, anchor);`);
if (!no_detach) this.builders.destroy.add_conditional('detaching', `@detach(${name});`);
this.chunks.mount.push(b`@insert(#target, ${name}, anchor);`);
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 }));
}
get_contents(local_key?: string) {
get_contents(key?: any) {
const { dev } = this.renderer.options;
if (this.has_outros) {
this.add_variable('#current');
if (!this.builders.intro.is_empty()) {
this.builders.intro.add_line(`#current = true;`);
this.builders.mount.add_line(`#current = true;`);
if (this.chunks.intro.length > 0) {
this.chunks.intro.push(b`#current = true;`);
this.chunks.mount.push(b`#current = true;`);
}
if (!this.builders.outro.is_empty()) {
this.builders.outro.add_line(`#current = false;`);
if (this.chunks.outro.length > 0) {
this.chunks.outro.push(b`#current = false;`);
}
}
if (this.autofocus) {
this.builders.mount.add_line(`${this.autofocus}.focus();`);
this.chunks.mount.push(b`${this.autofocus}.focus();`);
}
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.add_block(`key: ${local_key},`);
}
if (this.first) {
properties.add_block(`first: null,`);
this.builders.hydrate.add_line(`this.first = ${this.first};`);
}
properties.key = key
properties.first = this.first;
if (this.builders.create.is_empty() && this.builders.hydrate.is_empty()) {
properties.add_line(`c: @noop,`);
if (this.chunks.create.length === 0 && this.chunks.hydrate.length === 0) {
properties.create = noop;
} else {
const hydrate = !this.builders.hydrate.is_empty() && (
const hydrate = this.chunks.hydrate.length > 0 && (
this.renderer.options.hydratable
? `this.h()`
: this.builders.hydrate
? b`this.h();`
: this.chunks.hydrate
);
properties.add_block(deindent`
${method_name('c', 'create')}() {
${this.builders.create}
${hydrate}
},
`);
properties.create = b`function create() {
${this.chunks.create}
${hydrate}
}`;
}
if (this.renderer.options.hydratable || !this.builders.claim.is_empty()) {
if (this.builders.claim.is_empty() && this.builders.hydrate.is_empty()) {
properties.add_line(`l: @noop,`);
if (this.renderer.options.hydratable || this.chunks.claim.length > 0) {
if (this.chunks.claim.length === 0 && this.chunks.hydrate.length === 0) {
properties.claim = noop;
} else {
properties.add_block(deindent`
${method_name('l', 'claim')}(nodes) {
${this.builders.claim}
${this.renderer.options.hydratable && !this.builders.hydrate.is_empty() && `this.h();`}
},
`);
properties.claim = x`function claim(#nodes) {
${this.chunks.claim}
${this.renderer.options.hydratable && this.chunks.hydrate.length > 0 && b`this.h();`}
}`;
}
}
if (this.renderer.options.hydratable && !this.builders.hydrate.is_empty()) {
properties.add_block(deindent`
${method_name('h', 'hydrate')}() {
${this.builders.hydrate}
},
`);
if (this.renderer.options.hydratable && this.chunks.hydrate.length > 0) {
properties.hydrate = x`function hydrate() {
${this.chunks.hydrate}
}`;
}
if (this.builders.mount.is_empty()) {
properties.add_line(`m: @noop,`);
if (this.chunks.mount.length === 0) {
properties.mount = noop;
} else {
properties.add_block(deindent`
${method_name('m', 'mount')}(#target, anchor) {
${this.builders.mount}
},
`);
properties.mount = x`function mount(#target, anchor) {
${this.chunks.mount}
}`;
}
if (this.has_update_method || this.maintain_context) {
if (this.builders.update.is_empty() && !this.maintain_context) {
properties.add_line(`p: @noop,`);
if (this.chunks.update.length === 0 && !this.maintain_context) {
properties.update = noop;
} else {
properties.add_block(deindent`
${method_name('p', 'update')}(changed, ${this.maintain_context ? 'new_ctx' : 'ctx'}) {
${this.maintain_context && `ctx = new_ctx;`}
${this.builders.update}
},
`);
const ctx = this.maintain_context ? x`new_ctx` : x`ctx`;
properties.update = x`function update(#changed, ${ctx}) {
${this.maintain_context && b`ctx = ${ctx};`}
${this.chunks.update}
}`;
}
}
if (this.has_animation) {
properties.add_block(deindent`
${method_name('r', 'measure')}() {
${this.builders.measure}
},
${method_name('f', 'fix')}() {
${this.builders.fix}
},
${method_name('a', 'animate')}() {
${this.builders.animate}
},
`);
properties.measure = x`function measure() {
${this.chunks.measure}
}`;
properties.fix = x`function fix() {
${this.chunks.fix}
}`;
properties.animate = x`function animate() {
${this.chunks.animate}
}`;
}
if (this.has_intro_method || this.has_outro_method) {
if (this.builders.intro.is_empty()) {
properties.add_line(`i: @noop,`);
if (this.chunks.intro.length === 0) {
properties.intro = noop;
} else {
properties.add_block(deindent`
${method_name('i', 'intro')}(#local) {
${this.has_outros && `if (#current) return;`}
${this.builders.intro}
},
`);
properties.intro = x`function intro(#local) {
${this.has_outros && b`if (#current) return;`}
${this.chunks.intro}
}`;
}
if (this.builders.outro.is_empty()) {
properties.add_line(`o: @noop,`);
if (this.chunks.outro.length === 0) {
properties.outro = noop;
} else {
properties.add_block(deindent`
${method_name('o', 'outro')}(#local) {
${this.builders.outro}
},
`);
properties.outro = x`function outro(#local) {
${this.chunks.outro}
}`;
}
}
if (this.builders.destroy.is_empty()) {
properties.add_line(`d: @noop`);
if (this.chunks.destroy.length === 0) {
properties.destroy = noop;
} else {
properties.add_block(deindent`
${method_name('d', 'destroy')}(detaching) {
${this.builders.destroy}
}
`);
properties.destroy = x`function destroy(detaching) {
${this.chunks.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 */
return deindent`
${this.variables.size > 0 &&
`var ${Array.from(this.variables.keys())
.map(key => {
const init = this.variables.get(key);
return init !== undefined ? `${key} = ${init}` : key;
})
.join(', ')};`}
return b`
${Array.from(this.variables.entries()).map(([init, id]) => {
const id_node = { type: 'Identifier', name: id };
const init_node = { type: 'Identifier', name: init };
return b`let ${id_node} = ${init_node}`;
})}
${!this.builders.init.is_empty() && this.builders.init}
${this.chunks.init}
${dev
? deindent`
const block = {
${properties}
};
? b`
const block = ${return_value};
@dispatch_dev("SvelteRegisterBlock", { block, id: ${this.name || 'create_fragment'}.name, type: "${this.type}", source: "${this.comment ? this.comment.replace(/"/g, '\\"') : ''}", ctx });
return block;`
: deindent`
return {
${properties}
};`
: b`
return ${return_value};`
}
`.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 */
}
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 = '') {
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) {
this.builders.hydrate.add_line(
`#dispose${chunk} = ${this.event_listeners[0]};`
this.chunks.hydrate.push(
b`${dispose} = ${this.event_listeners[0]};`
);
this.builders.destroy.add_line(
`#dispose${chunk}();`
this.chunks.destroy.push(
b`${dispose}();`
);
} else {
this.builders.hydrate.add_block(deindent`
#dispose${chunk} = [
this.chunks.hydrate.push(b`
${dispose} = [
${this.event_listeners.join(',\n')}
];
`);
this.builders.destroy.add_line(
`@run_all(#dispose${chunk});`
this.chunks.destroy.push(
b`@run_all(${dispose});`
);
}
}
}
toString() {
const local_key = this.key && this.get_unique_name('key');
// toString() {
// const local_key = this.key && this.get_unique_name('key');
return deindent`
${this.comment && `// ${escape(this.comment, { only_escape_at_symbol: true })}`}
function ${this.name}(${this.key ? `${local_key}, ` : ''}ctx) {
${this.get_contents(local_key)}
}
`;
}
// return deindent`
// ${this.comment && `// ${escape(this.comment, { only_escape_at_symbol: true })}`}
// function ${this.name}(${this.key ? `${local_key}, ` : ''}ctx) {
// ${this.get_contents(local_key)}
// }
// `;
// }
}

@ -1,8 +1,7 @@
import Block from './Block';
import { CompileOptions } from '../../interfaces';
import { CompileOptions, Node } from '../../interfaces';
import Component from '../Component';
import FragmentWrapper from './wrappers/Fragment';
import CodeBuilder from '../utils/CodeBuilder';
export default class Renderer {
component: Component; // TODO Maybe Renderer shouldn't know about Component?
@ -10,7 +9,7 @@ export default class Renderer {
blocks: Array<Block | string> = [];
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[] = [];
block: Block;

@ -1,6 +1,6 @@
import { b, x } from 'code-red';
import deindent from '../utils/deindent';
import { stringify, escape } from '../utils/stringify';
import CodeBuilder from '../utils/CodeBuilder';
import Component from '../Component';
import Renderer from './Renderer';
import { CompileOptions } from '../../interfaces';
@ -22,12 +22,12 @@ export default function dom(
block.has_outro_method = true;
// 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) {
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);
@ -38,7 +38,7 @@ export default function dom(
const add_css = component.get_unique_name('add_css');
if (styles && component.compile_options.css !== false && !options.customElement) {
builder.add_block(deindent`
body.push(b`
function ${add_css}() {
var style = @element("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
const blocks = renderer.blocks.slice().reverse();
blocks.forEach(block => {
builder.add_block(block.toString());
});
body.push(...blocks);
if (options.dev && !options.hydratable) {
block.builders.claim.add_line(
'throw new @_Error("options.hydrate only works if the component was compiled with the `hydratable: true` option");'
block.chunks.claim.push(
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 */
const set = (uses_props || writable_props.length > 0 || component.slots.size > 0)
? deindent`
? x`
${$$props} => {
${uses_props && component.invalidate('$$props', `$$props = @assign(@assign({}, $$props), $$new_props)`)}
${writable_props.map(prop =>
@ -90,7 +88,7 @@ export default function dom(
: null;
/* eslint-enable @typescript-eslint/indent,indent */
const body = [];
const accessors = [];
const not_equal = component.component_options.immutable ? `@not_equal` : `@safe_not_equal`;
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);
if (!variable.writable || component.component_options.accessors) {
body.push(deindent`
accessors.push(deindent`
get ${x.export_name}() {
return ${x.hoistable ? x.name : 'this.$$.ctx.' + x.name};
}
`);
} else if (component.compile_options.dev) {
body.push(deindent`
accessors.push(deindent`
get ${x.export_name}() {
throw new @_Error("<${component.tag}>: Props cannot be read directly from the component instance unless compiling with 'accessors: true' or '<svelte:options accessors/>'");
}
@ -114,21 +112,21 @@ export default function dom(
if (component.component_options.accessors) {
if (variable.writable && !renderer.readonly.has(x.name)) {
body.push(deindent`
accessors.push(deindent`
set ${x.export_name}(${x.name}) {
this.$set({ ${x.name === x.export_name ? x.name : `${x.export_name}: ${x.name}`} });
@flush();
}
`);
} else if (component.compile_options.dev) {
body.push(deindent`
accessors.push(deindent`
set ${x.export_name}(value) {
throw new @_Error("<${component.tag}>: Cannot set read-only property '${x.export_name}'");
}
`);
}
} else if (component.compile_options.dev) {
body.push(deindent`
accessors.push(deindent`
set ${x.export_name}(value) {
throw new @_Error("<${component.tag}>: Props cannot be set directly on the component instance unless compiling with 'accessors: true' or '<svelte:options accessors/>'");
}
@ -141,35 +139,35 @@ export default function dom(
const expected = props.filter(prop => !prop.initialised);
if (expected.length) {
dev_props_check = deindent`
dev_props_check = b`
const { ctx } = this.$$;
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)) {
@_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(", ")} };
}
` : deindent`
` : x`
() => {
return {};
}
`;
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} => {
${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}`)};
`)}
}
` : deindent`
` : x`
${$$props} => {}
`;
}
@ -231,7 +229,7 @@ export default function dom(
args.push('$$props', '$$invalidate');
}
builder.add_block(deindent`
body.push(b`
function create_fragment(ctx) {
${block.get_contents()}
}
@ -288,7 +286,7 @@ export default function dom(
const variable = component.var_lookup.get(store.name.slice(1));
return !variable || variable.hoistable;
})
.map(({ name }) => deindent`
.map(({ name }) => b`
${component.compile_options.dev && `@validate_store(${name.slice(1)}, '${name.slice(1)}');`}
@component_subscribe($$self, ${name.slice(1)}, $$value => { ${name} = $$value; $$invalidate('${name}', ${name}); });
`);
@ -345,7 +343,7 @@ export default function dom(
let unknown_props_check;
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(', ')}];
@_Object.keys($$props).forEach(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(', ')}) {
${reactive_store_declarations.length > 0 && `let ${reactive_store_declarations.join(', ')};`}
@ -379,7 +377,7 @@ export default function dom(
${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(', ')} }) => {
${reactive_declarations}
};
@ -395,7 +393,7 @@ export default function dom(
const prop_names = `[${props.map(v => JSON.stringify(v.export_name)).join(', ')}]`;
if (options.customElement) {
builder.add_block(deindent`
body.push(b`
class ${name} extends @SvelteElement {
constructor(options) {
super();
@ -411,7 +409,7 @@ export default function dom(
@insert(options.target, this, options.anchor);
}
${(props.length > 0 || uses_props) && deindent`
${(props.length > 0 || uses_props) && b`
if (options.props) {
this.$set(options.props);
@flush();
@ -429,14 +427,16 @@ export default function dom(
`);
if (component.tag != null) {
builder.add_block(deindent`
body.push(b`
@_customElements.define("${component.tag}", ${name});
`);
}
} else {
const superclass = options.dev ? 'SvelteComponentDev' : 'SvelteComponent';
builder.add_block(deindent`
// TODO add accessors
body.push(b`
class ${name} extends @${superclass} {
constructor(options) {
super(${options.dev && `options`});
@ -446,11 +446,9 @@ export default function dom(
${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 AwaitBlock from '../../nodes/AwaitBlock';
import create_debugging_comment from './shared/create_debugging_comment';
import deindent from '../../utils/deindent';
import { b } from 'code-red';
import FragmentWrapper from './Fragment';
import PendingBlock from '../../nodes/PendingBlock';
import ThenBlock from '../../nodes/ThenBlock';
@ -147,22 +147,22 @@ export default class AwaitBlockWrapper extends Wrapper {
this.pending.block.has_outro_method && `blocks: [,,,]`
].filter(Boolean);
block.builders.init.add_block(deindent`
block.chunks.init.push(b`
let ${info} = {
${info_props.join(',\n')}
};
`);
block.builders.init.add_block(deindent`
block.chunks.init.push(b`
@handle_promise(${promise} = ${snippet}, ${info});
`);
block.builders.create.add_block(deindent`
block.chunks.create.push(b`
${info}.block.c();
`);
if (parent_nodes && this.renderer.options.hydratable) {
block.builders.claim.add_block(deindent`
block.chunks.claim.push(b`
${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;
block.builders.mount.add_block(deindent`
block.chunks.mount.push(b`
${info}.block.m(${initial_mount_node}, ${info}.anchor = ${anchor_node});
${info}.mount = () => ${update_mount_node};
${info}.anchor = ${anchor};
`);
if (has_transitions) {
block.builders.intro.add_line(`@transition_in(${info}.block);`);
block.chunks.intro.push(b`@transition_in(${info}.block);`);
}
const conditions = [];
@ -195,12 +195,12 @@ export default class AwaitBlockWrapper extends Wrapper {
`@handle_promise(${promise}, ${info})`
);
block.builders.update.add_line(
`${info}.ctx = ctx;`
block.chunks.update.push(
b`${info}.ctx = ctx;`
);
if (this.pending.block.has_update_method) {
block.builders.update.add_block(deindent`
block.chunks.update.push(b`
if (${conditions.join(' && ')}) {
// nothing
} else {
@ -208,20 +208,20 @@ export default class AwaitBlockWrapper extends Wrapper {
}
`);
} else {
block.builders.update.add_block(deindent`
block.chunks.update.push(b`
${conditions.join(' && ')}
`);
}
} else {
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));
`);
}
}
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) {
const block = ${info}.blocks[#i];
@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}.token = null;
${info} = null;

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

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

@ -4,7 +4,7 @@ import Wrapper from './shared/Wrapper';
import create_debugging_comment from './shared/create_debugging_comment';
import EachBlock from '../../nodes/EachBlock';
import FragmentWrapper from './Fragment';
import deindent from '../../utils/deindent';
import { b } from 'code-red';
import ElseBlock from '../../nodes/ElseBlock';
import { attach_head } from '../../utils/tail';
@ -123,8 +123,8 @@ export default class EachBlockWrapper extends Wrapper {
view_length: fixed_length === null ? `${iterations}.[✂${c}-${c+4}✂]` : fixed_length
};
const store =
node.expression.node.type === 'Identifier' &&
const store =
node.expression.node.type === 'Identifier' &&
node.expression.node.name[0] === '$'
? node.expression.node.name.slice(1)
: null;
@ -188,9 +188,9 @@ export default class EachBlockWrapper extends Wrapper {
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) {
const child_ctx = @_Object.create(ctx);
${this.context_props}
@ -223,7 +223,7 @@ export default class EachBlockWrapper extends Wrapper {
}
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) {
@transition_in(${this.vars.iterations}[#i]);
}
@ -242,24 +242,24 @@ export default class EachBlockWrapper extends Wrapper {
if (this.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
block.builders.init.add_block(deindent`
block.chunks.init.push(b`
if (!${this.vars.data_length}) {
${each_block_else} = ${this.else.block.name}(ctx);
${each_block_else}.c();
}
`);
block.builders.mount.add_block(deindent`
block.chunks.mount.push(b`
if (${each_block_else}) {
${each_block_else}.m(${initial_mount_node}, ${initial_anchor_node});
}
`);
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}) {
${each_block_else}.p(changed, ctx);
} else if (!${this.vars.data_length}) {
@ -272,7 +272,7 @@ export default class EachBlockWrapper extends Wrapper {
}
`);
} else {
block.builders.update.add_block(deindent`
block.chunks.update.push(b`
if (${this.vars.data_length}) {
if (${each_block_else}) {
${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'});
`);
}
@ -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 => ${
// @ts-ignore todo: probably error
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) {
${iterations}[#i].c();
}
`);
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) {
${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) {
${iterations}[#i].m(${initial_mount_node}, ${initial_anchor_node});
}
@ -384,7 +384,7 @@ export default class EachBlockWrapper extends Wrapper {
? `@outro_and_destroy_block`
: `@destroy_block`;
block.builders.update.add_block(deindent`
block.chunks.update.push(b`
const ${this.vars.each_block_value} = ${snippet};
${this.block.has_outros && `@group_outros();`}
@ -395,14 +395,14 @@ export default class EachBlockWrapper extends Wrapper {
`);
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) {
@transition_out(${iterations}[#i]);
}
`);
}
block.builders.destroy.add_block(deindent`
block.chunks.destroy.push(b`
for (let #i = 0; #i < ${view_length}; #i += 1) {
${iterations}[#i].d(${parent_node ? '' : 'detaching'});
}
@ -435,7 +435,7 @@ export default class EachBlockWrapper extends Wrapper {
view_length
} = this.vars;
block.builders.init.add_block(deindent`
block.chunks.init.push(b`
let ${iterations} = [];
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) {
${iterations}[#i].c();
}
`);
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) {
${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) {
${iterations}[#i].m(${initial_mount_node}, ${initial_anchor_node});
}
@ -477,7 +477,7 @@ export default class EachBlockWrapper extends Wrapper {
if (condition !== '') {
const for_loop_body = this.block.has_update_method
? deindent`
? b`
if (${iterations}[#i]) {
${iterations}[#i].p(changed, child_ctx);
${has_transitions && `@transition_in(${this.vars.iterations}[#i], 1);`}
@ -489,7 +489,7 @@ export default class EachBlockWrapper extends Wrapper {
}
`
: has_transitions
? deindent`
? b`
if (${iterations}[#i]) {
@transition_in(${this.vars.iterations}[#i], 1);
} else {
@ -499,7 +499,7 @@ export default class EachBlockWrapper extends Wrapper {
${iterations}[#i].m(${update_mount_node}, ${update_anchor_node});
}
`
: deindent`
: b`
if (!${iterations}[#i]) {
${iterations}[#i] = ${create_each_block}(child_ctx);
${iterations}[#i].c();
@ -514,12 +514,12 @@ export default class EachBlockWrapper extends Wrapper {
if (this.block.has_outros) {
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, () => {
${iterations}[i] = null;
});
`);
remove_old_blocks = deindent`
remove_old_blocks = b`
@group_outros();
for (#i = ${this.vars.each_block_value}.${length}; #i < ${view_length}; #i += 1) {
${out}(#i);
@ -527,7 +527,7 @@ export default class EachBlockWrapper extends Wrapper {
@check_outros();
`;
} 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) {
${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
// 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.vars.each_block_value} = ${snippet};
@ -551,7 +551,7 @@ export default class EachBlockWrapper extends Wrapper {
${remove_old_blocks}
`;
block.builders.update.add_block(deindent`
block.chunks.update.push(b`
if (${condition}) {
${update}
}
@ -559,7 +559,7 @@ export default class EachBlockWrapper extends Wrapper {
}
if (this.block.has_outros) {
block.builders.outro.add_block(deindent`
block.chunks.outro.push(b`
${iterations} = ${iterations}.filter(@_Boolean);
for (let #i = 0; #i < ${view_length}; #i += 1) {
@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 ElementWrapper from './index';
import { stringify } from '../../../utils/stringify';
import deindent from '../../../utils/deindent';
import { b } from 'code-red';
import Expression from '../../../nodes/shared/Expression';
import Text from '../../../nodes/Text';
@ -105,8 +105,8 @@ export default class AttributeWrapper {
const init = should_cache ? `${last} = ${value}` : value;
if (is_legacy_input_type) {
block.builders.hydrate.add_line(
`@set_input_type(${element.var}, ${init});`
block.chunks.hydrate.push(
b`@set_input_type(${element.var}, ${init});`
);
updater = `@set_input_type(${element.var}, ${should_cache ? last : value});`;
} else if (is_select_value_attribute) {
@ -116,15 +116,15 @@ export default class AttributeWrapper {
const option = block.get_unique_name('option');
const if_statement = is_multiple_select
? deindent`
? b`
${option}.selected = ~${last}.indexOf(${option}.__value);`
: deindent`
: b`
if (${option}.__value === ${last}) {
${option}.selected = true;
break;
}`;
updater = deindent`
updater = b`
for (var ${i} = 0; ${i} < ${element.var}.options.length; ${i} += 1) {
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};
${updater}
`);
} else if (property_name) {
block.builders.hydrate.add_line(
`${element.var}.${property_name} = ${init};`
block.chunks.hydrate.push(
b`${element.var}.${property_name} = ${init};`
);
updater = block.renderer.options.dev
? `@prop_dev(${element.var}, "${property_name}", ${should_cache ? last : value});`
: `${element.var}.${property_name} = ${should_cache ? last : value};`;
} else {
block.builders.hydrate.add_line(
`${method}(${element.var}, "${name}", ${init});`
block.chunks.hydrate.push(
b`${method}(${element.var}, "${name}", ${init});`
);
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)
: changed_check;
block.builders.update.add_conditional(
condition,
updater
);
block.chunks.update.push(b`if (${condition}) ${updater}`);
} else {
const value = this.node.get_value(block);
const statement = (
is_legacy_input_type
? `@set_input_type(${element.var}, ${value});`
? b`@set_input_type(${element.var}, ${value});`
: property_name
? `${element.var}.${property_name} = ${value};`
: `${method}(${element.var}, "${name}", ${value === true ? '""' : value});`
? b`${element.var}.${property_name} = ${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
if (this.node.is_true && name === 'autofocus') {
@ -185,10 +182,10 @@ export default class AttributeWrapper {
}
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);
if (this.node.get_dependencies().length > 0) block.builders.update.add_line(update_value);
block.chunks.hydrate.push(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 ElementWrapper from '../Element';
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);
block.builders.hydrate.add_line(
`ctx.$$binding_groups[${binding_group}].push(${parent.var});`
block.chunks.hydrate.push(
b`ctx.$$binding_groups[${binding_group}].push(${parent.var});`
);
block.builders.destroy.add_line(
`ctx.$$binding_groups[${binding_group}].splice(ctx.$$binding_groups[${binding_group}].indexOf(${parent.var}), 1);`
block.chunks.destroy.push(
b`ctx.$$binding_groups[${binding_group}].splice(ctx.$$binding_groups[${binding_group}].indexOf(${parent.var}), 1);`
);
break;
}
@ -154,7 +155,7 @@ export default class BindingWrapper {
block.add_variable(last, 'true');
update_conditions.push(`${last} !== (${last} = ${this.snippet})`);
update_dom = `${parent.var}[${last} ? "pause" : "play"]();`;
update_dom = b`${parent.var}[${last} ? "pause" : "play"]();`;
break;
}
@ -165,15 +166,15 @@ export default class BindingWrapper {
}
if (update_dom) {
block.builders.update.add_line(
update_conditions.length ? `if (${update_conditions.join(' && ')}) ${update_dom}` : update_dom
block.chunks.update.push(
update_conditions.length ? b`if (${update_conditions.join(' && ')}) ${update_dom}` : update_dom
);
}
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)) {
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') {
return node.get_static_attribute_value('multiple') === true ?
`@select_options(${element.var}, ${binding.snippet})` :
`@select_option(${element.var}, ${binding.snippet})`;
b`@select_options(${element.var}, ${binding.snippet})` :
b`@select_option(${element.var}, ${binding.snippet})`;
}
if (binding.node.name === 'group') {
const type = node.get_static_attribute_value('type');
const condition = type === 'checkbox'
? `~${binding.snippet}.indexOf(${element.var}.__value)`
: `${element.var}.__value === ${binding.snippet}`;
? b`~${binding.snippet}.indexOf(${element.var}.__value)`
: b`${element.var}.__value === ${binding.snippet}`;
return `${element.var}.checked = ${condition};`;
}
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) {

@ -1,3 +1,4 @@
import { b } from 'code-red';
import Attribute from '../../../nodes/Attribute';
import Block from '../../Block';
import AttributeWrapper from './Attribute';
@ -49,17 +50,18 @@ export default class StyleAttributeWrapper extends AttributeWrapper {
dependencies.map(dependency => `changed.${dependency}`).join(' || ')
);
block.builders.update.add_conditional(
condition,
`@set_style(${this.parent.var}, "${prop.key}", ${value}${prop.important ? ', 1' : ''});`
block.chunks.update.push(
b`if (${condition}) {
@set_style(${this.parent.var}, "${prop.key}", ${value}${prop.important ? ', 1' : ''});
}`
);
}
} else {
value = stringify((prop.value[0] as Text).data);
}
block.builders.hydrate.add_line(
`@set_style(${this.parent.var}, "${prop.key}", ${value}${prop.important ? ', 1' : ''});`
block.chunks.hydrate.push(
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 TextWrapper from '../Text';
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 AttributeWrapper from './Attribute';
import StyleAttributeWrapper from './StyleAttribute';
@ -250,45 +250,45 @@ export default class ElementWrapper extends Wrapper {
block.add_variable(node);
const render_statement = this.get_render_statement();
block.builders.create.add_line(
`${node} = ${render_statement};`
block.chunks.create.push(
b`${node} = ${render_statement};`
);
if (renderer.options.hydratable) {
if (parent_nodes) {
block.builders.claim.add_block(deindent`
block.chunks.claim.push(b`
${node} = ${this.get_claim_statement(parent_nodes)};
var ${nodes} = @children(${this.node.name === 'template' ? `${node}.content` : node});
`);
} else {
block.builders.claim.add_line(
`${node} = ${render_statement};`
block.chunks.claim.push(
b`${node} = ${render_statement};`
);
}
}
if (parent_node) {
block.builders.mount.add_line(
`@append(${parent_node}, ${node});`
block.chunks.mount.push(
b`@append(${parent_node}, ${node});`
);
if (parent_node === '@_document.head') {
block.builders.destroy.add_line(`@detach(${node});`);
block.chunks.destroy.push(b`@detach(${node});`);
}
} 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
// 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
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') {
block.builders.create.add_line(
block.chunks.create.push(
// @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 {
const inner_html = escape(
@ -297,8 +297,8 @@ export default class ElementWrapper extends Wrapper {
.join('')
);
block.builders.create.add_line(
`${node}.innerHTML = \`${inner_html}\`;`
block.chunks.create.push(
b`${node}.innerHTML = \`${inner_html}\`;`
);
}
} else {
@ -330,8 +330,8 @@ export default class ElementWrapper extends Wrapper {
this.add_classes(block);
if (nodes && this.renderer.options.hydratable) {
block.builders.claim.add_line(
`${nodes}.forEach(@detach);`
block.chunks.claim.push(
b`${nodes}.forEach(@detach);`
);
}
@ -367,8 +367,8 @@ export default class ElementWrapper extends Wrapper {
if (renderer.options.dev) {
const loc = renderer.locate(this.node.start);
block.builders.hydrate.add_line(
`@add_location(${this.var}, ${renderer.file_var}, ${loc.line}, ${loc.column}, ${this.node.start});`
block.chunks.hydrate.push(
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) {
// need to create a block-local function that calls an instance-level function
if (animation_frame) {
block.builders.init.add_block(deindent`
block.chunks.init.push(b`
function ${handler}() {
@_cancelAnimationFrame(${animation_frame});
if (!${this.var}.paused) {
@ -481,7 +481,7 @@ export default class ElementWrapper extends Wrapper {
}
`);
} else {
block.builders.init.add_block(deindent`
block.chunks.init.push(b`
function ${handler}() {
${needs_lock && `${lock} = true;`}
ctx.${handler}.call(${this.var}${contextual_dependencies.size > 0 ? ', ctx' : ''});
@ -494,7 +494,7 @@ export default class ElementWrapper extends Wrapper {
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(', ')} }` : ``}) {
${group.bindings.map(b => b.handler.mutation)}
${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`);
block.add_variable(resize_listener);
block.builders.mount.add_line(
`${resize_listener} = @add_resize_listener(${this.var}, ${callee}.bind(${this.var}));`
block.chunks.mount.push(
b`${resize_listener} = @add_resize_listener(${this.var}, ${callee}.bind(${this.var}));`
);
block.builders.destroy.add_line(
`${resize_listener}.cancel();`
block.chunks.destroy.push(
b`${resize_listener}.cancel();`
);
} else {
block.event_listeners.push(
@ -539,27 +539,27 @@ export default class ElementWrapper extends Wrapper {
if (should_initialise) {
const callback = has_local_function ? handler : `() => ${callee}.call(${this.var})`;
block.builders.hydrate.add_line(
`if (${some_initial_state_is_undefined}) @add_render_callback(${callback});`
block.chunks.hydrate.push(
b`if (${some_initial_state_is_undefined}) @add_render_callback(${callback});`
);
}
if (group.events[0] === 'resize') {
block.builders.hydrate.add_line(
`@add_render_callback(() => ${callee}.call(${this.var}));`
block.chunks.hydrate.push(
b`@add_render_callback(() => ${callee}.call(${this.var}));`
);
}
});
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');
if (this_binding) {
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} = [
${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(
`@${fn}(${this.var}, ${data});`
block.chunks.hydrate.push(
b`${fn}(${this.var}, ${data});`
);
block.builders.update.add_block(deindent`
@${fn}(${this.var}, @get_spread_update(${levels}, [
block.chunks.update.push(b`
${fn}(${this.var}, @get_spread_update(${levels}, [
${updates.join(',\n')}
]));
`);
@ -658,36 +658,36 @@ export default class ElementWrapper extends Wrapper {
const fn = component.qualify(intro.name);
const intro_block = deindent`
const intro_block = b`
@add_render_callback(() => {
if (!${name}) ${name} = @create_bidirectional_transition(${this.var}, ${fn}, ${snippet}, true);
${name}.run(1);
});
`;
const outro_block = deindent`
const outro_block = b`
if (!${name}) ${name} = @create_bidirectional_transition(${this.var}, ${fn}, ${snippet}, false);
${name}.run(0);
`;
if (intro.is_local) {
block.builders.intro.add_block(deindent`
block.chunks.intro.push(b`
if (#local) {
${intro_block}
}
`);
block.builders.outro.add_block(deindent`
block.chunks.outro.push(b`
if (#local) {
${outro_block}
}
`);
} else {
block.builders.intro.add_block(intro_block);
block.builders.outro.add_block(outro_block);
block.chunks.intro.push(intro_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 {
@ -705,7 +705,7 @@ export default class ElementWrapper extends Wrapper {
let intro_block;
if (outro) {
intro_block = deindent`
intro_block = b`
@add_render_callback(() => {
if (${outro_name}) ${outro_name}.end(1);
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 {
intro_block = deindent`
intro_block = b`
if (!${intro_name}) {
@add_render_callback(() => {
${intro_name} = @create_in_transition(${this.var}, ${fn}, ${snippet});
@ -726,14 +726,14 @@ export default class ElementWrapper extends Wrapper {
}
if (intro.is_local) {
intro_block = deindent`
intro_block = b`
if (#local) {
${intro_block}
}
`;
}
block.builders.intro.add_block(intro_block);
block.chunks.intro.push(intro_block);
}
if (outro) {
@ -745,28 +745,28 @@ export default class ElementWrapper extends Wrapper {
const fn = component.qualify(outro.name);
if (!intro) {
block.builders.intro.add_block(deindent`
block.chunks.intro.push(b`
if (${outro_name}) ${outro_name}.end(1);
`);
}
// TODO hide elements that have outro'd (unless they belong to a still-outroing
// 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});
`;
if (outro.is_local) {
outro_block = deindent`
outro_block = b`
if (#local) {
${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(stop_animation, '@noop');
block.builders.measure.add_block(deindent`
block.chunks.measure.push(b`
${rect} = ${this.var}.getBoundingClientRect();
`);
block.builders.fix.add_block(deindent`
block.chunks.fix.push(b`
@fix_position(${this.var});
${stop_animation}();
${outro && `@add_transform(${this.var}, ${rect});`}
@ -797,7 +797,7 @@ export default class ElementWrapper extends Wrapper {
const name = component.qualify(this.node.animation.name);
block.builders.animate.add_block(deindent`
block.chunks.animate.push(b`
${stop_animation}();
${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)}`;
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) {
const all_dependencies = this.class_dependencies.concat(...dependencies);
const deps = all_dependencies.map(dependency => `changed${quote_prop_if_necessary(dependency)}`).join(' || ');
const condition = all_dependencies.length > 1 ? `(${deps})` : deps;
block.builders.update.add_conditional(
condition,
updater
);
block.chunks.update.push(b`if (${condition}) ${updater}`);
}
});
}

@ -6,7 +6,7 @@ import IfBlock from '../../nodes/IfBlock';
import create_debugging_comment from './shared/create_debugging_comment';
import ElseBlock from '../../nodes/ElseBlock';
import FragmentWrapper from './Fragment';
import deindent from '../../utils/deindent';
import { b } from 'code-red';
import { walk } from 'estree-walker';
function is_else_if(node: ElseBlock) {
@ -198,7 +198,7 @@ export default class IfBlockWrapper extends Wrapper {
if (has_outros) {
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 {
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);
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) {
block.builders.claim.add_line(
`${if_name}${name}.l(${parent_nodes});`
block.chunks.claim.push(
b`${if_name}${name}.l(${parent_nodes});`
);
}
if (has_intros || has_outros) {
block.builders.intro.add_line(`@transition_in(${name});`);
block.chunks.intro.push(b`@transition_in(${name});`);
}
if (needs_anchor) {
@ -250,10 +250,10 @@ export default class IfBlockWrapper extends Wrapper {
/* eslint-disable @typescript-eslint/indent,indent */
if (this.needs_update) {
block.builders.init.add_block(deindent`
block.chunks.init.push(b`
function ${select_block_type}(changed, ctx) {
${this.branches.map(({ dependencies, condition, snippet, block }) => condition
? deindent`
? b`
${snippet && (
dependencies.length > 0
? `if ((${condition} == null) || ${dependencies.map(n => `changed.${n}`).join(' || ')}) ${condition} = !!(${snippet})`
@ -264,7 +264,7 @@ export default class IfBlockWrapper extends Wrapper {
}
`);
} else {
block.builders.init.add_block(deindent`
block.chunks.init.push(b`
function ${select_block_type}(changed, ctx) {
${this.branches.map(({ condition, snippet, block }) => condition
? `if (${snippet || condition}) return ${block.name};`
@ -274,21 +274,21 @@ export default class IfBlockWrapper extends Wrapper {
}
/* 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 ${name} = ${current_block_type_and}${current_block_type}(ctx);
`);
const initial_mount_node = parent_node || '#target';
const anchor_node = parent_node ? 'null' : 'anchor';
block.builders.mount.add_line(
`${if_name}${name}.m(${initial_mount_node}, ${anchor_node});`
block.chunks.mount.push(
b`${if_name}${name}.m(${initial_mount_node}, ${anchor_node});`
);
if (this.needs_update) {
const update_mount_node = this.get_update_mount_node(anchor);
const change_block = deindent`
const change_block = b`
${if_name}${name}.d(1);
${name} = ${current_block_type_and}${current_block_type}(ctx);
if (${name}) {
@ -299,7 +299,7 @@ export default class IfBlockWrapper extends Wrapper {
`;
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}) {
${name}.p(changed, ctx);
} else {
@ -307,17 +307,17 @@ export default class IfBlockWrapper extends Wrapper {
}
`);
} else {
block.builders.update.add_block(deindent`
block.chunks.update.push(b`
if (${current_block_type} !== (${current_block_type} = ${select_block_type}(changed, ctx))) {
${change_block}
}
`);
}
} 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
@ -344,7 +344,7 @@ export default class IfBlockWrapper extends Wrapper {
block.add_variable(name);
/* eslint-disable @typescript-eslint/indent,indent */
block.builders.init.add_block(deindent`
block.chunks.init.push(b`
var ${if_block_creators} = [
${this.branches.map(branch => branch.block.name).join(',\n')}
];
@ -352,17 +352,17 @@ export default class IfBlockWrapper extends Wrapper {
var ${if_blocks} = [];
${this.needs_update
? deindent`
? b`
function ${select_block_type}(changed, ctx) {
${this.branches.map(({ dependencies, condition, snippet }, i) => condition
? deindent`
? b`
${snippet && `if ((${condition} == null) || ${dependencies.map(n => `changed.${n}`).join(' || ')}) ${condition} = !!(${snippet})`}
if (${condition}) return ${String(i)};`
: `return ${i};`)}
${!has_else && `return -1;`}
}
`
: deindent`
: b`
function ${select_block_type}(changed, ctx) {
${this.branches.map(({ condition, snippet }, i) => condition
? `if (${snippet || condition}) return ${String(i)};`
@ -374,12 +374,12 @@ export default class IfBlockWrapper extends Wrapper {
/* eslint-enable @typescript-eslint/indent,indent */
if (has_else) {
block.builders.init.add_block(deindent`
block.chunks.init.push(b`
${current_block_type_index} = ${select_block_type}(null, ctx);
${name} = ${if_blocks}[${current_block_type_index}] = ${if_block_creators}[${current_block_type_index}](ctx);
`);
} else {
block.builders.init.add_block(deindent`
block.chunks.init.push(b`
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);
}
@ -389,14 +389,14 @@ export default class IfBlockWrapper extends Wrapper {
const initial_mount_node = parent_node || '#target';
const anchor_node = parent_node ? 'null' : 'anchor';
block.builders.mount.add_line(
`${if_current_block_type_index}${if_blocks}[${current_block_type_index}].m(${initial_mount_node}, ${anchor_node});`
block.chunks.mount.push(
b`${if_current_block_type_index}${if_blocks}[${current_block_type_index}].m(${initial_mount_node}, ${anchor_node});`
);
if (this.needs_update) {
const update_mount_node = this.get_update_mount_node(anchor);
const destroy_old_block = deindent`
const destroy_old_block = b`
@group_outros();
@transition_out(${if_blocks}[${previous_block_index}], 1, 1, () => {
${if_blocks}[${previous_block_index}] = null;
@ -404,7 +404,7 @@ export default class IfBlockWrapper extends Wrapper {
@check_outros();
`;
const create_new_block = deindent`
const create_new_block = b`
${name} = ${if_blocks}[${current_block_type_index}];
if (!${name}) {
${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
? deindent`
? b`
${destroy_old_block}
${create_new_block}
`
: deindent`
: b`
if (${name}) {
${destroy_old_block}
}
@ -433,7 +433,7 @@ export default class IfBlockWrapper extends Wrapper {
`;
if (dynamic) {
block.builders.update.add_block(deindent`
block.chunks.update.push(b`
var ${previous_block_index} = ${current_block_type_index};
${current_block_type_index} = ${select_block_type}(changed, ctx);
if (${current_block_type_index} === ${previous_block_index}) {
@ -443,7 +443,7 @@ export default class IfBlockWrapper extends Wrapper {
}
`);
} else {
block.builders.update.add_block(deindent`
block.chunks.update.push(b`
var ${previous_block_index} = ${current_block_type_index};
${current_block_type_index} = ${select_block_type}(changed, ctx);
if (${current_block_type_index} !== ${previous_block_index}) {
@ -452,10 +452,10 @@ export default class IfBlockWrapper extends Wrapper {
`);
}
} 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});
`);
}
@ -472,22 +472,22 @@ export default class IfBlockWrapper extends Wrapper {
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);
`);
const initial_mount_node = parent_node || '#target';
const anchor_node = parent_node ? 'null' : 'anchor';
block.builders.mount.add_line(
`if (${name}) ${name}.m(${initial_mount_node}, ${anchor_node});`
block.chunks.mount.push(
b`if (${name}) ${name}.m(${initial_mount_node}, ${anchor_node});`
);
if (branch.dependencies.length > 0) {
const update_mount_node = this.get_update_mount_node(anchor);
const enter = dynamic
? deindent`
? b`
if (${name}) {
${name}.p(changed, ctx);
${has_transitions && `@transition_in(${name}, 1);`}
@ -498,7 +498,7 @@ export default class IfBlockWrapper extends Wrapper {
${name}.m(${update_mount_node}, ${anchor});
}
`
: deindent`
: b`
if (!${name}) {
${name} = ${branch.block.name}(ctx);
${name}.c();
@ -508,13 +508,13 @@ export default class IfBlockWrapper extends Wrapper {
`;
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,
// as that will typically result in glitching
if (branch.block.has_outro_method) {
block.builders.update.add_block(deindent`
block.chunks.update.push(b`
if (${branch.condition}) {
${enter}
} else if (${name}) {
@ -526,7 +526,7 @@ export default class IfBlockWrapper extends Wrapper {
}
`);
} else {
block.builders.update.add_block(deindent`
block.chunks.update.push(b`
if (${branch.condition}) {
${enter}
} else if (${name}) {
@ -536,11 +536,11 @@ export default class IfBlockWrapper extends Wrapper {
`);
}
} else if (dynamic) {
block.builders.update.add_block(
`if (${branch.condition}) ${name}.p(changed, ctx);`
block.chunks.update.push(
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 { stringify_props } from '../../../utils/stringify_props';
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 get_object from '../../../utils/get_object';
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} = [
${initial_props.join(',\n')}
];
`);
statements.push(deindent`
statements.push(b`
for (var #i = 0; #i < ${levels}.length; #i += 1) {
${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(' || ');
updates.push(deindent`
updates.push(b`
var ${name_changes} = ${conditions ? `(${conditions}) ? @get_spread_update(${levels}, [
${changes.join(',\n')}
]) : {}` : '{}'};
@ -237,7 +237,7 @@ export default class InlineComponentWrapper extends Wrapper {
if (dependencies.length > 0) {
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)};
`);
}
@ -269,13 +269,13 @@ export default class InlineComponentWrapper extends Wrapper {
const snippet = binding.expression.render(block);
statements.push(deindent`
statements.push(b`
if (${snippet} !== void 0) {
${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(' || ')}) {
${name_changes}${quote_prop_if_necessary(binding.name)} = ${snippet};
}
@ -300,7 +300,7 @@ export default class InlineComponentWrapper extends Wrapper {
if (contextual_dependencies.length > 0) {
args.push(`{ ${contextual_dependencies.join(', ')} }`);
block.builders.init.add_block(deindent`
block.chunks.init.push(b`
function ${name}(${value}) {
ctx.${name}.call(null, ${value}, ctx);
${updating} = true;
@ -310,7 +310,7 @@ export default class InlineComponentWrapper extends Wrapper {
block.maintain_context = true; // TODO put this somewhere more logical
} else {
block.builders.init.add_block(deindent`
block.chunks.init.push(b`
function ${name}(${value}) {
ctx.${name}.call(null, ${value});
${updating} = true;
@ -319,7 +319,7 @@ export default class InlineComponentWrapper extends Wrapper {
`);
}
const body = deindent`
const body = b`
function ${name}(${args.join(', ')}) {
${lhs} = ${value};
${component.invalidate(dependencies[0])};
@ -344,11 +344,11 @@ export default class InlineComponentWrapper extends Wrapper {
const snippet = this.node.expression.render(block);
block.builders.init.add_block(deindent`
block.chunks.init.push(b`
var ${switch_value} = ${snippet};
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};`}`}
${statements}
return ${stringify_props(component_opts)};
@ -362,17 +362,17 @@ export default class InlineComponentWrapper extends Wrapper {
}
`);
block.builders.create.add_line(
`if (${name}) ${name}.$$.fragment.c();`
block.chunks.create.push(
b`if (${name}) ${name}.$$.fragment.c();`
);
if (parent_nodes && this.renderer.options.hydratable) {
block.builders.claim.add_line(
`if (${name}) ${name}.$$.fragment.l(${parent_nodes});`
block.chunks.claim.push(
b`if (${name}) ${name}.$$.fragment.l(${parent_nodes});`
);
}
block.builders.mount.add_block(deindent`
block.chunks.mount.push(b`
if (${name}) {
@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);
if (updates.length) {
block.builders.update.add_block(deindent`
block.chunks.update.push(b`
${updates}
`);
}
block.builders.update.add_block(deindent`
block.chunks.update.push(b`
if (${switch_value} !== (${switch_value} = ${snippet})) {
if (${name}) {
@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 (updates.length) {
block.builders.update.add_block(deindent`
block.chunks.update.push(b`
else if (${switch_value}) {
${name}.$set(${name_changes});
}
`);
}
block.builders.outro.add_line(
`if (${name}) @transition_out(${name}.$$.fragment, #local);`
block.chunks.outro.push(
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 {
const expression = this.node.name === 'svelte:self'
? '__svelte:self__' // TODO conflict-proof this
: component.qualify(this.node.name);
block.builders.init.add_block(deindent`
${(this.node.attributes.length || this.node.bindings.length) && deindent`
block.chunks.init.push(b`
${(this.node.attributes.length || this.node.bindings.length) && b`
${props && `let ${props} = ${attribute_object};`}`}
${statements}
var ${name} = new ${expression}(${stringify_props(component_opts)});
@ -445,35 +445,35 @@ export default class InlineComponentWrapper extends Wrapper {
${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) {
block.builders.claim.add_line(
`${name}.$$.fragment.l(${parent_nodes});`
block.chunks.claim.push(
b`${name}.$$.fragment.l(${parent_nodes});`
);
}
block.builders.mount.add_line(
`@mount_component(${name}, ${parent_node || '#target'}, ${parent_node ? 'null' : 'anchor'});`
block.chunks.mount.push(
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);
`);
if (updates.length) {
block.builders.update.add_block(deindent`
block.chunks.update.push(b`
${updates}
${name}.$set(${name_changes});
`);
}
block.builders.destroy.add_block(deindent`
block.chunks.destroy.push(b`
@destroy_component(${name}${parent_node ? '' : ', detaching'});
`);
block.builders.outro.add_line(
`@transition_out(${name}.$$.fragment, #local);`
block.chunks.outro.push(
b`@transition_out(${name}.$$.fragment, #local);`
);
}
}

@ -1,3 +1,4 @@
import { b } from 'code-red';
import Renderer from '../Renderer';
import Block from '../Block';
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;
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(
block,
content => insert(content)
);
block.builders.mount.add_line(insert(init));
block.chunks.mount.push(insert(init));
}
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';
block.builders.hydrate.add_line(`${html_tag} = new @HtmlTag(${init}, ${update_anchor});`);
block.builders.mount.add_line(`${html_tag}.m(${parent_node || '#target'}${parent_node ? '' : ', anchor'});`);
block.chunks.hydrate.push(b`${html_tag} = new @HtmlTag(${init}, ${update_anchor});`);
block.chunks.mount.push(b`${html_tag}.m(${parent_node || '#target'}${parent_node ? '' : ', anchor'});`);
if (needs_anchor) {
block.add_element(html_anchor, '@empty()', '@empty()', parent_node);
}
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 Slot from '../../nodes/Slot';
import FragmentWrapper from './Fragment';
import deindent from '../../utils/deindent';
import { b } from 'code-red';
import { sanitize, quote_prop_if_necessary } from '../../../utils/names';
import add_to_set from '../../utils/add_to_set';
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(', ')} }` : '';
renderer.blocks.push(deindent`
renderer.blocks.push(b`
const ${get_slot_changes} = (${arg}) => (${stringify_props(changes_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_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} = @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.claim.push_condition(`!${slot}`);
block.builders.hydrate.push_condition(`!${slot}`);
block.builders.mount.push_condition(`!${slot}`);
block.builders.update.push_condition(`!${slot}`);
block.builders.destroy.push_condition(`!${slot}`);
// block.builders.create.push_condition(`!${slot}`);
// block.builders.claim.push_condition(`!${slot}`);
// block.builders.hydrate.push_condition(`!${slot}`);
// block.builders.mount.push_condition(`!${slot}`);
// block.builders.update.push_condition(`!${slot}`);
// block.builders.destroy.push_condition(`!${slot}`);
const listeners = block.event_listeners;
block.event_listeners = [];
@ -128,37 +128,37 @@ export default class SlotWrapper extends Wrapper {
block.render_listeners(`_${slot}`);
block.event_listeners = listeners;
block.builders.create.pop_condition();
block.builders.claim.pop_condition();
block.builders.hydrate.pop_condition();
block.builders.mount.pop_condition();
block.builders.update.pop_condition();
block.builders.destroy.pop_condition();
// block.builders.create.pop_condition();
// block.builders.claim.pop_condition();
// block.builders.hydrate.pop_condition();
// block.builders.mount.pop_condition();
// block.builders.update.pop_condition();
// block.builders.destroy.pop_condition();
block.builders.create.add_line(
`if (${slot}) ${slot}.c();`
block.chunks.create.push(
b`if (${slot}) ${slot}.c();`
);
block.builders.claim.add_line(
`if (${slot}) ${slot}.l(${parent_nodes});`
block.chunks.claim.push(
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`
: `if (${slot})`;
block.builders.mount.add_block(deindent`
block.chunks.mount.push(b`
${mount_leadin} {
${slot}.m(${parent_node || '#target'}, ${parent_node ? 'null' : 'anchor'});
}
`);
block.builders.intro.add_line(
`@transition_in(${slot}, #local);`
block.chunks.intro.push(
b`@transition_in(${slot}, #local);`
);
block.builders.outro.add_line(
`@transition_out(${slot}, #local);`
block.chunks.outro.push(
b`@transition_out(${slot}, #local);`
);
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(' || ');
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}) {
${slot}.p(
@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(
`if (${slot}) ${slot}.d(detaching);`
block.chunks.destroy.push(
b`if (${slot}) ${slot}.d(detaching);`
);
}
}

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

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

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

@ -1,5 +1,5 @@
import flatten_reference from '../../../utils/flatten_reference';
import deindent from '../../../utils/deindent';
import { b } from 'code-red';
import Component from '../../../Component';
import Block from '../../Block';
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();
body = binding.expression.node.type === 'Identifier'
? deindent`
? b`
${component.invalidate(object, `${lhs} = $$value`)};
`
: deindent`
: b`
${lhs} = $$value;
${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);
if (contextual_dependencies.length) {
component.partly_hoisted.push(deindent`
component.partly_hoisted.push(b`
function ${fn}(${['$$value', ...contextual_dependencies].join(', ')}) {
if (${lhs} === $$value) return;
@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 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 ${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
// nulled out before they're created, to avoid glitches
// with shifting indices
block.builders.update.add_line(deindent`
block.chunks.update.push(b`
if (${condition}) {
${unassign}();
${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}();`;
}
component.partly_hoisted.push(deindent`
component.partly_hoisted.push(b`
function ${fn}($$value) {
@binding_callbacks[$$value ? 'unshift' : 'push'](() => {
${body}
@ -90,6 +90,6 @@ export default function bind_this(component: Component, block: Block, binding: B
}
`);
block.builders.destroy.add_line(`ctx.${fn}(null);`);
return `ctx.${fn}(${variable});`;
block.chunks.destroy.push(b`ctx.${fn}(null);`);
return b`ctx.${fn}(${variable});`;
}

@ -1,4 +1,4 @@
import deindent from '../utils/deindent';
import { b } from 'code-red';
import Component from '../Component';
import { CompileOptions } from '../../interfaces';
import { stringify } from '../utils/stringify';
@ -95,7 +95,7 @@ export default function ssr(
});
const main = renderer.has_bindings
? deindent`
? b`
let $$settled;
let $$rendered;
@ -111,7 +111,7 @@ export default function ssr(
return $$rendered;
`
: deindent`
: b`
${reactive_store_values}
${reactive_declarations}
@ -136,8 +136,8 @@ export default function ssr(
main
].filter(Boolean);
return (deindent`
${css.code && deindent`
return b`
${css.code && b`
const #css = {
code: ${css.code ? stringify(css.code) : `''`},
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) => {
${blocks.join('\n\n')}
});
`).trim();
`;
}
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 deindent from './deindent';
import CodeBuilder from './CodeBuilder';
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', () => {
it('uses the basename', () => {
assert.equal(get_name_from_filename('path/to/Widget.svelte'), 'Widget');

Loading…
Cancel
Save