From 93c7e1de11d1b23b69ce74473ce8f263baf30b35 Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Mon, 9 Sep 2019 09:36:34 -0400 Subject: [PATCH] early WIP --- package-lock.json | 39 +- package.json | 1 + src/compiler/compile/Component.ts | 68 ++-- .../compile/nodes/shared/Expression.ts | 8 +- src/compiler/compile/render_dom/Block.ts | 337 +++++++++--------- src/compiler/compile/render_dom/Renderer.ts | 5 +- src/compiler/compile/render_dom/index.ts | 70 ++-- .../compile/render_dom/wrappers/AwaitBlock.ts | 28 +- .../compile/render_dom/wrappers/Body.ts | 6 +- .../compile/render_dom/wrappers/DebugTag.ts | 20 +- .../compile/render_dom/wrappers/EachBlock.ts | 66 ++-- .../render_dom/wrappers/Element/Attribute.ts | 41 +-- .../render_dom/wrappers/Element/Binding.ts | 31 +- .../wrappers/Element/StyleAttribute.ts | 12 +- .../render_dom/wrappers/Element/index.ts | 125 ++++--- .../compile/render_dom/wrappers/IfBlock.ts | 90 ++--- .../wrappers/InlineComponent/index.ts | 72 ++-- .../render_dom/wrappers/RawMustacheTag.ts | 11 +- .../compile/render_dom/wrappers/Slot.ts | 58 +-- .../compile/render_dom/wrappers/Title.ts | 12 +- .../compile/render_dom/wrappers/Window.ts | 22 +- .../compile/render_dom/wrappers/shared/Tag.ts | 6 +- .../render_dom/wrappers/shared/add_actions.ts | 14 +- .../render_dom/wrappers/shared/bind_this.ts | 20 +- src/compiler/compile/render_ssr/index.ts | 12 +- src/compiler/compile/utils/CodeBuilder.ts | 103 ------ src/compiler/compile/utils/__test__.ts | 165 --------- 27 files changed, 607 insertions(+), 835 deletions(-) delete mode 100644 src/compiler/compile/utils/CodeBuilder.ts diff --git a/package-lock.json b/package-lock.json index bd36702370..d4922a2049 100644 --- a/package-lock.json +++ b/package-lock.json @@ -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", diff --git a/package.json b/package.json index b8a3eae3ce..3ad84f2601 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/src/compiler/compile/Component.ts b/src/compiler/compile/Component.ts index fa8665ffde..ce54f5f92b 100644 --- a/src/compiler/compile/Component.ts +++ b/src/compiler/compile/Component.ts @@ -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, diff --git a/src/compiler/compile/nodes/shared/Expression.ts b/src/compiler/compile/nodes/shared/Expression.ts index a5a730c4d1..7974e0e241 100644 --- a/src/compiler/compile/nodes/shared/Expression.ts +++ b/src/compiler/compile/nodes/shared/Expression.ts @@ -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; 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); }); } diff --git a/src/compiler/compile/render_dom/Block.ts b/src/compiler/compile/render_dom/Block.ts index 4f6a51e120..f073060b45 100644 --- a/src/compiler/compile/render_dom/Block.ts +++ b/src/compiler/compile/render_dom/Block.ts @@ -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; - 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 = {}; - 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)} + // } + // `; + // } } diff --git a/src/compiler/compile/render_dom/Renderer.ts b/src/compiler/compile/render_dom/Renderer.ts index 727841dbc6..f0cf905df6 100644 --- a/src/compiler/compile/render_dom/Renderer.ts +++ b/src/compiler/compile/render_dom/Renderer.ts @@ -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 = []; readonly: Set = new Set(); - meta_bindings: CodeBuilder = new CodeBuilder(); // initial values for e.g. window.innerWidth, if there's a meta tag + meta_bindings: Node[] = []; // initial values for e.g. window.innerWidth, if there's a meta tag binding_groups: string[] = []; block: Block; diff --git a/src/compiler/compile/render_dom/index.ts b/src/compiler/compile/render_dom/index.ts index 504b5ffe05..471bf09006 100644 --- a/src/compiler/compile/render_dom/index.ts +++ b/src/compiler/compile/render_dom/index.ts @@ -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 ''"); } @@ -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 ''"); } @@ -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; } diff --git a/src/compiler/compile/render_dom/wrappers/AwaitBlock.ts b/src/compiler/compile/render_dom/wrappers/AwaitBlock.ts index 2d249e123a..a5baca066e 100644 --- a/src/compiler/compile/render_dom/wrappers/AwaitBlock.ts +++ b/src/compiler/compile/render_dom/wrappers/AwaitBlock.ts @@ -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; diff --git a/src/compiler/compile/render_dom/wrappers/Body.ts b/src/compiler/compile/render_dom/wrappers/Body.ts index 623625ce6d..21d7f90ae7 100644 --- a/src/compiler/compile/render_dom/wrappers/Body.ts +++ b/src/compiler/compile/render_dom/wrappers/Body.ts @@ -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}); `); }); diff --git a/src/compiler/compile/render_dom/wrappers/DebugTag.ts b/src/compiler/compile/render_dom/wrappers/DebugTag.ts index 6705b51cc5..6129637e22 100644 --- a/src/compiler/compile/render_dom/wrappers/DebugTag.ts +++ b/src/compiler/compile/render_dom/wrappers/DebugTag.ts @@ -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} }); diff --git a/src/compiler/compile/render_dom/wrappers/EachBlock.ts b/src/compiler/compile/render_dom/wrappers/EachBlock.ts index fe56ac0fa4..8d97b65ab8 100644 --- a/src/compiler/compile/render_dom/wrappers/EachBlock.ts +++ b/src/compiler/compile/render_dom/wrappers/EachBlock.ts @@ -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);`); } } diff --git a/src/compiler/compile/render_dom/wrappers/Element/Attribute.ts b/src/compiler/compile/render_dom/wrappers/Element/Attribute.ts index 4d44b30617..457e84f152 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/Attribute.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/Attribute.ts @@ -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); } } diff --git a/src/compiler/compile/render_dom/wrappers/Element/Binding.ts b/src/compiler/compile/render_dom/wrappers/Element/Binding.ts index 6eb0697c3c..fe2f7ceb1c 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/Binding.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/Binding.ts @@ -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) { diff --git a/src/compiler/compile/render_dom/wrappers/Element/StyleAttribute.ts b/src/compiler/compile/render_dom/wrappers/Element/StyleAttribute.ts index 2e9eb30a97..c7135ce267 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/StyleAttribute.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/StyleAttribute.ts @@ -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' : ''});` ); }); } diff --git a/src/compiler/compile/render_dom/wrappers/Element/index.ts b/src/compiler/compile/render_dom/wrappers/Element/index.ts index aa42286686..d5e63fd1da 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/index.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/index.ts @@ -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}`); } }); } diff --git a/src/compiler/compile/render_dom/wrappers/IfBlock.ts b/src/compiler/compile/render_dom/wrappers/IfBlock.ts index 1b5cf34bf9..6752315f0b 100644 --- a/src/compiler/compile/render_dom/wrappers/IfBlock.ts +++ b/src/compiler/compile/render_dom/wrappers/IfBlock.ts @@ -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});`); } } diff --git a/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts b/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts index 0889ce7d03..f65aece1f4 100644 --- a/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts +++ b/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts @@ -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);` ); } } diff --git a/src/compiler/compile/render_dom/wrappers/RawMustacheTag.ts b/src/compiler/compile/render_dom/wrappers/RawMustacheTag.ts index 66610c7985..e29946aa61 100644 --- a/src/compiler/compile/render_dom/wrappers/RawMustacheTag.ts +++ b/src/compiler/compile/render_dom/wrappers/RawMustacheTag.ts @@ -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();`); } } } diff --git a/src/compiler/compile/render_dom/wrappers/Slot.ts b/src/compiler/compile/render_dom/wrappers/Slot.ts index 3585d27358..b98e37e7d7 100644 --- a/src/compiler/compile/render_dom/wrappers/Slot.ts +++ b/src/compiler/compile/render_dom/wrappers/Slot.ts @@ -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);` ); } } diff --git a/src/compiler/compile/render_dom/wrappers/Title.ts b/src/compiler/compile/render_dom/wrappers/Title.ts index 302c9f1aa9..0ccd85b872 100644 --- a/src/compiler/compile/render_dom/wrappers/Title.ts +++ b/src/compiler/compile/render_dom/wrappers/Title.ts @@ -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};`); } } } diff --git a/src/compiler/compile/render_dom/wrappers/Window.ts b/src/compiler/compile/render_dom/wrappers/Window.ts index c47f12593c..84706f7d05 100644 --- a/src/compiler/compile/render_dom/wrappers/Window.ts +++ b/src/compiler/compile/render_dom/wrappers/Window.ts @@ -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}); `); diff --git a/src/compiler/compile/render_dom/wrappers/shared/Tag.ts b/src/compiler/compile/render_dom/wrappers/shared/Tag.ts index 7340bce8e1..d57f0184f4 100644 --- a/src/compiler/compile/render_dom/wrappers/shared/Tag.ts +++ b/src/compiler/compile/render_dom/wrappers/shared/Tag.ts @@ -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 }; diff --git a/src/compiler/compile/render_dom/wrappers/shared/add_actions.ts b/src/compiler/compile/render_dom/wrappers/shared/add_actions.ts index 260058f2be..fdc74e2f3b 100644 --- a/src/compiler/compile/render_dom/wrappers/shared/add_actions.ts +++ b/src/compiler/compile/render_dom/wrappers/shared/add_actions.ts @@ -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();` ); }); } diff --git a/src/compiler/compile/render_dom/wrappers/shared/bind_this.ts b/src/compiler/compile/render_dom/wrappers/shared/bind_this.ts index 571331fd4e..0896dc3991 100644 --- a/src/compiler/compile/render_dom/wrappers/shared/bind_this.ts +++ b/src/compiler/compile/render_dom/wrappers/shared/bind_this.ts @@ -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});`; } \ No newline at end of file diff --git a/src/compiler/compile/render_ssr/index.ts b/src/compiler/compile/render_ssr/index.ts index c63bd5d457..29e71f072b 100644 --- a/src/compiler/compile/render_ssr/index.ts +++ b/src/compiler/compile/render_ssr/index.ts @@ -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[]) { diff --git a/src/compiler/compile/utils/CodeBuilder.ts b/src/compiler/compile/utils/CodeBuilder.ts deleted file mode 100644 index b930368143..0000000000 --- a/src/compiler/compile/utils/CodeBuilder.ts +++ /dev/null @@ -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'); - } -} diff --git a/src/compiler/compile/utils/__test__.ts b/src/compiler/compile/utils/__test__.ts index b5bc5d8ea8..60ad681b47 100644 --- a/src/compiler/compile/utils/__test__.ts +++ b/src/compiler/compile/utils/__test__.ts @@ -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');