From 93c7e1de11d1b23b69ce74473ce8f263baf30b35 Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Mon, 9 Sep 2019 09:36:34 -0400 Subject: [PATCH 01/93] 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 bd36702370ca..d4922a204908 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 b8a3eae3cece..3ad84f260158 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 fa8665ffde50..ce54f5f92bdb 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 a5a730c4d199..7974e0e2414e 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 4f6a51e12014..f073060b45dd 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 727841dbc616..f0cf905df63c 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 504b5ffe05f0..471bf09006a2 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 2d249e123a42..a5baca066edc 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 623625ce6d36..21d7f90ae7d3 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 6705b51cc557..6129637e2275 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 fe56ac0fa4d1..8d97b65ab829 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 4d44b306173b..457e84f1523b 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 6eb0697c3cd9..fe2f7ceb1c4c 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 2e9eb30a977f..c7135ce26718 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 aa422866867e..d5e63fd1da5e 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 1b5cf34bf946..6752315f0be2 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 0889ce7d036d..f65aece1f43f 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 66610c798547..e29946aa6154 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 3585d273586d..b98e37e7d7e0 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 302c9f1aa960..0ccd85b87293 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 c47f12593c3c..84706f7d05ba 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 7340bce8e146..d57f0184f415 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 260058f2be57..fdc74e2f3b34 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 571331fd4e41..0896dc39918c 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 c63bd5d45778..29e71f072b36 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 b93036814324..000000000000 --- 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 b5bc5d8ea867..60ad681b47bb 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'); From e876f604a46d0f0cd2b381943bcb359d18a97aea Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Tue, 10 Sep 2019 09:32:05 -0400 Subject: [PATCH 02/93] more progress. everything still broken --- src/compiler/compile/Component.ts | 35 ++++++----- src/compiler/compile/create_module.ts | 18 +++--- src/compiler/compile/nodes/EventHandler.ts | 11 ++-- .../compile/nodes/shared/Expression.ts | 22 +++---- src/compiler/compile/render_dom/Block.ts | 53 +++++++++++------ src/compiler/compile/render_dom/Renderer.ts | 4 +- .../compile/render_dom/wrappers/AwaitBlock.ts | 5 +- .../compile/render_dom/wrappers/EachBlock.ts | 59 ++++++++++--------- .../render_dom/wrappers/Element/Attribute.ts | 2 +- .../render_dom/wrappers/Element/Binding.ts | 4 +- .../render_dom/wrappers/Element/index.ts | 45 +++++++------- .../compile/render_dom/wrappers/IfBlock.ts | 24 ++++---- .../wrappers/InlineComponent/index.ts | 38 ++++++------ .../render_dom/wrappers/MustacheTag.ts | 10 ++-- .../render_dom/wrappers/RawMustacheTag.ts | 9 +-- .../compile/render_dom/wrappers/Slot.ts | 3 +- .../compile/render_dom/wrappers/Text.ts | 12 ++-- .../compile/render_dom/wrappers/Title.ts | 2 +- .../compile/render_dom/wrappers/Window.ts | 30 +++++----- .../compile/render_dom/wrappers/shared/Tag.ts | 4 +- .../render_dom/wrappers/shared/Wrapper.ts | 18 +++--- .../render_dom/wrappers/shared/add_actions.ts | 12 ++-- .../render_dom/wrappers/shared/bind_this.ts | 2 +- src/compiler/compile/utils/stringify.ts | 7 +++ src/compiler/interfaces.ts | 5 ++ test/runtime/samples/_/_config.js | 5 ++ test/runtime/samples/_/main.svelte | 1 + 27 files changed, 252 insertions(+), 188 deletions(-) create mode 100644 test/runtime/samples/_/_config.js create mode 100644 test/runtime/samples/_/main.svelte diff --git a/src/compiler/compile/Component.ts b/src/compiler/compile/Component.ts index ce54f5f92bdb..addc00b3eb21 100644 --- a/src/compiler/compile/Component.ts +++ b/src/compiler/compile/Component.ts @@ -16,7 +16,7 @@ import Stylesheet from './css/Stylesheet'; import { test } from '../config'; import Fragment from './nodes/Fragment'; import internal_exports from './internal_exports'; -import { Node, Ast, CompileOptions, Var, Warning } from '../interfaces'; +import { Node, Ast, CompileOptions, Var, Warning, Identifier } from '../interfaces'; import error from '../utils/error'; import get_code_frame from '../utils/get_code_frame'; import flatten_reference from './utils/flatten_reference'; @@ -90,7 +90,7 @@ export default class Component { ast: Ast; source: string; code: MagicString; - name: string; + name: Identifier; compile_options: CompileOptions; fragment: Fragment; module_scope: Scope; @@ -99,7 +99,7 @@ export default class Component { component_options: ComponentOptions; namespace: string; - tag: string; + tag: Identifier; accessors: boolean; vars: Var[] = []; @@ -122,8 +122,8 @@ export default class Component { reactive_declaration_nodes: Set = new Set(); has_reactive_assignments = false; injected_reactive_declaration_vars: Set = new Set(); - helpers: Map = new Map(); - globals: Map = new Map(); + helpers: Map = new Map(); + globals: Map = new Map(); indirect_dependencies: Map> = new Map(); @@ -141,7 +141,7 @@ export default class Component { stylesheet: Stylesheet; - aliases: Map = new Map(); + aliases: Map = new Map(); used_names: Set = new Set(); globally_used_names: Set = new Set(); @@ -156,7 +156,7 @@ export default class Component { stats: Stats, warnings: Warning[] ) { - this.name = name; + this.name = { type: 'Identifier', name }; this.stats = stats; this.warnings = warnings; @@ -205,7 +205,10 @@ export default class Component { message: `No custom element 'tag' option was specified. To automatically register a custom element, specify a name with a hyphen in it, e.g. . To hide this warning, use `, }); } - this.tag = this.component_options.tag || compile_options.tag; + this.tag = { + type: 'Identifier', + name: this.component_options.tag || compile_options.tag + }; } else { this.tag = this.name; } @@ -335,7 +338,7 @@ export default class Component { const referenced_globals = Array.from( this.globals, - ([name, alias]) => name !== alias && { name, alias } + ([name, alias]) => name !== alias.name && { name, alias } ).filter(Boolean); if (referenced_globals.length) { this.helper('globals'); @@ -348,7 +351,7 @@ export default class Component { const module = create_module( printed.code, format, - name, + name.name, banner, compile_options.sveltePath, imported_helpers, @@ -437,7 +440,7 @@ export default class Component { }; } - get_unique_name(name: string) { + get_unique_name(name: string): Identifier { if (test) name = `${name}$`; let alias = name; for ( @@ -449,7 +452,7 @@ export default class Component { alias = `${name}_${i++}` ); this.used_names.add(alias); - return alias; + return { type: 'Identifier', name: alias }; } get_unique_name_maker() { @@ -463,7 +466,7 @@ export default class Component { internal_exports.forEach(add); this.var_lookup.forEach((_value, key) => add(key)); - return (name: string) => { + return (name: string): Identifier => { if (test) name = `${name}$`; let alias = name; for ( @@ -473,7 +476,11 @@ export default class Component { ); local_used_names.add(alias); this.globally_used_names.add(alias); - return alias; + + return { + type: 'Identifier', + name: alias + }; }; } diff --git a/src/compiler/compile/create_module.ts b/src/compiler/compile/create_module.ts index 79cb33549c48..83ba38c510db 100644 --- a/src/compiler/compile/create_module.ts +++ b/src/compiler/compile/create_module.ts @@ -1,6 +1,6 @@ import deindent from './utils/deindent'; import list from '../utils/list'; -import { ModuleFormat, Node } from '../interfaces'; +import { ModuleFormat, Node, Identifier } from '../interfaces'; import { stringify_props } from './utils/stringify_props'; const wrappers = { esm, cjs }; @@ -16,8 +16,8 @@ export default function create_module( name: string, banner: string, sveltePath = 'svelte', - helpers: Array<{ name: string; alias: string }>, - globals: Array<{ name: string; alias: string }>, + helpers: Array<{ name: string; alias: Identifier }>, + globals: Array<{ name: string; alias: Identifier }>, imports: Node[], module_exports: Export[], source: string @@ -45,14 +45,14 @@ function esm( banner: string, sveltePath: string, internal_path: string, - helpers: Array<{ name: string; alias: string }>, - globals: Array<{ name: string; alias: string }>, + helpers: Array<{ name: string; alias: Identifier }>, + globals: Array<{ name: string; alias: Identifier }>, imports: Node[], module_exports: Export[], source: string ) { const internal_imports = helpers.length > 0 && ( - `import ${stringify_props(helpers.map(h => h.name === h.alias ? h.name : `${h.name} as ${h.alias}`).sort())} from ${JSON.stringify(internal_path)};` + `import ${stringify_props(helpers.map(h => h.name === h.alias.name ? h.name : `${h.name} as ${h.alias}`).sort())} from ${JSON.stringify(internal_path)};` ); const internal_globals = globals.length > 0 && ( `const ${stringify_props(globals.map(g => `${g.name}: ${g.alias}`).sort())} = ${helpers.find(({ name }) => name === 'globals').alias};` @@ -90,12 +90,12 @@ function cjs( banner: string, sveltePath: string, internal_path: string, - helpers: Array<{ name: string; alias: string }>, - globals: Array<{ name: string; alias: string }>, + helpers: Array<{ name: string; alias: Identifier }>, + globals: Array<{ name: string; alias: Identifier }>, imports: Node[], module_exports: Export[] ) { - const declarations = helpers.map(h => `${h.alias === h.name ? h.name : `${h.name}: ${h.alias}`}`).sort(); + const declarations = helpers.map(h => `${h.alias.name === h.name ? h.name : `${h.name}: ${h.alias}`}`).sort(); const internal_imports = helpers.length > 0 && ( `const ${stringify_props(declarations)} = require(${JSON.stringify(internal_path)});\n` diff --git a/src/compiler/compile/nodes/EventHandler.ts b/src/compiler/compile/nodes/EventHandler.ts index 0c65e463ba4a..428ee678bf81 100644 --- a/src/compiler/compile/nodes/EventHandler.ts +++ b/src/compiler/compile/nodes/EventHandler.ts @@ -4,13 +4,14 @@ import Component from '../Component'; import deindent from '../utils/deindent'; import Block from '../render_dom/Block'; import { sanitize } from '../../utils/names'; +import { Identifier } from '../../interfaces'; export default class EventHandler extends Node { type: 'EventHandler'; name: string; modifiers: Set; expression: Expression; - handler_name: string; + handler_name: Identifier; uses_context = false; can_make_passive = false; @@ -42,21 +43,21 @@ export default class EventHandler extends Node { } } } else { - const name = component.get_unique_name(`${sanitize(this.name)}_handler`); + const id = component.get_unique_name(`${sanitize(this.name)}_handler`); component.add_var({ - name, + name: id.name, internal: true, referenced: true }); component.partly_hoisted.push(deindent` - function ${name}(event) { + function ${id}(event) { @bubble($$self, event); } `); - this.handler_name = name; + this.handler_name = id; } } diff --git a/src/compiler/compile/nodes/shared/Expression.ts b/src/compiler/compile/nodes/shared/Expression.ts index 7974e0e2414e..ffb0f4ea3a1a 100644 --- a/src/compiler/compile/nodes/shared/Expression.ts +++ b/src/compiler/compile/nodes/shared/Expression.ts @@ -307,7 +307,7 @@ export default class Expression { if (map.has(node)) scope = scope.parent; if (node === function_expression) { - const name = component.get_unique_name( + const id = component.get_unique_name( sanitize(get_function_name(node, owner)) ); @@ -325,16 +325,16 @@ export default class Expression { const body = code.slice(node.body.start, node.body.end).trim(); const fn = node.type === 'FunctionExpression' - ? `${node.async ? 'async ' : ''}function${node.generator ? '*' : ''} ${name}(${args.join(', ')}) ${body}` - : `const ${name} = ${node.async ? 'async ' : ''}(${args.join(', ')}) => ${body};`; + ? `${node.async ? 'async ' : ''}function${node.generator ? '*' : ''} ${id}(${args.join(', ')}) ${body}` + : `const ${id} = ${node.async ? 'async ' : ''}(${args.join(', ')}) => ${body};`; if (dependencies.size === 0 && contextual_dependencies.size === 0) { // we can hoist this out of the component completely component.fully_hoisted.push(fn); - code.overwrite(node.start, node.end, name); + code.overwrite(node.start, node.end, id.name); component.add_var({ - name, + name: id.name, internal: true, hoistable: true, referenced: true @@ -344,10 +344,10 @@ export default class Expression { else if (contextual_dependencies.size === 0) { // function can be hoisted inside the component init component.partly_hoisted.push(fn); - code.overwrite(node.start, node.end, `ctx.${name}`); + code.overwrite(node.start, node.end, `ctx.${id}`); component.add_var({ - name, + name: id.name, internal: true, referenced: true }); @@ -356,17 +356,17 @@ export default class Expression { else { // we need a combo block/init recipe component.partly_hoisted.push(fn); - code.overwrite(node.start, node.end, name); + code.overwrite(node.start, node.end, id.name); component.add_var({ - name, + name: id.name, internal: true, referenced: true }); declarations.push(b` - function ${name}(${original_params ? '...args' : ''}) { - return ctx.${name}(ctx${original_params ? ', ...args' : ''}); + function ${id}(${original_params ? '...args' : ''}) { + return ctx.${id}(ctx${original_params ? ', ...args' : ''}); } `); } diff --git a/src/compiler/compile/render_dom/Block.ts b/src/compiler/compile/render_dom/Block.ts index f073060b45dd..a94743b21ebe 100644 --- a/src/compiler/compile/render_dom/Block.ts +++ b/src/compiler/compile/render_dom/Block.ts @@ -2,34 +2,46 @@ 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'; +import { Node, Identifier } from '../../interfaces'; export interface BlockOptions { parent?: Block; - name: string; + name: Identifier; type: string; renderer?: Renderer; comment?: string; - key?: string; - bindings?: Map; + key?: Identifier; + bindings?: Map; dependencies?: Set; } export default class Block { parent?: Block; renderer: Renderer; - name: string; + name: Identifier; type: string; comment?: string; wrappers: Wrapper[]; - key: string; - first: string; + key: Identifier; + first: Identifier; dependencies: Set; - bindings: Map; + bindings: Map; chunks: { init: Node[]; @@ -56,9 +68,9 @@ export default class Block { has_outro_method: boolean; outros: number; - aliases: Map; + aliases: Map; variables: Map; - get_unique_name: (name: string) => string; + get_unique_name: (name: string) => Identifier; has_update_method = false; autofocus: string; @@ -108,6 +120,7 @@ export default class Block { } assign_variable_names() { + // TODO reimplement for #3539 const seen = new Set(); const dupes = new Set(); @@ -139,7 +152,7 @@ export default class Block { counts.set(wrapper.var, i + 1); wrapper.var = this.get_unique_name(wrapper.var + i); } else { - wrapper.var = this.get_unique_name(wrapper.var); + wrapper.var = this.get_unique_name(wrapper.var.name); } } } @@ -154,8 +167,8 @@ export default class Block { add_element( name: string, - render_statement: string, - claim_statement: string, + render_statement: Node, + claim_statement: Node, parent_node: string, no_detach?: boolean ) { @@ -192,7 +205,7 @@ export default class Block { add_variable(name: string, init?: string) { if (name[0] === '#') { - name = this.alias(name.slice(1)); + name = this.alias(name.slice(1)).name; } if (this.variables.has(name) && this.variables.get(name) !== init) { @@ -281,7 +294,7 @@ export default class Block { properties.mount = noop; } else { properties.mount = x`function mount(#target, anchor) { - ${this.chunks.mount} + //${this.chunks.mount} }`; } @@ -338,7 +351,7 @@ export default class Block { }`; } - const return_value = x`{ + const return_value: any = x`{ key: ${properties.key}, first: ${properties.first}, c: ${properties.create}, @@ -354,13 +367,17 @@ export default class Block { d: ${properties.destroy} }`; + return_value.properties = return_value.properties.filter(prop => prop.value); + /* eslint-disable @typescript-eslint/indent,indent */ return b` - ${Array.from(this.variables.entries()).map(([init, id]) => { + ${Array.from(this.variables.entries()).map(([id, init]) => { const id_node = { type: 'Identifier', name: id }; const init_node = { type: 'Identifier', name: init }; - return b`let ${id_node} = ${init_node}`; + return init + ? b`let ${id_node} = ${init_node}` + : b`let ${id_node}`; })} ${this.chunks.init} diff --git a/src/compiler/compile/render_dom/Renderer.ts b/src/compiler/compile/render_dom/Renderer.ts index f0cf905df63c..90a76a68b74d 100644 --- a/src/compiler/compile/render_dom/Renderer.ts +++ b/src/compiler/compile/render_dom/Renderer.ts @@ -1,5 +1,5 @@ import Block from './Block'; -import { CompileOptions, Node } from '../../interfaces'; +import { CompileOptions, Node, Identifier } from '../../interfaces'; import Component from '../Component'; import FragmentWrapper from './wrappers/Fragment'; @@ -15,7 +15,7 @@ export default class Renderer { block: Block; fragment: FragmentWrapper; - file_var: string; + file_var: Identifier; locate: (c: number) => { line: number; column: number }; constructor(component: Component, options: CompileOptions) { diff --git a/src/compiler/compile/render_dom/wrappers/AwaitBlock.ts b/src/compiler/compile/render_dom/wrappers/AwaitBlock.ts index a5baca066edc..684575641498 100644 --- a/src/compiler/compile/render_dom/wrappers/AwaitBlock.ts +++ b/src/compiler/compile/render_dom/wrappers/AwaitBlock.ts @@ -8,6 +8,7 @@ import FragmentWrapper from './Fragment'; import PendingBlock from '../../nodes/PendingBlock'; import ThenBlock from '../../nodes/ThenBlock'; import CatchBlock from '../../nodes/CatchBlock'; +import { Identifier } from '../../../interfaces'; class AwaitBlockBranch extends Wrapper { node: PendingBlock | ThenBlock | CatchBlock; @@ -54,7 +55,7 @@ export default class AwaitBlockWrapper extends Wrapper { then: AwaitBlockBranch; catch: AwaitBlockBranch; - var = 'await_block'; + var: Identifier = { type: 'Identifier', name: 'await_block' }; constructor( renderer: Renderer, @@ -131,7 +132,7 @@ export default class AwaitBlockWrapper extends Wrapper { const info = block.get_unique_name(`info`); const promise = block.get_unique_name(`promise`); - block.add_variable(promise); + block.add_variable(promise.name); block.maintain_context = true; diff --git a/src/compiler/compile/render_dom/wrappers/EachBlock.ts b/src/compiler/compile/render_dom/wrappers/EachBlock.ts index 8d97b65ab829..a98d4a43d1b5 100644 --- a/src/compiler/compile/render_dom/wrappers/EachBlock.ts +++ b/src/compiler/compile/render_dom/wrappers/EachBlock.ts @@ -4,9 +4,10 @@ import Wrapper from './shared/Wrapper'; import create_debugging_comment from './shared/create_debugging_comment'; import EachBlock from '../../nodes/EachBlock'; import FragmentWrapper from './Fragment'; -import { b } from 'code-red'; +import { b, x } from 'code-red'; import ElseBlock from '../../nodes/ElseBlock'; import { attach_head } from '../../utils/tail'; +import { Identifier } from '../../../interfaces'; export class ElseBlockWrapper extends Wrapper { node: ElseBlock; @@ -51,10 +52,10 @@ export default class EachBlockWrapper extends Wrapper { fragment: FragmentWrapper; else?: ElseBlockWrapper; vars: { - create_each_block: string; - each_block_value: string; - get_each_context: string; - iterations: string; + create_each_block: Identifier; + each_block_value: Identifier; + get_each_context: Identifier; + iterations: Identifier; fixed_length: number; data_length: string; view_length: string; @@ -62,9 +63,9 @@ export default class EachBlockWrapper extends Wrapper { } context_props: string[]; - index_name: string; + index_name: Identifier; - var = 'each'; + var: Identifier = { type: 'Identifier', name: 'each' }; constructor( renderer: Renderer, @@ -93,7 +94,9 @@ export default class EachBlockWrapper extends Wrapper { // TODO this seems messy this.block.has_animation = this.node.has_animation; - this.index_name = this.node.index || renderer.component.get_unique_name(`${this.node.context}_index`); + this.index_name = this.node.index + ? { type: 'Identifier', name: this.node.index } + : renderer.component.get_unique_name(`${this.node.context}_index`); const fixed_length = node.expression.node.type === 'ArrayExpression' && @@ -198,12 +201,12 @@ export default class EachBlockWrapper extends Wrapper { } `); - const initial_anchor_node = parent_node ? 'null' : 'anchor'; - const initial_mount_node = parent_node || '#target'; + const initial_anchor_node: Identifier = { type: 'Identifier', name: parent_node ? 'null' : 'anchor' }; + const initial_mount_node: Identifier = { type: 'Identifier', name: parent_node || '#target' }; const update_anchor_node = needs_anchor ? block.get_unique_name(`${this.var}_anchor`) - : (this.next && this.next.var) || 'null'; - const update_mount_node = this.get_update_mount_node(update_anchor_node); + : (this.next && this.next.var) || { type: 'Identifier', name: 'null' }; + const update_mount_node: Identifier = this.get_update_mount_node((update_anchor_node as Identifier)); const args = { block, @@ -232,9 +235,9 @@ export default class EachBlockWrapper extends Wrapper { if (needs_anchor) { block.add_element( - update_anchor_node, - `@empty()`, - parent_nodes && `@empty()`, + (update_anchor_node as Identifier).name, + x`@empty()`, + parent_nodes && x`@empty()`, parent_node ); } @@ -312,10 +315,10 @@ export default class EachBlockWrapper extends Wrapper { parent_node: string; parent_nodes: string; snippet: string; - initial_anchor_node: string; - initial_mount_node: string; - update_anchor_node: string; - update_mount_node: string; + initial_anchor_node: Identifier; + initial_mount_node: Identifier; + update_anchor_node: Identifier; + update_mount_node: Identifier; }) { const { create_each_block, @@ -327,17 +330,17 @@ export default class EachBlockWrapper extends Wrapper { const get_key = block.get_unique_name('get_key'); const lookup = block.get_unique_name(`${this.var}_lookup`); - block.add_variable(iterations, '[]'); - block.add_variable(lookup, `new @_Map()`); + block.add_variable(iterations.name, '[]'); + block.add_variable(lookup.name, `new @_Map()`); if (this.fragment.nodes[0].is_dom_node()) { this.block.first = this.fragment.nodes[0].var; } else { this.block.first = this.block.get_unique_name('first'); this.block.add_element( - this.block.first, - `@empty()`, - parent_nodes && `@empty()`, + this.block.first.name, + x`@empty()`, + parent_nodes && x`@empty()`, null ); } @@ -421,10 +424,10 @@ export default class EachBlockWrapper extends Wrapper { block: Block; parent_nodes: string; snippet: string; - initial_anchor_node: string; - initial_mount_node: string; - update_anchor_node: string; - update_mount_node: string; + initial_anchor_node: Identifier; + initial_mount_node: Identifier; + update_anchor_node: Identifier; + update_mount_node: Identifier; }) { const { create_each_block, diff --git a/src/compiler/compile/render_dom/wrappers/Element/Attribute.ts b/src/compiler/compile/render_dom/wrappers/Element/Attribute.ts index 457e84f1523b..ac3532a30835 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/Attribute.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/Attribute.ts @@ -99,7 +99,7 @@ export default class AttributeWrapper { `${element.var}_${name.replace(/[^a-zA-Z_$]/g, '_')}_value` ); - if (should_cache) block.add_variable(last); + if (should_cache) block.add_variable(last.name); let updater; const init = should_cache ? `${last} = ${value}` : value; diff --git a/src/compiler/compile/render_dom/wrappers/Element/Binding.ts b/src/compiler/compile/render_dom/wrappers/Element/Binding.ts index fe2f7ceb1c4c..d32e59e9e833 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/Binding.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/Binding.ts @@ -152,7 +152,7 @@ export default class BindingWrapper { { // this is necessary to prevent audio restarting by itself const last = block.get_unique_name(`${parent.var}_is_paused`); - block.add_variable(last, 'true'); + block.add_variable(last.name, 'true'); update_conditions.push(`${last} !== (${last} = ${this.snippet})`); update_dom = b`${parent.var}[${last} ? "pause" : "play"]();`; @@ -272,7 +272,7 @@ function get_event_handler( mutation: store ? mutate_store(store, value, tail) : `${snippet}${tail} = ${value};`, - contextual_dependencies: new Set([object, property]) + contextual_dependencies: new Set([object.name, property.name]) }; } diff --git a/src/compiler/compile/render_dom/wrappers/Element/index.ts b/src/compiler/compile/render_dom/wrappers/Element/index.ts index d5e63fd1da5e..c481f0311322 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/index.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/index.ts @@ -4,7 +4,7 @@ import Wrapper from '../shared/Wrapper'; import Block from '../../Block'; import { is_void, quote_prop_if_necessary, quote_name_if_necessary, sanitize } from '../../../../utils/names'; import FragmentWrapper from '../Fragment'; -import { stringify, escape_html, escape } from '../../../utils/stringify'; +import { escape_html, escape, string_literal } from '../../../utils/stringify'; import TextWrapper from '../Text'; import fix_attribute_casing from './fix_attribute_casing'; import { b, x } from 'code-red'; @@ -114,7 +114,7 @@ export default class ElementWrapper extends Wrapper { slot_block: Block; select_binding_dependencies?: Set; - var: string; + var: any; constructor( renderer: Renderer, @@ -125,7 +125,10 @@ export default class ElementWrapper extends Wrapper { next_sibling: Wrapper ) { super(renderer, block, parent, node); - this.var = node.name.replace(/[^a-zA-Z0-9_$]/g, '_'); + this.var = { + type: 'Identifier', + name: node.name.replace(/[^a-zA-Z0-9_$]/g, '_') + }; this.class_dependencies = []; @@ -288,7 +291,7 @@ export default class ElementWrapper extends Wrapper { if (this.fragment.nodes.length === 1 && this.fragment.nodes[0].node.type === 'Text') { block.chunks.create.push( // @ts-ignore todo: should it be this.fragment.nodes[0].node.data instead? - b`${node}.textContent = ${stringify(this.fragment.nodes[0].data)};` + b`${node}.textContent = ${string_literal(this.fragment.nodes[0].data)};` ); } else { const inner_html = escape( @@ -306,7 +309,7 @@ export default class ElementWrapper extends Wrapper { child.render( block, this.node.name === 'template' ? `${node}.content` : node, - nodes + nodes.name ); }); } @@ -377,19 +380,19 @@ export default class ElementWrapper extends Wrapper { const { name, namespace } = this.node; if (namespace === 'http://www.w3.org/2000/svg') { - return `@svg_element("${name}")`; + return x`@svg_element("${name}")`; } if (namespace) { - return `@_document.createElementNS("${namespace}", "${name}")`; + return x`@_document.createElementNS("${namespace}", "${name}")`; } const is = this.attributes.find(attr => attr.node.name === 'is'); if (is) { - return `@element_is("${name}", ${is.render_chunks().join(' + ')});`; + return x`@element_is("${name}", ${is.render_chunks().join(' + ')});`; } - return `@element("${name}")`; + return x`@element("${name}")`; } get_claim_statement(nodes: string) { @@ -402,9 +405,9 @@ export default class ElementWrapper extends Wrapper { ? this.node.name : this.node.name.toUpperCase(); - return `@claim_element(${nodes}, "${name}", ${attributes - ? `{ ${attributes} }` - : `{}`}, ${this.node.namespace === namespaces.svg ? true : false})`; + return x`@claim_element(${nodes}, "${name}", ${attributes + ? x`{ ${attributes} }` + : x`{}`}, ${this.node.namespace === namespaces.svg ? true : false})`; } add_bindings(block: Block) { @@ -418,7 +421,7 @@ export default class ElementWrapper extends Wrapper { block.get_unique_name(`${this.var}_updating`) : null; - if (lock) block.add_variable(lock, 'false'); + if (lock) block.add_variable(lock.name, 'false'); const groups = events .map(event => ({ @@ -433,7 +436,7 @@ export default class ElementWrapper extends Wrapper { const handler = renderer.component.get_unique_name(`${this.var}_${group.events.join('_')}_handler`); renderer.component.add_var({ - name: handler, + name: handler.name, internal: true, referenced: true }); @@ -450,7 +453,7 @@ export default class ElementWrapper extends Wrapper { add_to_set(contextual_dependencies, binding.node.expression.contextual_dependencies); add_to_set(contextual_dependencies, binding.handler.contextual_dependencies); - binding.render(block, lock); + binding.render(block, lock.name); }); // media bindings — awkward special case. The native timeupdate events @@ -505,7 +508,7 @@ export default class ElementWrapper extends Wrapper { if (name === 'resize') { // special case const resize_listener = block.get_unique_name(`${this.var}_resize_listener`); - block.add_variable(resize_listener); + block.add_variable(resize_listener.name); block.chunks.mount.push( b`${resize_listener} = @add_resize_listener(${this.var}, ${callee}.bind(${this.var}));` @@ -654,7 +657,7 @@ export default class ElementWrapper extends Wrapper { ? intro.expression.render(block) : '{}'; - block.add_variable(name); + block.add_variable(name.name); const fn = component.qualify(intro.name); @@ -695,7 +698,7 @@ export default class ElementWrapper extends Wrapper { const outro_name = outro && block.get_unique_name(`${this.var}_outro`); if (intro) { - block.add_variable(intro_name); + block.add_variable(intro_name.name); const snippet = intro.expression ? intro.expression.render(block) : '{}'; @@ -737,7 +740,7 @@ export default class ElementWrapper extends Wrapper { } if (outro) { - block.add_variable(outro_name); + block.add_variable(outro_name.name); const snippet = outro.expression ? outro.expression.render(block) : '{}'; @@ -780,8 +783,8 @@ export default class ElementWrapper extends Wrapper { const rect = block.get_unique_name('rect'); const stop_animation = block.get_unique_name('stop_animation'); - block.add_variable(rect); - block.add_variable(stop_animation, '@noop'); + block.add_variable(rect.name); + block.add_variable(stop_animation.name, '@noop'); block.chunks.measure.push(b` ${rect} = ${this.var}.getBoundingClientRect(); diff --git a/src/compiler/compile/render_dom/wrappers/IfBlock.ts b/src/compiler/compile/render_dom/wrappers/IfBlock.ts index 6752315f0be2..311d8f7773b0 100644 --- a/src/compiler/compile/render_dom/wrappers/IfBlock.ts +++ b/src/compiler/compile/render_dom/wrappers/IfBlock.ts @@ -6,8 +6,10 @@ import IfBlock from '../../nodes/IfBlock'; import create_debugging_comment from './shared/create_debugging_comment'; import ElseBlock from '../../nodes/ElseBlock'; import FragmentWrapper from './Fragment'; -import { b } from 'code-red'; +import { b, x } from 'code-red'; import { walk } from 'estree-walker'; +import { Identifier } from '../../../interfaces'; +import Node from '../../nodes/shared/Node'; function is_else_if(node: ElseBlock) { return ( @@ -19,8 +21,8 @@ class IfBlockBranch extends Wrapper { block: Block; fragment: FragmentWrapper; dependencies?: string[]; - condition?: string; - snippet?: string; + condition?: any; + snippet?: Node; is_dynamic: boolean; var = null; @@ -54,9 +56,9 @@ class IfBlockBranch extends Wrapper { if (should_cache) { this.condition = block.get_unique_name(`show_if`); - this.snippet = expression.render(block); + this.snippet = expression.node; } else { - this.condition = expression.render(block); + this.condition = expression.node; } } @@ -79,7 +81,7 @@ export default class IfBlockWrapper extends Wrapper { branches: IfBlockBranch[]; needs_update = false; - var = 'if_block'; + var: Identifier = { type: 'Identifier', name: 'if_block' }; constructor( renderer: Renderer, @@ -224,9 +226,9 @@ export default class IfBlockWrapper extends Wrapper { if (needs_anchor) { block.add_element( - anchor, - `@empty()`, - parent_nodes && `@empty()`, + (anchor as Identifier).name, + x`@empty()`, + parent_nodes && x`@empty()`, parent_node ); } @@ -340,7 +342,7 @@ export default class IfBlockWrapper extends Wrapper { ? '' : `if (~${current_block_type_index}) `; - block.add_variable(current_block_type_index); + block.add_variable(current_block_type_index.name); block.add_variable(name); /* eslint-disable @typescript-eslint/indent,indent */ @@ -470,7 +472,7 @@ export default class IfBlockWrapper extends Wrapper { ) { const branch = this.branches[0]; - if (branch.snippet) block.add_variable(branch.condition, branch.snippet); + if (branch.snippet) block.add_variable(branch.condition, '' + branch.snippet); block.chunks.init.push(b` var ${name} = (${branch.condition}) && ${branch.block.name}(ctx); diff --git a/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts b/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts index f65aece1f43f..f58f53b0fb0d 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 { b } from 'code-red'; +import { b, x } from 'code-red'; import Attribute from '../../../nodes/Attribute'; import get_object from '../../../utils/get_object'; import create_debugging_comment from '../shared/create_debugging_comment'; @@ -15,9 +15,10 @@ import EachBlock from '../../../nodes/EachBlock'; import TemplateScope from '../../../nodes/shared/TemplateScope'; import is_dynamic from '../shared/is_dynamic'; import bind_this from '../shared/bind_this'; +import { Identifier } from '../../../../interfaces'; export default class InlineComponentWrapper extends Wrapper { - var: string; + var: Identifier; slots: Map = new Map(); node: InlineComponent; fragment: FragmentWrapper; @@ -61,11 +62,14 @@ export default class InlineComponentWrapper extends Wrapper { } }); - this.var = ( - this.node.name === 'svelte:self' ? renderer.component.name : - this.node.name === 'svelte:component' ? 'switch_instance' : - sanitize(this.node.name) - ).toLowerCase(); + this.var = { + type: 'Identifier', + name: ( + this.node.name === 'svelte:self' ? renderer.component.name.name : + this.node.name === 'svelte:component' ? 'switch_instance' : + sanitize(this.node.name) + ).toLowerCase() + }; if (this.node.children.length) { const default_slot = block.child({ @@ -253,19 +257,19 @@ export default class InlineComponentWrapper extends Wrapper { component.has_reactive_assignments = true; if (binding.name === 'this') { - return bind_this(component, block, binding, this.var); + return bind_this(component, block, binding, this.var.name); } - const name = component.get_unique_name(`${this.var}_${binding.name}_binding`); + const id = component.get_unique_name(`${this.var}_${binding.name}_binding`); component.add_var({ - name, + name: id.name, internal: true, referenced: true }); const updating = block.get_unique_name(`updating_${binding.name}`); - block.add_variable(updating); + block.add_variable(updating.name); const snippet = binding.expression.render(block); @@ -292,13 +296,13 @@ export default class InlineComponentWrapper extends Wrapper { const { name } = binding.expression.node; const { object, property, snippet } = block.bindings.get(name); lhs = snippet; - contextual_dependencies.push(object, property); + contextual_dependencies.push(object.name, property.name); } const value = block.get_unique_name('value'); - const args = [value]; + const args: any[] = [value]; if (contextual_dependencies.length > 0) { - args.push(`{ ${contextual_dependencies.join(', ')} }`); + args.push(x`{ ${contextual_dependencies.join(', ')} }`); block.chunks.init.push(b` function ${name}(${value}) { @@ -311,7 +315,7 @@ export default class InlineComponentWrapper extends Wrapper { block.maintain_context = true; // TODO put this somewhere more logical } else { block.chunks.init.push(b` - function ${name}(${value}) { + function ${id}(${value}) { ctx.${name}.call(null, ${value}); ${updating} = true; @add_flush_callback(() => ${updating} = false); @@ -320,7 +324,7 @@ export default class InlineComponentWrapper extends Wrapper { } const body = b` - function ${name}(${args.join(', ')}) { + function ${id}(${args.join(', ')}) { ${lhs} = ${value}; ${component.invalidate(dependencies[0])}; } @@ -328,7 +332,7 @@ export default class InlineComponentWrapper extends Wrapper { component.partly_hoisted.push(body); - return `@binding_callbacks.push(() => @bind(${this.var}, '${binding.name}', ${name}));`; + return `@binding_callbacks.push(() => @bind(${this.var}, '${binding.name}', ${id}));`; }); const munged_handlers = this.node.handlers.map(handler => { diff --git a/src/compiler/compile/render_dom/wrappers/MustacheTag.ts b/src/compiler/compile/render_dom/wrappers/MustacheTag.ts index 71faf91cb227..434fcb85dc25 100644 --- a/src/compiler/compile/render_dom/wrappers/MustacheTag.ts +++ b/src/compiler/compile/render_dom/wrappers/MustacheTag.ts @@ -4,9 +4,11 @@ import Tag from './shared/Tag'; import Wrapper from './shared/Wrapper'; import MustacheTag from '../../nodes/MustacheTag'; import RawMustacheTag from '../../nodes/RawMustacheTag'; +import { Identifier } from '../../../interfaces'; +import { x } from 'code-red'; export default class MustacheTagWrapper extends Tag { - var = 't'; + var: Identifier = { type: 'Identifier', name: 't' }; constructor(renderer: Renderer, block: Block, parent: Wrapper, node: MustacheTag | RawMustacheTag) { super(renderer, block, parent, node); @@ -20,9 +22,9 @@ export default class MustacheTagWrapper extends Tag { ); block.add_element( - this.var, - `@text(${init})`, - parent_nodes && `@claim_text(${parent_nodes}, ${init})`, + this.var.name, + x`@text(${init})`, + parent_nodes && x`@claim_text(${parent_nodes}, ${init})`, parent_node ); } diff --git a/src/compiler/compile/render_dom/wrappers/RawMustacheTag.ts b/src/compiler/compile/render_dom/wrappers/RawMustacheTag.ts index e29946aa6154..d4a7251832f8 100644 --- a/src/compiler/compile/render_dom/wrappers/RawMustacheTag.ts +++ b/src/compiler/compile/render_dom/wrappers/RawMustacheTag.ts @@ -1,13 +1,14 @@ -import { b } from 'code-red'; +import { b, x } from 'code-red'; import Renderer from '../Renderer'; import Block from '../Block'; import Tag from './shared/Tag'; import Wrapper from './shared/Wrapper'; import MustacheTag from '../../nodes/MustacheTag'; import RawMustacheTag from '../../nodes/RawMustacheTag'; +import { Identifier } from '../../../interfaces'; export default class RawMustacheTagWrapper extends Tag { - var = 'raw'; + var: Identifier = { type: 'Identifier', name: 'raw' }; constructor( renderer: Renderer, @@ -41,7 +42,7 @@ export default class RawMustacheTagWrapper extends Tag { const html_tag = block.get_unique_name('html_tag'); const html_anchor = needs_anchor && block.get_unique_name('html_anchor'); - block.add_variable(html_tag); + block.add_variable(html_tag.name); const { init } = this.rename_this_method( block, @@ -54,7 +55,7 @@ export default class RawMustacheTagWrapper extends Tag { 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); + block.add_element(html_anchor.name, x`@empty()`, x`@empty()`, parent_node); } if (!parent_node || in_head) { diff --git a/src/compiler/compile/render_dom/wrappers/Slot.ts b/src/compiler/compile/render_dom/wrappers/Slot.ts index b98e37e7d7e0..6bd1b24e07fc 100644 --- a/src/compiler/compile/render_dom/wrappers/Slot.ts +++ b/src/compiler/compile/render_dom/wrappers/Slot.ts @@ -10,12 +10,13 @@ import get_slot_data from '../../utils/get_slot_data'; import { stringify_props } from '../../utils/stringify_props'; import Expression from '../../nodes/shared/Expression'; import is_dynamic from './shared/is_dynamic'; +import { Identifier } from '../../../interfaces'; export default class SlotWrapper extends Wrapper { node: Slot; fragment: FragmentWrapper; - var = 'slot'; + var: Identifier = { type: 'Identifier', name: 'slot' }; dependencies: Set = new Set(['$$scope']); constructor( diff --git a/src/compiler/compile/render_dom/wrappers/Text.ts b/src/compiler/compile/render_dom/wrappers/Text.ts index 704d5aad77dd..747fe87fd9bd 100644 --- a/src/compiler/compile/render_dom/wrappers/Text.ts +++ b/src/compiler/compile/render_dom/wrappers/Text.ts @@ -3,6 +3,8 @@ import Block from '../Block'; import Text from '../../nodes/Text'; import Wrapper from './shared/Wrapper'; import { stringify } from '../../utils/stringify'; +import { Identifier } from '../../../interfaces'; +import { x } from 'code-red'; // Whitespace inside one of these elements will not result in // a whitespace node being created in any circumstances. (This @@ -33,7 +35,7 @@ export default class TextWrapper extends Wrapper { node: Text; data: string; skip: boolean; - var: string; + var: Identifier; constructor( renderer: Renderer, @@ -46,7 +48,7 @@ export default class TextWrapper extends Wrapper { this.skip = should_skip(this.node); this.data = data; - this.var = this.skip ? null : 't'; + this.var = (this.skip ? null : x`t`) as unknown as Identifier; } use_space() { @@ -69,9 +71,9 @@ export default class TextWrapper extends Wrapper { const use_space = this.use_space(); block.add_element( - this.var, - use_space ? `@space()` : `@text(${stringify(this.data)})`, - parent_nodes && (use_space ? `@claim_space(${parent_nodes})` : `@claim_text(${parent_nodes}, ${stringify(this.data)})`), + this.var.name, + use_space ? x`@space()` : x`@text(${stringify(this.data)})`, + parent_nodes && (use_space ? x`@claim_space(${parent_nodes})` : x`@claim_text(${parent_nodes}, ${stringify(this.data)})`), parent_node ); } diff --git a/src/compiler/compile/render_dom/wrappers/Title.ts b/src/compiler/compile/render_dom/wrappers/Title.ts index 0ccd85b87293..7d9c2d40a1ab 100644 --- a/src/compiler/compile/render_dom/wrappers/Title.ts +++ b/src/compiler/compile/render_dom/wrappers/Title.ts @@ -64,7 +64,7 @@ export default class TitleWrapper extends Wrapper { `title_value` ); - if (this.node.should_cache) block.add_variable(last); + if (this.node.should_cache) block.add_variable(last.name); const init = this.node.should_cache ? `${last} = ${value}` : value; diff --git a/src/compiler/compile/render_dom/wrappers/Window.ts b/src/compiler/compile/render_dom/wrappers/Window.ts index 84706f7d05ba..a2a84254ef53 100644 --- a/src/compiler/compile/render_dom/wrappers/Window.ts +++ b/src/compiler/compile/render_dom/wrappers/Window.ts @@ -73,14 +73,14 @@ export default class WindowWrapper extends Wrapper { const scrolling_timeout = block.get_unique_name(`scrolling_timeout`); Object.keys(events).forEach(event => { - const handler_name = block.get_unique_name(`onwindow${event}`); + const id = block.get_unique_name(`onwindow${event}`); const props = events[event]; if (event === 'scroll') { // TODO other bidirectional bindings... - block.add_variable(scrolling, 'false'); - block.add_variable(clear_scrolling, `() => { ${scrolling} = false }`); - block.add_variable(scrolling_timeout); + block.add_variable(scrolling.name, 'false'); + block.add_variable(clear_scrolling.name, `() => { ${scrolling} = false }`); + block.add_variable(scrolling_timeout.name); const condition = [ bindings.scrollX && `"${bindings.scrollX}" in this._state`, @@ -103,7 +103,7 @@ export default class WindowWrapper extends Wrapper { ${scrolling} = true; @_clearTimeout(${scrolling_timeout}); ${scrolling_timeout} = @_setTimeout(${clear_scrolling}, 100); - ctx.${handler_name}(); + ctx.${id}(); }) `); } else { @@ -114,24 +114,24 @@ export default class WindowWrapper extends Wrapper { }); block.event_listeners.push(b` - @listen(@_window, "${event}", ctx.${handler_name}) + @listen(@_window, "${event}", ctx.${id}) `); } component.add_var({ - name: handler_name, + name: id.name, internal: true, referenced: true }); component.partly_hoisted.push(b` - function ${handler_name}() { + function ${id}() { ${props.map(prop => `${prop.name} = @_window.${prop.value}; $$invalidate('${prop.name}', ${prop.name});`)} } `); block.chunks.init.push(b` - @add_render_callback(ctx.${handler_name}); + @add_render_callback(ctx.${id}); `); component.has_reactive_assignments = true; @@ -159,28 +159,28 @@ export default class WindowWrapper extends Wrapper { // another special case. (I'm starting to think these are all special cases.) if (bindings.online) { - const handler_name = block.get_unique_name(`onlinestatuschanged`); + const id = block.get_unique_name(`onlinestatuschanged`); const name = bindings.online; component.add_var({ - name: handler_name, + name: id.name, internal: true, referenced: true }); component.partly_hoisted.push(b` - function ${handler_name}() { + function ${id}() { ${name} = @_navigator.onLine; $$invalidate('${name}', ${name}); } `); block.chunks.init.push(b` - @add_render_callback(ctx.${handler_name}); + @add_render_callback(ctx.${id}); `); block.event_listeners.push( - `@listen(@_window, "online", ctx.${handler_name})`, - `@listen(@_window, "offline", ctx.${handler_name})` + `@listen(@_window, "online", ctx.${id})`, + `@listen(@_window, "offline", ctx.${id})` ); component.has_reactive_assignments = true; diff --git a/src/compiler/compile/render_dom/wrappers/shared/Tag.ts b/src/compiler/compile/render_dom/wrappers/shared/Tag.ts index d57f0184f415..e05e1cd6c821 100644 --- a/src/compiler/compile/render_dom/wrappers/shared/Tag.ts +++ b/src/compiler/compile/render_dom/wrappers/shared/Tag.ts @@ -20,12 +20,12 @@ export default class Tag extends Wrapper { update: ((value: string) => string) ) { const dependencies = this.node.expression.dynamic_dependencies(); - const snippet = this.node.expression.render(block); + const snippet = this.node.expression.node; const value = this.node.should_cache && block.get_unique_name(`${this.var}_value`); const content = this.node.should_cache ? value : snippet; - if (this.node.should_cache) block.add_variable(value, `${snippet} + ""`); + if (this.node.should_cache) block.add_variable(value.name, `${snippet} + ""`); if (dependencies.length > 0) { const changed_check = ( diff --git a/src/compiler/compile/render_dom/wrappers/shared/Wrapper.ts b/src/compiler/compile/render_dom/wrappers/shared/Wrapper.ts index 60c4a4187b5d..57e997721c08 100644 --- a/src/compiler/compile/render_dom/wrappers/shared/Wrapper.ts +++ b/src/compiler/compile/render_dom/wrappers/shared/Wrapper.ts @@ -1,6 +1,8 @@ import Renderer from '../../Renderer'; import Block from '../../Block'; import { INode } from '../../../nodes/interfaces'; +import { Identifier } from '../../../../interfaces'; +import { x } from 'code-red'; export default class Wrapper { renderer: Renderer; @@ -10,7 +12,7 @@ export default class Wrapper { prev: Wrapper | null; next: Wrapper | null; - var: string; + var: Identifier; can_use_innerhtml: boolean; constructor( @@ -48,13 +50,13 @@ export default class Wrapper { const needs_anchor = this.next ? !this.next.is_dom_node() : !parent_node || !this.parent.is_dom_node(); const anchor = needs_anchor ? block.get_unique_name(`${this.var}_anchor`) - : (this.next && this.next.var) || 'null'; + : (this.next && this.next.var) || { type: 'Identifier', name: 'null' }; if (needs_anchor) { block.add_element( - anchor, - `@empty()`, - parent_nodes && `@empty()`, + anchor.name, + x`@empty()`, + parent_nodes && x`@empty()`, parent_node ); } @@ -62,10 +64,10 @@ export default class Wrapper { return anchor; } - get_update_mount_node(anchor: string) { - return (this.parent && this.parent.is_dom_node()) + get_update_mount_node(anchor: Identifier): Identifier { + return ((this.parent && this.parent.is_dom_node()) ? this.parent.var - : `${anchor}.parentNode`; + : x`${anchor}.parentNode`) as Identifier; } is_dom_node() { 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 fdc74e2f3b34..bbcbadf87f9f 100644 --- a/src/compiler/compile/render_dom/wrappers/shared/add_actions.ts +++ b/src/compiler/compile/render_dom/wrappers/shared/add_actions.ts @@ -19,30 +19,30 @@ export default function add_actions( dependencies = expression.dynamic_dependencies(); } - const name = block.get_unique_name( + const id = block.get_unique_name( `${action.name.replace(/[^a-zA-Z0-9_$]/g, '_')}_action` ); - block.add_variable(name); + block.add_variable(id.name); const fn = component.qualify(action.name); block.chunks.mount.push( - b`${name} = ${fn}.call(null, ${target}${snippet ? `, ${snippet}` : ''}) || {};` + b`${id} = ${fn}.call(null, ${target}${snippet ? `, ${snippet}` : ''}) || {};` ); if (dependencies && dependencies.length > 0) { - let conditional = `typeof ${name}.update === 'function' && `; + let conditional = `typeof ${id}.update === 'function' && `; const deps = dependencies.map(dependency => `changed.${dependency}`).join(' || '); conditional += dependencies.length > 1 ? `(${deps})` : deps; block.chunks.update.push( - b`if (${conditional}) ${name}.update.call(null, ${snippet});` + b`if (${conditional}) ${id}.update.call(null, ${snippet});` ); } block.chunks.destroy.push( - b`if (${name} && typeof ${name}.destroy === 'function') ${name}.destroy();` + b`if (${id} && typeof ${id}.destroy === 'function') ${id}.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 0896dc39918c..b4e3d25e7dcc 100644 --- a/src/compiler/compile/render_dom/wrappers/shared/bind_this.ts +++ b/src/compiler/compile/render_dom/wrappers/shared/bind_this.ts @@ -8,7 +8,7 @@ export default function bind_this(component: Component, block: Block, binding: B const fn = component.get_unique_name(`${variable}_binding`); component.add_var({ - name: fn, + name: fn.name, internal: true, referenced: true }); diff --git a/src/compiler/compile/utils/stringify.ts b/src/compiler/compile/utils/stringify.ts index cd478b90ff56..650a49051a4e 100644 --- a/src/compiler/compile/utils/stringify.ts +++ b/src/compiler/compile/utils/stringify.ts @@ -2,6 +2,13 @@ export function stringify(data: string, options = {}) { return JSON.stringify(escape(data, options)); } +export function string_literal(data: string) { + return { + type: 'Literal', + value: data + }; +} + export function escape(data: string, { only_escape_at_symbol = false } = {}) { return data.replace(only_escape_at_symbol ? /@+/g : /(@+|#+)/g, (match: string) => { return match + match[0]; diff --git a/src/compiler/interfaces.ts b/src/compiler/interfaces.ts index d63194edcd93..dd73e53e4a46 100644 --- a/src/compiler/interfaces.ts +++ b/src/compiler/interfaces.ts @@ -1,3 +1,8 @@ +export interface Identifier { + type: 'Identifier'; + name: string; +} + interface BaseNode { start: number; end: number; diff --git a/test/runtime/samples/_/_config.js b/test/runtime/samples/_/_config.js new file mode 100644 index 000000000000..7ba33fb0089e --- /dev/null +++ b/test/runtime/samples/_/_config.js @@ -0,0 +1,5 @@ +export default { + solo: 1, + + html: '

Hello world!

' +}; \ No newline at end of file diff --git a/test/runtime/samples/_/main.svelte b/test/runtime/samples/_/main.svelte new file mode 100644 index 000000000000..efe5048cbcd5 --- /dev/null +++ b/test/runtime/samples/_/main.svelte @@ -0,0 +1 @@ +

Hello world!

\ No newline at end of file From a335d816fd09220bed45f82c0482a0345f3399d3 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Tue, 10 Sep 2019 18:27:19 -0400 Subject: [PATCH 03/93] use nodes instead of strings in more places --- src/compiler/compile/render_dom/Block.ts | 85 ++++++++++--------- src/compiler/compile/render_dom/index.ts | 13 +-- .../compile/render_dom/wrappers/AwaitBlock.ts | 2 +- .../compile/render_dom/wrappers/EachBlock.ts | 8 +- .../render_dom/wrappers/Element/Attribute.ts | 2 +- .../render_dom/wrappers/Element/Binding.ts | 4 +- .../render_dom/wrappers/Element/index.ts | 14 +-- .../compile/render_dom/wrappers/IfBlock.ts | 6 +- .../wrappers/InlineComponent/index.ts | 2 +- .../render_dom/wrappers/MustacheTag.ts | 2 +- .../render_dom/wrappers/RawMustacheTag.ts | 4 +- .../compile/render_dom/wrappers/Text.ts | 2 +- .../compile/render_dom/wrappers/Title.ts | 2 +- .../compile/render_dom/wrappers/Window.ts | 18 ++-- .../compile/render_dom/wrappers/shared/Tag.ts | 2 +- .../render_dom/wrappers/shared/Wrapper.ts | 2 +- .../render_dom/wrappers/shared/add_actions.ts | 2 +- .../render_dom/wrappers/shared/bind_this.ts | 8 +- test/runtime/index.js | 2 +- test/server-side-rendering/index.js | 3 + 20 files changed, 96 insertions(+), 87 deletions(-) diff --git a/src/compiler/compile/render_dom/Block.ts b/src/compiler/compile/render_dom/Block.ts index a94743b21ebe..746afd048fae 100644 --- a/src/compiler/compile/render_dom/Block.ts +++ b/src/compiler/compile/render_dom/Block.ts @@ -69,7 +69,7 @@ export default class Block { outros: number; aliases: Map; - variables: Map; + variables: Map = new Map(); get_unique_name: (name: string) => Identifier; has_update_method = false; @@ -113,7 +113,6 @@ export default class Block { this.outros = 0; this.get_unique_name = this.renderer.component.get_unique_name_maker(); - this.variables = new Map(); this.aliases = new Map().set('ctx', this.get_unique_name('ctx')); if (this.key) this.aliases.set('key', this.get_unique_name('key')); @@ -166,25 +165,25 @@ export default class Block { } add_element( - name: string, + id: Identifier, render_statement: Node, claim_statement: Node, parent_node: string, no_detach?: boolean ) { - this.add_variable(name); - this.chunks.create.push(b`${name} = ${render_statement};`); + this.add_variable(id); + this.chunks.create.push(b`${id} = ${render_statement};`); if (this.renderer.options.hydratable) { - this.chunks.claim.push(b`${name} = ${claim_statement || render_statement};`); + this.chunks.claim.push(b`${id} = ${claim_statement || render_statement};`); } if (parent_node) { - this.chunks.mount.push(b`@append(${parent_node}, ${name});`); - if (parent_node === '@_document.head' && !no_detach) this.chunks.destroy.push(b`@detach(${name});`); + this.chunks.mount.push(b`@append(${parent_node}, ${id});`); + if (parent_node === '@_document.head' && !no_detach) this.chunks.destroy.push(b`@detach(${id});`); } else { - this.chunks.mount.push(b`@insert(#target, ${name}, anchor);`); - if (!no_detach) this.chunks.destroy.push(b`if (detaching) @detach(${name});`); + this.chunks.mount.push(b`@insert(#target, ${id}, anchor);`); + if (!no_detach) this.chunks.destroy.push(b`if (detaching) @detach(${id});`); } } @@ -203,18 +202,21 @@ export default class Block { this.has_animation = true; } - add_variable(name: string, init?: string) { - if (name[0] === '#') { - name = this.alias(name.slice(1)).name; + add_variable(id: Identifier, init?: Node) { + if (id.name[0] === '#') { + // TODO is this still necessary? + id.name = this.alias(id.name.slice(1)).name; } - if (this.variables.has(name) && this.variables.get(name) !== init) { - throw new Error( - `Variable '${name}' already initialised with a different value` - ); - } + this.variables.forEach(v => { + if (v.id.name === id.name) { + throw new Error( + `Variable '${id.name}' already initialised with a different value` + ); + } + }); - this.variables.set(name, init); + this.variables.set(id.name, { id, init }); } alias(name: string) { @@ -233,7 +235,7 @@ export default class Block { const { dev } = this.renderer.options; if (this.has_outros) { - this.add_variable('#current'); + this.add_variable({ type: 'Identifier', name: '#current' }); if (this.chunks.intro.length > 0) { this.chunks.intro.push(b`#current = true;`); @@ -267,7 +269,7 @@ export default class Block { : this.chunks.hydrate ); - properties.create = b`function create() { + properties.create = x`function create() { ${this.chunks.create} ${hydrate} }`; @@ -352,32 +354,29 @@ export default class Block { } const return_value: any = x`{ - key: ${properties.key}, - first: ${properties.first}, - c: ${properties.create}, - l: ${properties.claim}, - h: ${properties.hydrate}, + // 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} + // p: ${properties.update}, + // r: ${properties.measure}, + // f: ${properties.fix}, + // a: ${properties.animate}, + // i: ${properties.intro}, + // o: ${properties.outro}, + // d: ${properties.destroy} }`; return_value.properties = return_value.properties.filter(prop => prop.value); /* eslint-disable @typescript-eslint/indent,indent */ return b` - ${Array.from(this.variables.entries()).map(([id, init]) => { - const id_node = { type: 'Identifier', name: id }; - const init_node = { type: 'Identifier', name: init }; - + ${Array.from(this.variables.values()).map(({ id, init }) => { return init - ? b`let ${id_node} = ${init_node}` - : b`let ${id_node}`; + ? b`let ${id} = ${init}` + : b`let ${id}`; })} ${this.chunks.init} @@ -414,10 +413,12 @@ export default class Block { render_listeners(chunk: string = '') { if (this.event_listeners.length > 0) { - const name = `#dispose${chunk}` - this.add_variable(name); + const dispose: Identifier = { + type: 'Identifier', + name: `#dispose${chunk}` + }; - const dispose = { type: 'Identifier', name }; + this.add_variable(dispose); if (this.event_listeners.length === 1) { this.chunks.hydrate.push( diff --git a/src/compiler/compile/render_dom/index.ts b/src/compiler/compile/render_dom/index.ts index 471bf09006a2..c7ce2cac7bc8 100644 --- a/src/compiler/compile/render_dom/index.ts +++ b/src/compiler/compile/render_dom/index.ts @@ -90,7 +90,7 @@ export default function dom( const accessors = []; - const not_equal = component.component_options.immutable ? `@not_equal` : `@safe_not_equal`; + const not_equal = component.component_options.immutable ? x`@not_equal` : x`@safe_not_equal`; let dev_props_check; let inject_state; let capture_state; props.forEach(x => { @@ -274,7 +274,7 @@ export default function dom( const definition = has_definition ? component.alias('instance') - : 'null'; + : { type: 'Literal', value: null }; const all_reactive_dependencies = new Set(); component.reactive_declarations.forEach(d => { @@ -390,7 +390,7 @@ export default function dom( `); } - const prop_names = `[${props.map(v => JSON.stringify(v.export_name)).join(', ')}]`; + const prop_names = x`[${props.map(v => ({ type: 'Literal', value: v.export_name }))}]`; if (options.customElement) { body.push(b` @@ -432,12 +432,15 @@ export default function dom( `); } } else { - const superclass = options.dev ? 'SvelteComponentDev' : 'SvelteComponent'; + const superclass = { + type: 'Identifier', + name: options.dev ? '@SvelteComponentDev' : '@SvelteComponent' + }; // TODO add accessors body.push(b` - class ${name} extends @${superclass} { + class ${name} extends ${superclass} { constructor(options) { super(${options.dev && `options`}); ${should_add_css && `if (!@_document.getElementById("${component.stylesheet.id}-style")) ${add_css}();`} diff --git a/src/compiler/compile/render_dom/wrappers/AwaitBlock.ts b/src/compiler/compile/render_dom/wrappers/AwaitBlock.ts index 684575641498..979bb553ce62 100644 --- a/src/compiler/compile/render_dom/wrappers/AwaitBlock.ts +++ b/src/compiler/compile/render_dom/wrappers/AwaitBlock.ts @@ -132,7 +132,7 @@ export default class AwaitBlockWrapper extends Wrapper { const info = block.get_unique_name(`info`); const promise = block.get_unique_name(`promise`); - block.add_variable(promise.name); + block.add_variable(promise); block.maintain_context = true; diff --git a/src/compiler/compile/render_dom/wrappers/EachBlock.ts b/src/compiler/compile/render_dom/wrappers/EachBlock.ts index a98d4a43d1b5..2ce1f11a4f5d 100644 --- a/src/compiler/compile/render_dom/wrappers/EachBlock.ts +++ b/src/compiler/compile/render_dom/wrappers/EachBlock.ts @@ -235,7 +235,7 @@ export default class EachBlockWrapper extends Wrapper { if (needs_anchor) { block.add_element( - (update_anchor_node as Identifier).name, + update_anchor_node as Identifier, x`@empty()`, parent_nodes && x`@empty()`, parent_node @@ -330,15 +330,15 @@ export default class EachBlockWrapper extends Wrapper { const get_key = block.get_unique_name('get_key'); const lookup = block.get_unique_name(`${this.var}_lookup`); - block.add_variable(iterations.name, '[]'); - block.add_variable(lookup.name, `new @_Map()`); + block.add_variable(iterations, x`[]`); + block.add_variable(lookup, x`new @_Map()`); if (this.fragment.nodes[0].is_dom_node()) { this.block.first = this.fragment.nodes[0].var; } else { this.block.first = this.block.get_unique_name('first'); this.block.add_element( - this.block.first.name, + this.block.first, x`@empty()`, parent_nodes && x`@empty()`, null diff --git a/src/compiler/compile/render_dom/wrappers/Element/Attribute.ts b/src/compiler/compile/render_dom/wrappers/Element/Attribute.ts index ac3532a30835..457e84f1523b 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/Attribute.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/Attribute.ts @@ -99,7 +99,7 @@ export default class AttributeWrapper { `${element.var}_${name.replace(/[^a-zA-Z_$]/g, '_')}_value` ); - if (should_cache) block.add_variable(last.name); + if (should_cache) block.add_variable(last); let updater; const init = should_cache ? `${last} = ${value}` : value; diff --git a/src/compiler/compile/render_dom/wrappers/Element/Binding.ts b/src/compiler/compile/render_dom/wrappers/Element/Binding.ts index d32e59e9e833..3ea94364b084 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/Binding.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/Binding.ts @@ -1,4 +1,4 @@ -import { b } from 'code-red'; +import { b, x } from 'code-red'; import Binding from '../../../nodes/Binding'; import ElementWrapper from '../Element'; import get_object from '../../../utils/get_object'; @@ -152,7 +152,7 @@ export default class BindingWrapper { { // this is necessary to prevent audio restarting by itself const last = block.get_unique_name(`${parent.var}_is_paused`); - block.add_variable(last.name, 'true'); + block.add_variable(last, x`true`); update_conditions.push(`${last} !== (${last} = ${this.snippet})`); update_dom = b`${parent.var}[${last} ? "pause" : "play"]();`; diff --git a/src/compiler/compile/render_dom/wrappers/Element/index.ts b/src/compiler/compile/render_dom/wrappers/Element/index.ts index c481f0311322..f9ff501255b3 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/index.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/index.ts @@ -421,7 +421,7 @@ export default class ElementWrapper extends Wrapper { block.get_unique_name(`${this.var}_updating`) : null; - if (lock) block.add_variable(lock.name, 'false'); + if (lock) block.add_variable(lock, x`false`); const groups = events .map(event => ({ @@ -508,7 +508,7 @@ export default class ElementWrapper extends Wrapper { if (name === 'resize') { // special case const resize_listener = block.get_unique_name(`${this.var}_resize_listener`); - block.add_variable(resize_listener.name); + block.add_variable(resize_listener); block.chunks.mount.push( b`${resize_listener} = @add_resize_listener(${this.var}, ${callee}.bind(${this.var}));` @@ -657,7 +657,7 @@ export default class ElementWrapper extends Wrapper { ? intro.expression.render(block) : '{}'; - block.add_variable(name.name); + block.add_variable(name); const fn = component.qualify(intro.name); @@ -698,7 +698,7 @@ export default class ElementWrapper extends Wrapper { const outro_name = outro && block.get_unique_name(`${this.var}_outro`); if (intro) { - block.add_variable(intro_name.name); + block.add_variable(intro_name); const snippet = intro.expression ? intro.expression.render(block) : '{}'; @@ -740,7 +740,7 @@ export default class ElementWrapper extends Wrapper { } if (outro) { - block.add_variable(outro_name.name); + block.add_variable(outro_name); const snippet = outro.expression ? outro.expression.render(block) : '{}'; @@ -783,8 +783,8 @@ export default class ElementWrapper extends Wrapper { const rect = block.get_unique_name('rect'); const stop_animation = block.get_unique_name('stop_animation'); - block.add_variable(rect.name); - block.add_variable(stop_animation.name, '@noop'); + block.add_variable(rect); + block.add_variable(stop_animation, x`@noop`); block.chunks.measure.push(b` ${rect} = ${this.var}.getBoundingClientRect(); diff --git a/src/compiler/compile/render_dom/wrappers/IfBlock.ts b/src/compiler/compile/render_dom/wrappers/IfBlock.ts index 311d8f7773b0..6dc6ff5f3305 100644 --- a/src/compiler/compile/render_dom/wrappers/IfBlock.ts +++ b/src/compiler/compile/render_dom/wrappers/IfBlock.ts @@ -226,7 +226,7 @@ export default class IfBlockWrapper extends Wrapper { if (needs_anchor) { block.add_element( - (anchor as Identifier).name, + anchor as Identifier, x`@empty()`, parent_nodes && x`@empty()`, parent_node @@ -342,7 +342,7 @@ export default class IfBlockWrapper extends Wrapper { ? '' : `if (~${current_block_type_index}) `; - block.add_variable(current_block_type_index.name); + block.add_variable(current_block_type_index); block.add_variable(name); /* eslint-disable @typescript-eslint/indent,indent */ @@ -472,7 +472,7 @@ export default class IfBlockWrapper extends Wrapper { ) { const branch = this.branches[0]; - if (branch.snippet) block.add_variable(branch.condition, '' + branch.snippet); + if (branch.snippet) block.add_variable(branch.condition, branch.snippet); block.chunks.init.push(b` var ${name} = (${branch.condition}) && ${branch.block.name}(ctx); diff --git a/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts b/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts index f58f53b0fb0d..1c0a8106c3a9 100644 --- a/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts +++ b/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts @@ -269,7 +269,7 @@ export default class InlineComponentWrapper extends Wrapper { }); const updating = block.get_unique_name(`updating_${binding.name}`); - block.add_variable(updating.name); + block.add_variable(updating); const snippet = binding.expression.render(block); diff --git a/src/compiler/compile/render_dom/wrappers/MustacheTag.ts b/src/compiler/compile/render_dom/wrappers/MustacheTag.ts index 434fcb85dc25..c3134a9be412 100644 --- a/src/compiler/compile/render_dom/wrappers/MustacheTag.ts +++ b/src/compiler/compile/render_dom/wrappers/MustacheTag.ts @@ -22,7 +22,7 @@ export default class MustacheTagWrapper extends Tag { ); block.add_element( - this.var.name, + this.var, x`@text(${init})`, parent_nodes && x`@claim_text(${parent_nodes}, ${init})`, parent_node diff --git a/src/compiler/compile/render_dom/wrappers/RawMustacheTag.ts b/src/compiler/compile/render_dom/wrappers/RawMustacheTag.ts index d4a7251832f8..b2c0fc86cf20 100644 --- a/src/compiler/compile/render_dom/wrappers/RawMustacheTag.ts +++ b/src/compiler/compile/render_dom/wrappers/RawMustacheTag.ts @@ -42,7 +42,7 @@ export default class RawMustacheTagWrapper extends Tag { const html_tag = block.get_unique_name('html_tag'); const html_anchor = needs_anchor && block.get_unique_name('html_anchor'); - block.add_variable(html_tag.name); + block.add_variable(html_tag); const { init } = this.rename_this_method( block, @@ -55,7 +55,7 @@ export default class RawMustacheTagWrapper extends Tag { block.chunks.mount.push(b`${html_tag}.m(${parent_node || '#target'}${parent_node ? '' : ', anchor'});`); if (needs_anchor) { - block.add_element(html_anchor.name, x`@empty()`, x`@empty()`, parent_node); + block.add_element(html_anchor, x`@empty()`, x`@empty()`, parent_node); } if (!parent_node || in_head) { diff --git a/src/compiler/compile/render_dom/wrappers/Text.ts b/src/compiler/compile/render_dom/wrappers/Text.ts index 747fe87fd9bd..1ada6805d404 100644 --- a/src/compiler/compile/render_dom/wrappers/Text.ts +++ b/src/compiler/compile/render_dom/wrappers/Text.ts @@ -71,7 +71,7 @@ export default class TextWrapper extends Wrapper { const use_space = this.use_space(); block.add_element( - this.var.name, + this.var, use_space ? x`@space()` : x`@text(${stringify(this.data)})`, parent_nodes && (use_space ? x`@claim_space(${parent_nodes})` : x`@claim_text(${parent_nodes}, ${stringify(this.data)})`), parent_node diff --git a/src/compiler/compile/render_dom/wrappers/Title.ts b/src/compiler/compile/render_dom/wrappers/Title.ts index 7d9c2d40a1ab..0ccd85b87293 100644 --- a/src/compiler/compile/render_dom/wrappers/Title.ts +++ b/src/compiler/compile/render_dom/wrappers/Title.ts @@ -64,7 +64,7 @@ export default class TitleWrapper extends Wrapper { `title_value` ); - if (this.node.should_cache) block.add_variable(last.name); + if (this.node.should_cache) block.add_variable(last); const init = this.node.should_cache ? `${last} = ${value}` : value; diff --git a/src/compiler/compile/render_dom/wrappers/Window.ts b/src/compiler/compile/render_dom/wrappers/Window.ts index a2a84254ef53..2bc6840a9d9d 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 { b } from 'code-red'; +import { b, x } from 'code-red'; import add_event_handlers from './shared/add_event_handlers'; import Window from '../../nodes/Window'; import add_actions from './shared/add_actions'; @@ -78,24 +78,24 @@ export default class WindowWrapper extends Wrapper { if (event === 'scroll') { // TODO other bidirectional bindings... - block.add_variable(scrolling.name, 'false'); - block.add_variable(clear_scrolling.name, `() => { ${scrolling} = false }`); - block.add_variable(scrolling_timeout.name); + block.add_variable(scrolling, x`false`); + block.add_variable(clear_scrolling, x`() => { ${scrolling} = false }`); + block.add_variable(scrolling_timeout); const condition = [ bindings.scrollX && `"${bindings.scrollX}" in this._state`, bindings.scrollY && `"${bindings.scrollY}" in this._state` ].filter(Boolean).join(' || '); - const x = bindings.scrollX && `this._state.${bindings.scrollX}`; - const y = bindings.scrollY && `this._state.${bindings.scrollY}`; + const scrollX = bindings.scrollX && `this._state.${bindings.scrollX}`; + const scrollY = bindings.scrollY && `this._state.${bindings.scrollY}`; renderer.meta_bindings.push(b` if (${condition}) { - @_scrollTo(${x || '@_window.pageXOffset'}, ${y || '@_window.pageYOffset'}); + @_scrollTo(${scrollX || '@_window.pageXOffset'}, ${scrollY || '@_window.pageYOffset'}); } - ${x && `${x} = @_window.pageXOffset;`} - ${y && `${y} = @_window.pageYOffset;`} + ${scrollX && `${scrollX} = @_window.pageXOffset;`} + ${scrollY && `${scrollY} = @_window.pageYOffset;`} `); block.event_listeners.push(b` diff --git a/src/compiler/compile/render_dom/wrappers/shared/Tag.ts b/src/compiler/compile/render_dom/wrappers/shared/Tag.ts index e05e1cd6c821..b67617965a88 100644 --- a/src/compiler/compile/render_dom/wrappers/shared/Tag.ts +++ b/src/compiler/compile/render_dom/wrappers/shared/Tag.ts @@ -25,7 +25,7 @@ export default class Tag extends Wrapper { const value = this.node.should_cache && block.get_unique_name(`${this.var}_value`); const content = this.node.should_cache ? value : snippet; - if (this.node.should_cache) block.add_variable(value.name, `${snippet} + ""`); + if (this.node.should_cache) block.add_variable(value, snippet); // TODO may need to coerce snippet to string if (dependencies.length > 0) { const changed_check = ( diff --git a/src/compiler/compile/render_dom/wrappers/shared/Wrapper.ts b/src/compiler/compile/render_dom/wrappers/shared/Wrapper.ts index 57e997721c08..cad5b8423501 100644 --- a/src/compiler/compile/render_dom/wrappers/shared/Wrapper.ts +++ b/src/compiler/compile/render_dom/wrappers/shared/Wrapper.ts @@ -54,7 +54,7 @@ export default class Wrapper { if (needs_anchor) { block.add_element( - anchor.name, + anchor, x`@empty()`, parent_nodes && x`@empty()`, parent_node 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 bbcbadf87f9f..485ae9b9fd40 100644 --- a/src/compiler/compile/render_dom/wrappers/shared/add_actions.ts +++ b/src/compiler/compile/render_dom/wrappers/shared/add_actions.ts @@ -23,7 +23,7 @@ export default function add_actions( `${action.name.replace(/[^a-zA-Z0-9_$]/g, '_')}_action` ); - block.add_variable(id.name); + block.add_variable(id); const fn = component.qualify(action.name); 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 b4e3d25e7dcc..24dd2b39723a 100644 --- a/src/compiler/compile/render_dom/wrappers/shared/bind_this.ts +++ b/src/compiler/compile/render_dom/wrappers/shared/bind_this.ts @@ -1,8 +1,9 @@ import flatten_reference from '../../../utils/flatten_reference'; -import { b } from 'code-red'; +import { b, x } from 'code-red'; import Component from '../../../Component'; import Block from '../../Block'; import Binding from '../../../nodes/Binding'; +import { Identifier } from '../../../../interfaces'; export default function bind_this(component: Component, block: Block, binding: Binding, variable: string) { const fn = component.get_unique_name(`${variable}_binding`); @@ -53,8 +54,9 @@ export default function bind_this(component: Component, block: Block, binding: B const args = []; for (const arg of contextual_dependencies) { - args.push(arg); - block.add_variable(arg, `ctx.${arg}`); + const id: Identifier = { type: 'Identifier', name: arg }; + args.push(id); + block.add_variable(id, x`ctx.${id}`); } const assign = block.get_unique_name(`assign_${variable}`); diff --git a/test/runtime/index.js b/test/runtime/index.js index 880e316e0c57..ae1b40847c39 100644 --- a/test/runtime/index.js +++ b/test/runtime/index.js @@ -211,7 +211,7 @@ describe("runtime", () => { fs.readdirSync("test/runtime/samples").forEach(dir => { runTest(dir, false); - runTest(dir, true); + // runTest(dir, true); }); async function create_component(src = '
') { diff --git a/test/server-side-rendering/index.js b/test/server-side-rendering/index.js index cf6e5ad96447..b1752249ea18 100644 --- a/test/server-side-rendering/index.js +++ b/test/server-side-rendering/index.js @@ -80,6 +80,9 @@ describe("ssr", () => { }); }); + // TODO re-enable SSR tests + return; + // duplicate client-side tests, as far as possible fs.readdirSync("test/runtime/samples").forEach(dir => { if (dir[0] === ".") return; From 8addd2313e51bcbf8a5b32b612169e8f5290a19f Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Tue, 10 Sep 2019 18:27:44 -0400 Subject: [PATCH 04/93] bump code-red --- package-lock.json | 13 ++++++------- package.json | 2 +- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index d4922a204908..1f3c60c8d57c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -331,9 +331,8 @@ "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==", + "version": "github:Rich-Harris/astring#ff83f5e4e75b304cdd428ada4a71372276b0084d", + "from": "github:Rich-Harris/astring#generic-handler", "dev": true }, "async-limiter": { @@ -508,13 +507,13 @@ "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==", + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/code-red/-/code-red-0.0.6.tgz", + "integrity": "sha512-nsAPEQ+o1Z8UyIbOaOqfTxWHaA4JarPH7OBxDPmqAkkRvATvc2j7khlaAtsXnFreH2fTwekmZed4GlHvY3hQiw==", "dev": true, "requires": { "acorn": "^7.0.0", - "astring": "^1.4.1", + "astring": "github:Rich-Harris/astring#generic-handler", "estree-walker": "^0.6.1", "is-reference": "^1.1.3", "periscopic": "^1.0.0", diff --git a/package.json b/package.json index 3ad84f260158..945b01cf126e 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,7 @@ "acorn": "^7.0.0", "agadoo": "^1.0.1", "c8": "^5.0.1", - "code-red": "0.0.2", + "code-red": "0.0.6", "codecov": "^3.5.0", "css-tree": "1.0.0-alpha22", "eslint": "^6.3.0", From 0bcbe965dc0cb3710374845170f10bdb7d398f80 Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Tue, 10 Sep 2019 22:35:58 -0400 Subject: [PATCH 05/93] baby steps --- package-lock.json | 8 +- package.json | 2 +- src/compiler/compile/Component.ts | 71 ++----- src/compiler/compile/create_module.ts | 225 ++++++++++++++--------- src/compiler/compile/render_dom/Block.ts | 29 +-- src/compiler/compile/render_dom/index.ts | 22 ++- test/runtime/index.js | 7 +- test/runtime/samples/_/_config.js | 1 + 8 files changed, 196 insertions(+), 169 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1f3c60c8d57c..7479160cad4d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -507,13 +507,13 @@ "dev": true }, "code-red": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/code-red/-/code-red-0.0.6.tgz", - "integrity": "sha512-nsAPEQ+o1Z8UyIbOaOqfTxWHaA4JarPH7OBxDPmqAkkRvATvc2j7khlaAtsXnFreH2fTwekmZed4GlHvY3hQiw==", + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/code-red/-/code-red-0.0.7.tgz", + "integrity": "sha512-UgcXT2tiYOFe5MF6FYeP1s+XKvd5XFlm+p+By6/Q/0/NwgT2ZqkR32liLhosDivtO1vvtLTg51LN1LUW5AYSEw==", "dev": true, "requires": { "acorn": "^7.0.0", - "astring": "github:Rich-Harris/astring#generic-handler", + "astring": "github:Rich-Harris/astring#ff83f5e4e75b304cdd428ada4a71372276b0084d", "estree-walker": "^0.6.1", "is-reference": "^1.1.3", "periscopic": "^1.0.0", diff --git a/package.json b/package.json index 945b01cf126e..42eb37276f5b 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,7 @@ "acorn": "^7.0.0", "agadoo": "^1.0.1", "c8": "^5.0.1", - "code-red": "0.0.6", + "code-red": "0.0.7", "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 addc00b3eb21..c915251e4d13 100644 --- a/src/compiler/compile/Component.ts +++ b/src/compiler/compile/Component.ts @@ -1,4 +1,4 @@ -import MagicString, { Bundle } from 'magic-string'; +import MagicString from 'magic-string'; // @ts-ignore import { walk, childKeys } from 'estree-walker'; import { getLocator } from 'locate-character'; @@ -333,8 +333,16 @@ export default class Component { // } // ); - const printed = print({ type: 'Program', body: result } as any); - console.log(printed); + const program: any = { type: 'Program', body: result }; + + walk(program, { + enter: (node) => { + if (node.type === 'Identifier' && node.name[0] === '@') { + const alias = this.helper(node.name.slice(1)); + node.name = alias.name; + } + } + }); const referenced_globals = Array.from( this.globals, @@ -348,10 +356,10 @@ export default class Component { alias, })); - const module = create_module( - printed.code, + create_module( + program, format, - name.name, + name, banner, compile_options.sveltePath, imported_helpers, @@ -362,61 +370,14 @@ export default class Component { .map(variable => ({ name: variable.name, as: variable.export_name, - })), - this.source + })) ); - const parts = module.split('✂]'); - const final_chunk = parts.pop(); - - const compiled = new Bundle({ separator: '' }); - - function add_string(str: string) { - compiled.addSource({ - content: new MagicString(str), - }); - } - - const { filename } = compile_options; - - // special case — the source file doesn't actually get used anywhere. we need - // to add an empty file to populate map.sources and map.sourcesContent - if (!parts.length) { - compiled.addSource({ - filename, - content: new MagicString(this.source).remove(0, this.source.length), - }); - } - - const pattern = /\[✂(\d+)-(\d+)$/; - - parts.forEach((str: string) => { - const chunk = str.replace(pattern, ''); - if (chunk) add_string(chunk); - - const match = pattern.exec(str); - - const snippet = this.code.snip(+match[1], +match[2]); - - compiled.addSource({ - filename, - content: snippet, - }); - }); - - add_string(final_chunk); - css = compile_options.customElement ? { code: null, map: null } : this.stylesheet.render(compile_options.cssOutputFilename, true); - js = { - code: compiled.toString(), - map: compiled.generateMap({ - includeContent: true, - file: compile_options.outputFilename, - }), - }; + js = print(program); } return { diff --git a/src/compiler/compile/create_module.ts b/src/compiler/compile/create_module.ts index 83ba38c510db..2e2525883582 100644 --- a/src/compiler/compile/create_module.ts +++ b/src/compiler/compile/create_module.ts @@ -1,7 +1,6 @@ -import deindent from './utils/deindent'; import list from '../utils/list'; import { ModuleFormat, Node, Identifier } from '../interfaces'; -import { stringify_props } from './utils/stringify_props'; +import { b, x } from 'code-red'; const wrappers = { esm, cjs }; @@ -11,24 +10,23 @@ interface Export { } export default function create_module( - code: string, + program: any, format: ModuleFormat, - name: string, + name: Identifier, banner: string, sveltePath = 'svelte', helpers: Array<{ name: string; alias: Identifier }>, globals: Array<{ name: string; alias: Identifier }>, imports: Node[], - module_exports: Export[], - source: string -): string { + module_exports: Export[] +) { const internal_path = `${sveltePath}/internal`; if (format === 'esm') { - return esm(code, name, banner, sveltePath, internal_path, helpers, globals, imports, module_exports, source); + return esm(program, name, banner, sveltePath, internal_path, helpers, globals, imports, module_exports); } - if (format === 'cjs') return cjs(code, name, banner, sveltePath, internal_path, helpers, globals, imports, module_exports); + if (format === 'cjs') return cjs(program, name, banner, sveltePath, internal_path, helpers, globals, imports, module_exports); throw new Error(`options.format is invalid (must be ${list(Object.keys(wrappers))})`); } @@ -40,54 +38,75 @@ function edit_source(source, sveltePath) { } function esm( - code: string, - name: string, - banner: string, + program: any, + name: Identifier, + _banner: string, sveltePath: string, internal_path: string, helpers: Array<{ name: string; alias: Identifier }>, globals: Array<{ name: string; alias: Identifier }>, imports: Node[], - module_exports: Export[], - source: string + module_exports: Export[] ) { - const internal_imports = helpers.length > 0 && ( - `import ${stringify_props(helpers.map(h => h.name === h.alias.name ? h.name : `${h.name} as ${h.alias}`).sort())} from ${JSON.stringify(internal_path)};` - ); - const internal_globals = globals.length > 0 && ( - `const ${stringify_props(globals.map(g => `${g.name}: ${g.alias}`).sort())} = ${helpers.find(({ name }) => name === 'globals').alias};` - ); - - const user_imports = imports.length > 0 && ( - imports - .map((declaration: Node) => { - const import_source = edit_source(declaration.source.value, sveltePath); - - return ( - source.slice(declaration.start, declaration.source.start) + - JSON.stringify(import_source) + - source.slice(declaration.source.end, declaration.end) - ); - }) - .join('\n') - ); - - return deindent` - ${banner} - ${internal_imports} + const import_declaration = { + type: 'ImportDeclaration', + specifiers: helpers.map(h => ({ + type: 'ImportSpecifier', + local: h.alias, + imported: { type: 'Identifier', name: h.name } + })), + source: { type: 'Literal', value: internal_path } + } + + const internal_globals = globals.length > 0 &&{ + type: 'VariableDeclaration', + kind: 'const', + declarations: [{ + id: { + type: 'ObjectPattern', + properties: globals.sort((a, b) => a.name < b.name ? -1 : 1).map(g => ({ + type: 'Property', + method: false, + shorthand: false, + computed: false, + key: { type: 'Identifier', name: g.name }, + value: { type: 'Identifier', name: g.alias } + })) + }, + init: { type: 'Identifier', name: helpers.find(({ name }) => name === 'globals').alias } + }] + }; + + // edit user imports + imports.forEach(node => { + node.source.value = edit_source(node.source.value, sveltePath); + }); + + const exports = module_exports.length > 0 && { + type: 'ExportNamedDeclaration', + specifiers: module_exports.map(x => ({ + type: 'Specifier', + local: { type: 'Identifier', name: x.name }, + exported: { type: 'Identifier', name: x.as } + })) + }; + + program.body = b` + ${import_declaration} ${internal_globals} - ${user_imports} + ${imports} - ${code} + ${program.body} export default ${name}; - ${module_exports.length > 0 && `export { ${module_exports.map(e => e.name === e.as ? e.name : `${e.name} as ${e.as}`).join(', ')} };`}`; + ${exports} + `; } function cjs( - code: string, - name: string, - banner: string, + program: any, + name: Identifier, + _banner: string, sveltePath: string, internal_path: string, helpers: Array<{ name: string; alias: Identifier }>, @@ -95,52 +114,80 @@ function cjs( imports: Node[], module_exports: Export[] ) { - const declarations = helpers.map(h => `${h.alias.name === h.name ? h.name : `${h.name}: ${h.alias}`}`).sort(); - - const internal_imports = helpers.length > 0 && ( - `const ${stringify_props(declarations)} = require(${JSON.stringify(internal_path)});\n` - ); - const internal_globals = globals.length > 0 && ( - `const ${stringify_props(globals.map(g => `${g.name}: ${g.alias}`).sort())} = ${helpers.find(({ name }) => name === 'globals').alias};` - ); - - const requires = imports.map(node => { - let lhs; - - if (node.specifiers[0].type === 'ImportNamespaceSpecifier') { - lhs = node.specifiers[0].local.name; - } else { - const properties = node.specifiers.map(s => { - if (s.type === 'ImportDefaultSpecifier') { - return `default: ${s.local.name}`; - } - - return s.local.name === s.imported.name - ? s.local.name - : `${s.imported.name}: ${s.local.name}`; - }); - - lhs = `{ ${properties.join(', ')} }`; - } - - const source = edit_source(node.source.value, sveltePath); - - return `const ${lhs} = require("${source}");`; - }); - - const exports = [`exports.default = ${name};`].concat( - module_exports.map(x => `exports.${x.as} = ${x.name};`) - ); - - return deindent` - ${banner} + const internal_requires = { + type: 'VariableDeclaration', + kind: 'const', + declarations: [{ + type: 'VariableDeclarator', + id: { + type: 'ObjectPattern', + properties: helpers.sort((a, b) => a.name < b.name ? -1 : 1).map(h => ({ + type: 'Property', + method: false, + shorthand: false, + computed: false, + key: { type: 'Identifier', name: h.name }, + value: h.alias, + kind: 'init' + })) + }, + init: x`require("${internal_path}")` + }] + }; + + const internal_globals = globals.length > 0 &&{ + type: 'VariableDeclaration', + kind: 'const', + declarations: [{ + type: 'VariableDeclarator', + id: { + type: 'ObjectPattern', + properties: globals.sort((a, b) => a.name < b.name ? -1 : 1).map(g => ({ + type: 'Property', + method: false, + shorthand: false, + computed: false, + key: { type: 'Identifier', name: g.name }, + value: { type: 'Identifier', name: g.alias } + })) + }, + init: { type: 'Identifier', name: helpers.find(({ name }) => name === 'globals').alias } + }] + }; + + const user_requires = imports.map(node => ({ + type: 'VariableDeclaration', + kind: 'const', + declarations: [{ + type: 'VariableDeclarator', + id: node.specifiers[0].type === 'ImportNamespaceSpecifier' + ? { type: 'Identifier', name: node.specifiers[0].local.name } + : { + type: 'ObjectPattern', + properties: node.specifiers.map(s => ({ + type: 'Property', + method: false, + shorthand: false, + computed: false, + key: s.imported || { type: 'Identifier', name: 'default' }, + value: s.local + })) + }, + init: x`require("${edit_source(node.source.value, sveltePath)}")` + }] + })); + + const exports = module_exports.map(x => b`exports.${{ type: 'Identifier', name: x.as }} = ${{ type: 'Identifier', name: x.name }};`); + + program.body = b` "use strict"; + ${internal_requires} + // ${internal_globals} + ${user_requires} - ${internal_imports} - ${internal_globals} - ${requires} - - ${code} + ${program.body} - ${exports}`; + exports.default = ${name}; + ${exports} + `; } diff --git a/src/compiler/compile/render_dom/Block.ts b/src/compiler/compile/render_dom/Block.ts index 746afd048fae..e1cc3d6a3d0d 100644 --- a/src/compiler/compile/render_dom/Block.ts +++ b/src/compiler/compile/render_dom/Block.ts @@ -255,7 +255,7 @@ export default class Block { const properties: Record = {}; - const noop = x`noop`; + const noop = x`@noop`; properties.key = key properties.first = this.first; @@ -296,7 +296,7 @@ export default class Block { properties.mount = noop; } else { properties.mount = x`function mount(#target, anchor) { - //${this.chunks.mount} + ${this.chunks.mount} }`; } @@ -354,21 +354,22 @@ export default class Block { } const return_value: any = x`{ - // key: ${properties.key}, - // first: ${properties.first}, - // c: ${properties.create}, - // l: ${properties.claim}, - // h: ${properties.hydrate}, + 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} + p: ${properties.update}, + r: ${properties.measure}, + f: ${properties.fix}, + a: ${properties.animate}, + i: ${properties.intro}, + o: ${properties.outro}, + d: ${properties.destroy} }`; + // TODO should code-red do this automatically? probably return_value.properties = return_value.properties.filter(prop => prop.value); /* eslint-disable @typescript-eslint/indent,indent */ diff --git a/src/compiler/compile/render_dom/index.ts b/src/compiler/compile/render_dom/index.ts index c7ce2cac7bc8..6612895a2572 100644 --- a/src/compiler/compile/render_dom/index.ts +++ b/src/compiler/compile/render_dom/index.ts @@ -390,7 +390,12 @@ export default function dom( `); } - const prop_names = x`[${props.map(v => ({ type: 'Literal', value: v.export_name }))}]`; + const prop_names = x`[]`; + + // TODO find a more idiomatic way of doing this + props.forEach(v => { + (prop_names as any).elements.push({ type: 'Literal', value: v.export_name }); + }); if (options.customElement) { body.push(b` @@ -453,5 +458,18 @@ export default function dom( `); } - return body; + return flatten(body, []); +} + +function flatten(nodes: any[], target: any[]) { + for (let i = 0; i < nodes.length; i += 1) { + const node = nodes[i]; + if (Array.isArray(node)) { + flatten(node, target); + } else { + target.push(node); + } + } + + return target; } diff --git a/test/runtime/index.js b/test/runtime/index.js index ae1b40847c39..505ac4d139f6 100644 --- a/test/runtime/index.js +++ b/test/runtime/index.js @@ -3,7 +3,7 @@ import * as path from "path"; import * as fs from "fs"; import { rollup } from 'rollup'; import * as virtual from 'rollup-plugin-virtual'; -import { clear_loops, flush, set_now, set_raf } from "../../internal"; +import { clear_loops, flush, set_now, set_raf, component_subscribe } from "../../internal"; import { showOutput, @@ -33,9 +33,7 @@ describe("runtime", () => { require.extensions[".svelte"] = function(module, filename) { const options = Object.assign({ - filename, - format: 'cjs', - sveltePath + filename }, compileOptions); const { js: { code } } = compile(fs.readFileSync(filename, "utf-8"), options); @@ -72,6 +70,7 @@ describe("runtime", () => { const cwd = path.resolve(`test/runtime/samples/${dir}`); compileOptions = config.compileOptions || {}; + compileOptions.format = 'cjs'; compileOptions.sveltePath = sveltePath; compileOptions.hydratable = hydrate; compileOptions.immutable = config.immutable; diff --git a/test/runtime/samples/_/_config.js b/test/runtime/samples/_/_config.js index 7ba33fb0089e..e7538c4ecfb8 100644 --- a/test/runtime/samples/_/_config.js +++ b/test/runtime/samples/_/_config.js @@ -1,5 +1,6 @@ export default { solo: 1, + show: 1, html: '

Hello world!

' }; \ No newline at end of file From 1d8d17bc0714b7aa97df293631826b3aae717b02 Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Wed, 11 Sep 2019 08:51:37 -0400 Subject: [PATCH 06/93] hoist nodes, not snippets --- package-lock.json | 6 +++--- package.json | 2 +- src/compiler/compile/Component.ts | 20 +++++++++++++------ src/compiler/compile/nodes/EventHandler.ts | 4 ++-- .../compile/nodes/shared/Expression.ts | 6 ++++-- src/compiler/compile/render_dom/index.ts | 3 ++- .../compile/render_dom/wrappers/Text.ts | 5 ++--- src/compiler/compile/render_ssr/index.ts | 2 +- .../compile/utils/flatten_reference.ts | 4 +--- src/compiler/compile/utils/snip.ts | 1 + test/runtime/samples/_/main.svelte | 6 +++++- 11 files changed, 36 insertions(+), 23 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7479160cad4d..ada0a223f88c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -507,9 +507,9 @@ "dev": true }, "code-red": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/code-red/-/code-red-0.0.7.tgz", - "integrity": "sha512-UgcXT2tiYOFe5MF6FYeP1s+XKvd5XFlm+p+By6/Q/0/NwgT2ZqkR32liLhosDivtO1vvtLTg51LN1LUW5AYSEw==", + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/code-red/-/code-red-0.0.8.tgz", + "integrity": "sha512-wvKPondTM1H6MoUnz5tj6z1xawzmaulkC0qLv5S1KLkShWgRybgIdvGyVr5pPQt2ovpdmh6BcpRXXoqs5X8tcA==", "dev": true, "requires": { "acorn": "^7.0.0", diff --git a/package.json b/package.json index 42eb37276f5b..f7d3d85a4e04 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,7 @@ "acorn": "^7.0.0", "agadoo": "^1.0.1", "c8": "^5.0.1", - "code-red": "0.0.7", + "code-red": "0.0.8", "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 c915251e4d13..2edc2d6cfcc2 100644 --- a/src/compiler/compile/Component.ts +++ b/src/compiler/compile/Component.ts @@ -111,8 +111,8 @@ export default class Component { hoistable_nodes: Set = new Set(); node_for_declaration: Map = new Map(); - partly_hoisted: string[] = []; - fully_hoisted: string[] = []; + partly_hoisted: Node[] = []; + fully_hoisted: Node[] = []; reactive_declarations: Array<{ assignees: Set; dependencies: Set; @@ -1077,7 +1077,11 @@ export default class Component { const top_level_function_declarations = new Map(); - this.ast.instance.content.body.forEach(node => { + const { body } = this.ast.instance.content; + let i = body.length; + while (i--) { + const node = body[i]; + if (node.type === 'VariableDeclaration') { const all_hoistable = node.declarations.every(d => { if (!d.init) return false; @@ -1105,7 +1109,9 @@ export default class Component { }); hoistable_nodes.add(node); - this.fully_hoisted.push(`[✂${node.start}-${node.end}✂]`); + + body.splice(i, 1); + this.fully_hoisted.push(node); } } @@ -1120,7 +1126,7 @@ export default class Component { if (node.type === 'FunctionDeclaration') { top_level_function_declarations.set(node.id.name, node); } - }); + } const checked = new Set(); const walking = new Set(); @@ -1209,7 +1215,9 @@ export default class Component { remove_indentation(this.code, node); - this.fully_hoisted.push(`[✂${node.start}-${node.end}✂]`); + const i = body.indexOf(node); + body.splice(i, 1); + this.fully_hoisted.push(node); } } } diff --git a/src/compiler/compile/nodes/EventHandler.ts b/src/compiler/compile/nodes/EventHandler.ts index 428ee678bf81..688f7e85ceae 100644 --- a/src/compiler/compile/nodes/EventHandler.ts +++ b/src/compiler/compile/nodes/EventHandler.ts @@ -1,7 +1,7 @@ import Node from './shared/Node'; import Expression from './shared/Expression'; import Component from '../Component'; -import deindent from '../utils/deindent'; +import { b } from 'code-red'; import Block from '../render_dom/Block'; import { sanitize } from '../../utils/names'; import { Identifier } from '../../interfaces'; @@ -51,7 +51,7 @@ export default class EventHandler extends Node { referenced: true }); - component.partly_hoisted.push(deindent` + component.partly_hoisted.push(b` function ${id}(event) { @bubble($$self, event); } diff --git a/src/compiler/compile/nodes/shared/Expression.ts b/src/compiler/compile/nodes/shared/Expression.ts index ffb0f4ea3a1a..87469309f999 100644 --- a/src/compiler/compile/nodes/shared/Expression.ts +++ b/src/compiler/compile/nodes/shared/Expression.ts @@ -325,8 +325,8 @@ export default class Expression { const body = code.slice(node.body.start, node.body.end).trim(); const fn = node.type === 'FunctionExpression' - ? `${node.async ? 'async ' : ''}function${node.generator ? '*' : ''} ${id}(${args.join(', ')}) ${body}` - : `const ${id} = ${node.async ? 'async ' : ''}(${args.join(', ')}) => ${body};`; + ? b`${node.async ? 'async ' : ''}function${node.generator ? '*' : ''} ${id}(${args.join(', ')}) ${body}` + : b`const ${id} = ${node.async ? 'async ' : ''}(${args.join(', ')}) => ${body};`; if (dependencies.size === 0 && contextual_dependencies.size === 0) { // we can hoist this out of the component completely @@ -411,6 +411,8 @@ export default class Expression { }); } + throw new Error(`bad`); + return this.rendered = `[✂${this.node.start}-${this.node.end}✂]`; } } diff --git a/src/compiler/compile/render_dom/index.ts b/src/compiler/compile/render_dom/index.ts index 6612895a2572..f514692bed68 100644 --- a/src/compiler/compile/render_dom/index.ts +++ b/src/compiler/compile/render_dom/index.ts @@ -236,7 +236,7 @@ export default function dom( ${component.module_javascript} - ${component.fully_hoisted.length > 0 && component.fully_hoisted.join('\n\n')} + ${component.fully_hoisted} `); const filtered_declarations = component.vars @@ -314,6 +314,7 @@ export default function dom( }) .map(n => `$$dirty.${n}`).join(' || '); + throw new Error(`bad`); let snippet = `[✂${d.node.body.start}-${d.node.end}✂]`; if (condition) snippet = `if (${condition}) { ${snippet} }`; diff --git a/src/compiler/compile/render_dom/wrappers/Text.ts b/src/compiler/compile/render_dom/wrappers/Text.ts index 1ada6805d404..553ecd8e83b6 100644 --- a/src/compiler/compile/render_dom/wrappers/Text.ts +++ b/src/compiler/compile/render_dom/wrappers/Text.ts @@ -2,7 +2,6 @@ import Renderer from '../Renderer'; import Block from '../Block'; import Text from '../../nodes/Text'; import Wrapper from './shared/Wrapper'; -import { stringify } from '../../utils/stringify'; import { Identifier } from '../../../interfaces'; import { x } from 'code-red'; @@ -72,8 +71,8 @@ export default class TextWrapper extends Wrapper { block.add_element( this.var, - use_space ? x`@space()` : x`@text(${stringify(this.data)})`, - parent_nodes && (use_space ? x`@claim_space(${parent_nodes})` : x`@claim_text(${parent_nodes}, ${stringify(this.data)})`), + use_space ? x`@space()` : x`@text("${this.data}")`, + parent_nodes && (use_space ? x`@claim_space(${parent_nodes})` : x`@claim_text(${parent_nodes}, "${this.data}")`), parent_node ); } diff --git a/src/compiler/compile/render_ssr/index.ts b/src/compiler/compile/render_ssr/index.ts index 29e71f072b36..3ab504bd77f2 100644 --- a/src/compiler/compile/render_ssr/index.ts +++ b/src/compiler/compile/render_ssr/index.ts @@ -145,7 +145,7 @@ export default function ssr( ${component.module_javascript} - ${component.fully_hoisted.length > 0 && component.fully_hoisted.join('\n\n')} + ${component.fully_hoisted} const ${name} = @create_ssr_component(($$result, $$props, $$bindings, $$slots) => { ${blocks.join('\n\n')} diff --git a/src/compiler/compile/utils/flatten_reference.ts b/src/compiler/compile/utils/flatten_reference.ts index 460cd2f1e9cc..7b814d5e19f6 100644 --- a/src/compiler/compile/utils/flatten_reference.ts +++ b/src/compiler/compile/utils/flatten_reference.ts @@ -4,7 +4,6 @@ export default function flatten_reference(node: Node) { if (node.type === 'Expression') throw new Error('bad'); const nodes = []; const parts = []; - const prop_end = node.end; while (node.type === 'MemberExpression') { nodes.unshift(node.property); @@ -16,7 +15,6 @@ export default function flatten_reference(node: Node) { node = node.object; } - const prop_start = node.end; const name = node.type === 'Identifier' ? node.name : node.type === 'ThisExpression' ? 'this' : null; @@ -27,5 +25,5 @@ export default function flatten_reference(node: Node) { parts.unshift(name); } - return { name, nodes, parts, keypath: `${name}[✂${prop_start}-${prop_end}✂]` }; + return { name, nodes, parts }; } diff --git a/src/compiler/compile/utils/snip.ts b/src/compiler/compile/utils/snip.ts index 979f1fdc8948..7a2e12f8e5e7 100644 --- a/src/compiler/compile/utils/snip.ts +++ b/src/compiler/compile/utils/snip.ts @@ -1,3 +1,4 @@ export function snip(expression) { + throw new Error(`bad`); return `[✂${expression.node.start}-${expression.node.end}✂]`; } \ No newline at end of file diff --git a/test/runtime/samples/_/main.svelte b/test/runtime/samples/_/main.svelte index efe5048cbcd5..22b3c84db099 100644 --- a/test/runtime/samples/_/main.svelte +++ b/test/runtime/samples/_/main.svelte @@ -1 +1,5 @@ -

Hello world!

\ No newline at end of file + + +

Hello {name}!

\ No newline at end of file From 50280232e8e79a5400c7d2415fc6d32b6f96fef0 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Wed, 11 Sep 2019 18:30:18 -0400 Subject: [PATCH 07/93] props --- src/compiler/compile/Component.ts | 257 +++-------- .../compile/nodes/shared/Expression.ts | 413 +++++++++--------- src/compiler/compile/render_dom/index.ts | 4 +- .../compile/render_dom/wrappers/DebugTag.ts | 72 +-- .../compile/render_dom/wrappers/EachBlock.ts | 3 +- .../render_dom/wrappers/MustacheTag.ts | 2 +- .../render_dom/wrappers/RawMustacheTag.ts | 2 +- .../compile/render_dom/wrappers/shared/Tag.ts | 3 +- src/compiler/compile/utils/invalidate.ts | 99 ++--- src/compiler/utils/indentation.ts | 57 --- test/runtime/samples/_/main.svelte | 2 +- 11 files changed, 364 insertions(+), 550 deletions(-) delete mode 100644 src/compiler/utils/indentation.ts diff --git a/src/compiler/compile/Component.ts b/src/compiler/compile/Component.ts index 2edc2d6cfcc2..039309cd2837 100644 --- a/src/compiler/compile/Component.ts +++ b/src/compiler/compile/Component.ts @@ -1,4 +1,3 @@ -import MagicString from 'magic-string'; // @ts-ignore import { walk, childKeys } from 'estree-walker'; import { getLocator } from 'locate-character'; @@ -23,14 +22,13 @@ import flatten_reference from './utils/flatten_reference'; import is_reference from 'is-reference'; import TemplateScope from './nodes/shared/TemplateScope'; import fuzzymatch from '../utils/fuzzymatch'; -import { remove_indentation, add_indentation } from '../utils/indentation'; import get_object from './utils/get_object'; import unwrap_parens from './utils/unwrap_parens'; 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'; +import { print, x } from 'code-red'; interface ComponentOptions { namespace?: string; @@ -48,37 +46,13 @@ childKeys.Attribute = ['value']; childKeys.ExportNamedDeclaration = ['declaration', 'specifiers']; function remove_node( - code: MagicString, - start: number, - end: number, body: Node, node: Node ) { const i = body.indexOf(node); if (i === -1) throw new Error('node not in list'); - let a; - let b; - - if (body.length === 1) { - // remove everything, leave {} - a = start; - b = end; - } else if (i === 0) { - // remove everything before second node, including comments - a = start; - while (/\s/.test(code.original[a])) a += 1; - - b = body[i].end; - while (/[\s,]/.test(code.original[b])) b += 1; - } else { - // remove the end of the previous node to the end of this one - a = body[i - 1].end; - b = node.end; - } - - code.remove(a, b); - return; + body.splice(i, 1); } export default class Component { @@ -89,7 +63,6 @@ export default class Component { ast: Ast; source: string; - code: MagicString; name: Identifier; compile_options: CompileOptions; fragment: Fragment; @@ -173,8 +146,6 @@ export default class Component { : compile_options.filename); this.locate = getLocator(this.source); - this.code = new MagicString(source); - // styles this.stylesheet = new Stylesheet( source, @@ -261,15 +232,6 @@ export default class Component { } } - add_sourcemap_locations(node: Node) { - walk(node, { - enter: (node: Node) => { - this.code.addSourcemapLocation(node.start); - this.code.addSourcemapLocation(node.end); - }, - }); - } - alias(name: string) { if (!this.aliases.has(name)) { this.aliases.set(name, this.get_unique_name(name)); @@ -502,21 +464,20 @@ export default class Component { } extract_imports(content) { - const { code } = this; - content.body.forEach(node => { if (node.type === 'ImportDeclaration') { // imports need to be hoisted out of the IIFE - remove_node(code, content.start, content.end, content.body, node); + remove_node(content.body, node); this.imports.push(node); } }); } extract_exports(content) { - const { code } = this; + let i = content.body.length; + while (i--) { + const node = content.body[i]; - content.body.forEach(node => { if (node.type === 'ExportDefaultDeclaration') { this.error(node, { code: `default-export`, @@ -546,21 +507,20 @@ export default class Component { variable.export_name = name; } - code.remove(node.start, node.declaration.start); + content.body[i] = node.declaration; } else { - remove_node(code, content.start, content.end, content.body, node); node.specifiers.forEach(specifier => { const variable = this.var_lookup.get(specifier.local.name); if (variable) { variable.export_name = specifier.exported.name; - } else { - // TODO what happens with `export { Math }` or some other global? } }); + + content.body.splice(i, 1); } } - }); + } } extract_javascript(script) { @@ -573,35 +533,37 @@ export default class Component { return true; }); + return nodes_to_include; + if (nodes_to_include.length === 0) return null; let a = script.content.start; while (/\s/.test(this.source[a])) a += 1; - let b = a; + // let b = a; - let result = ''; + // let result = ''; - script.content.body.forEach(node => { - if ( - this.hoistable_nodes.has(node) || - this.reactive_declaration_nodes.has(node) - ) { - if (a !== b) result += `[✂${a}-${b}✂]`; - a = node.end; - } + // script.content.body.forEach(node => { + // if ( + // this.hoistable_nodes.has(node) || + // this.reactive_declaration_nodes.has(node) + // ) { + // if (a !== b) result += `[✂${a}-${b}✂]`; + // a = node.end; + // } - b = node.end; - }); + // b = node.end; + // }); // while (/\s/.test(this.source[a - 1])) a -= 1; - b = script.content.end; - while (/\s/.test(this.source[b - 1])) b -= 1; + // b = script.content.end; + // while (/\s/.test(this.source[b - 1])) b -= 1; - if (a < b) result += `[✂${a}-${b}✂]`; + // if (a < b) result += `[✂${a}-${b}✂]`; - return result || null; + // return result || null; } walk_module_js() { @@ -620,8 +582,6 @@ export default class Component { }, }); - this.add_sourcemap_locations(script.content); - const { scope, globals } = create_scopes(script.content); this.module_scope = scope; @@ -657,7 +617,6 @@ export default class Component { this.extract_imports(script.content); this.extract_exports(script.content); - remove_indentation(this.code, script.content); this.module_javascript = this.extract_javascript(script); } @@ -665,8 +624,6 @@ export default class Component { const script = this.ast.instance; if (!script) return; - this.add_sourcemap_locations(script.content); - // inject vars for reactive declarations script.content.body.forEach(node => { if (node.type !== 'LabeledStatement') return; @@ -893,18 +850,16 @@ export default class Component { .join(', '); } - rewrite_props(get_insert: (variable: Var) => string) { + rewrite_props(_get_insert: (variable: Var) => string) { + // TODO + const component = this; - const { code, instance_scope, instance_scope_map: map } = this; + const { instance_scope, instance_scope_map: map } = this; let scope = instance_scope; - const coalesced_declarations = []; - let current_group; - walk(this.ast.instance.content, { - enter(node, parent) { + enter(node) { if (/Function/.test(node.type)) { - current_group = null; return this.skip(); } @@ -914,16 +869,15 @@ export default class Component { if (node.type === 'VariableDeclaration') { if (node.kind === 'var' || scope === instance_scope) { - node.declarations.forEach((declarator, i) => { - const next = node.declarations[i + 1]; + node.declarations.forEach(declarator => { + // const next = node.declarations[i + 1]; if (declarator.id.type !== 'Identifier') { - const inserts = []; - extract_names(declarator.id).forEach(name => { const variable = component.var_lookup.get(name); if (variable.export_name) { + // TODO is this still true post-#3539? component.error(declarator, { code: 'destructured-prop', message: `Cannot declare props in destructured declaration`, @@ -931,22 +885,10 @@ export default class Component { } if (variable.subscribable) { - inserts.push(get_insert(variable)); + // TODO } }); - if (inserts.length > 0) { - if (next) { - code.overwrite( - declarator.end, - next.start, - `; ${inserts.join('; ')}; ${node.kind} ` - ); - } else { - code.appendLeft(declarator.end, `; ${inserts.join('; ')}`); - } - } - return; } @@ -954,112 +896,43 @@ export default class Component { const variable = component.var_lookup.get(name); if (variable.export_name) { - if (current_group && current_group.kind !== node.kind) { - current_group = null; - } - - const insert = variable.subscribable - ? get_insert(variable) - : null; - - if (!current_group || (current_group.insert && insert)) { - current_group = { - kind: node.kind, - declarators: [declarator], - insert, - }; - coalesced_declarations.push(current_group); - } else if (insert) { - current_group.insert = insert; - current_group.declarators.push(declarator); - } else { - current_group.declarators.push(declarator); - } - - if ( - variable.writable && - variable.name !== variable.export_name - ) { - code.prependRight( - declarator.id.start, - `${variable.export_name}: ` - ); - } - - if (next) { - const next_variable = component.var_lookup.get(next.id.name); - const new_declaration = - !next_variable.export_name || - (current_group.insert && next_variable.subscribable); - - if (new_declaration) { - code.overwrite( - declarator.end, - next.start, - ` ${node.kind} ` - ); - } - } - } else { - current_group = null; - - if (variable.subscribable) { - const insert = get_insert(variable); - - if (next) { - code.overwrite( - declarator.end, - next.start, - `; ${insert}; ${node.kind} ` - ); - } else { - code.appendLeft(declarator.end, `; ${insert}`); - } - } + // const insert = variable.subscribable + // ? get_insert(variable) + // : null; + + declarator.id = { + type: 'ObjectPattern', + properties: [{ + type: 'Property', + method: false, + shorthand: true, + computed: false, + kind: 'init', + key: declarator.id, + value: { + type: 'AssignmentPattern', + left: declarator.id, + right: declarator.init + } + }] + }; + + declarator.init = x`$$props`; } }); } - } else { - if (node.type !== 'ExportNamedDeclaration') { - if (!parent || parent.type === 'Program') current_group = null; - } } }, - leave(node) { + leave(node, _parent, _key, index) { if (map.has(node)) { scope = scope.parent; } - }, - }); - - coalesced_declarations.forEach(group => { - const writable = group.kind === 'var' || group.kind === 'let'; - let c = 0; - let combining = false; - - group.declarators.forEach(declarator => { - const { id } = declarator; - - if (combining) { - code.overwrite(c, id.start, ', '); - } else { - if (writable) code.appendLeft(id.start, '{ '); - combining = true; + if (node.type === 'ExportNamedDeclaration' && node.declaration) { + _parent.body[index] = node.declaration; } - - c = declarator.end; - }); - - if (combining) { - const insert = group.insert ? `; ${group.insert}` : ''; - - const suffix = - `${writable ? ` } = $$props` : ``}${insert}` + - (code.original[c] === ';' ? `` : `;`); - code.appendLeft(c, suffix); - } + }, }); } @@ -1213,8 +1086,6 @@ export default class Component { variable.hoistable = true; hoistable_nodes.add(node); - remove_indentation(this.code, node); - const i = body.indexOf(node); body.splice(i, 1); this.fully_hoisted.push(node); @@ -1280,8 +1151,6 @@ export default class Component { }, }); - add_indentation(this.code, node.body, 2); - const expression = node.body.expression && unwrap_parens(node.body.expression); const declaration = expression && expression.left; diff --git a/src/compiler/compile/nodes/shared/Expression.ts b/src/compiler/compile/nodes/shared/Expression.ts index 87469309f999..50ff97ef9325 100644 --- a/src/compiler/compile/nodes/shared/Expression.ts +++ b/src/compiler/compile/nodes/shared/Expression.ts @@ -1,18 +1,18 @@ import Component from '../../Component'; import { walk } from 'estree-walker'; import is_reference from 'is-reference'; -import { b } from 'code-red'; +// 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 { globals } from '../../../utils/names'; import Wrapper from '../../render_dom/wrappers/shared/Wrapper'; import TemplateScope from './TemplateScope'; import get_object from '../../utils/get_object'; import Block from '../../render_dom/Block'; import { INode } from '../interfaces'; import is_dynamic from '../../render_dom/wrappers/shared/is_dynamic'; -import { invalidate } from '../../utils/invalidate'; +// import { invalidate } from '../../utils/invalidate'; const binary_operators: Record = { '**': 15, @@ -224,192 +224,189 @@ export default class Expression { } // TODO move this into a render-dom wrapper? - render(block?: Block) { - if (this.rendered) return this.rendered; - - const { - component, - declarations, - scope_map: map, - template_scope, - owner, - is_synthetic - } = this; - let scope = this.scope; - - const { code } = component; - - let function_expression; - - let dependencies: Set; - let contextual_dependencies: Set; - - // rewrite code as appropriate - walk(this.node, { - enter(node: any, parent: any, key: string) { - // don't manipulate shorthand props twice - if (key === 'value' && parent.shorthand) return; - - code.addSourcemapLocation(node.start); - code.addSourcemapLocation(node.end); - - if (map.has(node)) { - scope = map.get(node); - } - - if (is_reference(node, parent)) { - const { name, nodes } = flatten_reference(node); - - if (scope.has(name)) return; - if (globals.has(name) && !component.var_lookup.has(name)) return; - - if (function_expression) { - if (template_scope.names.has(name)) { - contextual_dependencies.add(name); - - template_scope.dependencies_for_name.get(name).forEach(dependency => { - dependencies.add(dependency); - }); - } else { - dependencies.add(name); - component.add_reference(name); // TODO is this redundant/misplaced? - } - } else if (!is_synthetic && is_contextual(component, template_scope, name)) { - code.prependRight(node.start, key === 'key' && parent.shorthand - ? `${name}: ctx.` - : 'ctx.'); - } - - if (node.type === 'MemberExpression') { - nodes.forEach(node => { - code.addSourcemapLocation(node.start); - code.addSourcemapLocation(node.end); - }); - } - - this.skip(); - } - - if (!function_expression) { - if (node.type === 'AssignmentExpression') { - // TODO should this be a warning/error? `

{foo = 1}

` - } - - if (node.type === 'FunctionExpression' || node.type === 'ArrowFunctionExpression') { - function_expression = node; - dependencies = new Set(); - contextual_dependencies = new Set(); - } - } - }, - - leave(node: Node, parent: Node) { - if (map.has(node)) scope = scope.parent; - - if (node === function_expression) { - const id = component.get_unique_name( - sanitize(get_function_name(node, owner)) - ); - - const args = contextual_dependencies.size > 0 - ? [`{ ${Array.from(contextual_dependencies).join(', ')} }`] - : []; - - let original_params; - - if (node.params.length > 0) { - original_params = code.slice(node.params[0].start, node.params[node.params.length - 1].end); - args.push(original_params); - } - - const body = code.slice(node.body.start, node.body.end).trim(); - - const fn = node.type === 'FunctionExpression' - ? b`${node.async ? 'async ' : ''}function${node.generator ? '*' : ''} ${id}(${args.join(', ')}) ${body}` - : b`const ${id} = ${node.async ? 'async ' : ''}(${args.join(', ')}) => ${body};`; - - if (dependencies.size === 0 && contextual_dependencies.size === 0) { - // we can hoist this out of the component completely - component.fully_hoisted.push(fn); - code.overwrite(node.start, node.end, id.name); - - component.add_var({ - name: id.name, - internal: true, - hoistable: true, - referenced: true - }); - } - - else if (contextual_dependencies.size === 0) { - // function can be hoisted inside the component init - component.partly_hoisted.push(fn); - code.overwrite(node.start, node.end, `ctx.${id}`); - - component.add_var({ - name: id.name, - internal: true, - referenced: true - }); - } - - else { - // we need a combo block/init recipe - component.partly_hoisted.push(fn); - code.overwrite(node.start, node.end, id.name); - - component.add_var({ - name: id.name, - internal: true, - referenced: true - }); - - declarations.push(b` - function ${id}(${original_params ? '...args' : ''}) { - return ctx.${id}(ctx${original_params ? ', ...args' : ''}); - } - `); - } - - if (parent && parent.method) { - code.prependRight(node.start, ': '); - } - - function_expression = null; - dependencies = null; - contextual_dependencies = null; - } - - if (node.type === 'AssignmentExpression' || node.type === 'UpdateExpression') { - const assignee = node.type === 'AssignmentExpression' ? node.left : node.argument; - - // normally (`a = 1`, `b.c = 2`), there'll be a single name - // (a or b). In destructuring cases (`[d, e] = [e, d]`) there - // may be more, in which case we need to tack the extra ones - // onto the initial function call - const names = new Set(extract_names(assignee)); - - const traced: Set = new Set(); - names.forEach(name => { - const dependencies = template_scope.dependencies_for_name.get(name); - if (dependencies) { - dependencies.forEach(name => traced.add(name)); - } else { - traced.add(name); - } - }); - - invalidate(component, scope, code, node, traced); - } - } - }); - - if (declarations.length > 0) { - block.maintain_context = true; - declarations.forEach(declaration => { - block.chunks.init.push(declaration); - }); - } + render(_block?: Block) { + // TODO + + // if (this.rendered) return this.rendered; + + // const { + // component, + // declarations, + // scope_map: map, + // template_scope, + // owner, + // is_synthetic + // } = this; + // let scope = this.scope; + + // let function_expression; + + // let dependencies: Set; + // let contextual_dependencies: Set; + + // // rewrite code as appropriate + // walk(this.node, { + // enter(node: any, parent: any, key: string) { + // // don't manipulate shorthand props twice + // if (key === 'value' && parent.shorthand) return; + + // if (map.has(node)) { + // scope = map.get(node); + // } + + // if (is_reference(node, parent)) { + // const { name, nodes } = flatten_reference(node); + + // if (scope.has(name)) return; + // if (globals.has(name) && !component.var_lookup.has(name)) return; + + // if (function_expression) { + // if (template_scope.names.has(name)) { + // contextual_dependencies.add(name); + + // template_scope.dependencies_for_name.get(name).forEach(dependency => { + // dependencies.add(dependency); + // }); + // } else { + // dependencies.add(name); + // component.add_reference(name); // TODO is this redundant/misplaced? + // } + // } else if (!is_synthetic && is_contextual(component, template_scope, name)) { + // code.prependRight(node.start, key === 'key' && parent.shorthand + // ? `${name}: ctx.` + // : 'ctx.'); + // } + + // if (node.type === 'MemberExpression') { + // nodes.forEach(node => { + // code.addSourcemapLocation(node.start); + // code.addSourcemapLocation(node.end); + // }); + // } + + // this.skip(); + // } + + // if (!function_expression) { + // if (node.type === 'AssignmentExpression') { + // // TODO should this be a warning/error? `

{foo = 1}

` + // } + + // if (node.type === 'FunctionExpression' || node.type === 'ArrowFunctionExpression') { + // function_expression = node; + // dependencies = new Set(); + // contextual_dependencies = new Set(); + // } + // } + // }, + + // leave(node: Node, parent: Node) { + // if (map.has(node)) scope = scope.parent; + + // if (node === function_expression) { + // const id = component.get_unique_name( + // sanitize(get_function_name(node, owner)) + // ); + + // const args = contextual_dependencies.size > 0 + // ? [`{ ${Array.from(contextual_dependencies).join(', ')} }`] + // : []; + + // let original_params; + + // if (node.params.length > 0) { + // original_params = code.slice(node.params[0].start, node.params[node.params.length - 1].end); + // args.push(original_params); + // } + + // const body = code.slice(node.body.start, node.body.end).trim(); + + // const fn = node.type === 'FunctionExpression' + // ? b`${node.async ? 'async ' : ''}function${node.generator ? '*' : ''} ${id}(${args.join(', ')}) ${body}` + // : b`const ${id} = ${node.async ? 'async ' : ''}(${args.join(', ')}) => ${body};`; + + // if (dependencies.size === 0 && contextual_dependencies.size === 0) { + // // we can hoist this out of the component completely + // component.fully_hoisted.push(fn); + // code.overwrite(node.start, node.end, id.name); + + // component.add_var({ + // name: id.name, + // internal: true, + // hoistable: true, + // referenced: true + // }); + // } + + // else if (contextual_dependencies.size === 0) { + // // function can be hoisted inside the component init + // component.partly_hoisted.push(fn); + // code.overwrite(node.start, node.end, `ctx.${id}`); + + // component.add_var({ + // name: id.name, + // internal: true, + // referenced: true + // }); + // } + + // else { + // // we need a combo block/init recipe + // component.partly_hoisted.push(fn); + // code.overwrite(node.start, node.end, id.name); + + // component.add_var({ + // name: id.name, + // internal: true, + // referenced: true + // }); + + // declarations.push(b` + // function ${id}(${original_params ? '...args' : ''}) { + // return ctx.${id}(ctx${original_params ? ', ...args' : ''}); + // } + // `); + // } + + // if (parent && parent.method) { + // code.prependRight(node.start, ': '); + // } + + // function_expression = null; + // dependencies = null; + // contextual_dependencies = null; + // } + + // if (node.type === 'AssignmentExpression' || node.type === 'UpdateExpression') { + // const assignee = node.type === 'AssignmentExpression' ? node.left : node.argument; + + // // normally (`a = 1`, `b.c = 2`), there'll be a single name + // // (a or b). In destructuring cases (`[d, e] = [e, d]`) there + // // may be more, in which case we need to tack the extra ones + // // onto the initial function call + // const names = new Set(extract_names(assignee)); + + // const traced: Set = new Set(); + // names.forEach(name => { + // const dependencies = template_scope.dependencies_for_name.get(name); + // if (dependencies) { + // dependencies.forEach(name => traced.add(name)); + // } else { + // traced.add(name); + // } + // }); + + // invalidate(component, scope, code, node, traced); + // } + // } + // }); + + // if (declarations.length > 0) { + // block.maintain_context = true; + // declarations.forEach(declaration => { + // block.chunks.init.push(declaration); + // }); + // } throw new Error(`bad`); @@ -417,29 +414,29 @@ export default class Expression { } } -function get_function_name(_node, parent) { - if (parent.type === 'EventHandler') { - return `${parent.name}_handler`; - } +// function get_function_name(_node, parent) { +// if (parent.type === 'EventHandler') { +// return `${parent.name}_handler`; +// } - if (parent.type === 'Action') { - return `${parent.name}_function`; - } +// if (parent.type === 'Action') { +// return `${parent.name}_function`; +// } - return 'func'; -} +// return 'func'; +// } -function is_contextual(component: Component, scope: TemplateScope, name: string) { - if (name === '$$props') return true; +// function is_contextual(component: Component, scope: TemplateScope, name: string) { +// if (name === '$$props') return true; - // if it's a name below root scope, it's contextual - if (!scope.is_top_level(name)) return true; +// // if it's a name below root scope, it's contextual +// if (!scope.is_top_level(name)) return true; - const variable = component.var_lookup.get(name); +// const variable = component.var_lookup.get(name); - // hoistables, module declarations, and imports are non-contextual - if (!variable || variable.hoistable) return false; +// // hoistables, module declarations, and imports are non-contextual +// if (!variable || variable.hoistable) return false; - // assume contextual - return true; -} +// // assume contextual +// return true; +// } diff --git a/src/compiler/compile/render_dom/index.ts b/src/compiler/compile/render_dom/index.ts index f514692bed68..d765dbc7d571 100644 --- a/src/compiler/compile/render_dom/index.ts +++ b/src/compiler/compile/render_dom/index.ts @@ -14,7 +14,7 @@ export default function dom( component: Component, options: CompileOptions ) { - const { name, code } = component; + const { name } = component; const renderer = new Renderer(component, options); const { block } = renderer; @@ -198,7 +198,7 @@ export default function dom( // onto the initial function call const names = new Set(extract_names(assignee)); - invalidate(component, scope, code, node, names); + invalidate(component, scope, node, names); } } }); diff --git a/src/compiler/compile/render_dom/wrappers/DebugTag.ts b/src/compiler/compile/render_dom/wrappers/DebugTag.ts index 6129637e2275..c7c0daf890f7 100644 --- a/src/compiler/compile/render_dom/wrappers/DebugTag.ts +++ b/src/compiler/compile/render_dom/wrappers/DebugTag.ts @@ -2,7 +2,7 @@ import Renderer from '../Renderer'; import Wrapper from './shared/Wrapper'; import Block from '../Block'; import DebugTag from '../../nodes/DebugTag'; -import add_to_set from '../../utils/add_to_set'; +// import add_to_set from '../../utils/add_to_set'; import { b } from 'code-red'; export default class DebugTagWrapper extends Wrapper { @@ -21,11 +21,11 @@ export default class DebugTagWrapper extends Wrapper { render(block: Block, _parent_node: string, _parent_nodes: string) { const { renderer } = this; - const { component } = renderer; + // const { component } = renderer; if (!renderer.options.dev) return; - const { var_lookup } = component; + // const { var_lookup } = component; if (this.node.expressions.length === 0) { // Debug all @@ -37,43 +37,45 @@ export default class DebugTagWrapper extends Wrapper { 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', { - storeName: true - }); - const log = `[✂${this.node.start + 1}-${this.node.start + 7}✂]`; + // TODO - const dependencies = new Set(); - this.node.expressions.forEach(expression => { - add_to_set(dependencies, expression.dependencies); - }); + // const { code } = component; + // code.overwrite(this.node.start + 1, this.node.start + 7, 'log', { + // storeName: true + // }); + // const log = `[✂${this.node.start + 1}-${this.node.start + 7}✂]`; + + // const dependencies = new Set(); + // this.node.expressions.forEach(expression => { + // add_to_set(dependencies, expression.dependencies); + // }); - const condition = Array.from(dependencies).map(d => `changed.${d}`).join(' || '); + // const condition = Array.from(dependencies).map(d => `changed.${d}`).join(' || '); - const ctx_identifiers = this.node.expressions - .filter(e => { - const looked_up_var = var_lookup.get(e.node.name); - return !(looked_up_var && looked_up_var.hoistable); - }) - .map(e => e.node.name) - .join(', '); - const logged_identifiers = this.node.expressions.map(e => e.node.name).join(', '); + // const ctx_identifiers = this.node.expressions + // .filter(e => { + // const looked_up_var = var_lookup.get(e.node.name); + // return !(looked_up_var && looked_up_var.hoistable); + // }) + // .map(e => e.node.name) + // .join(', '); + // const logged_identifiers = this.node.expressions.map(e => e.node.name).join(', '); - block.chunks.update.push(b` - if (${condition}) { - const { ${ctx_identifiers} } = ctx; - @_console.${log}({ ${logged_identifiers} }); - debugger; - } - `); + // block.chunks.update.push(b` + // if (${condition}) { + // const { ${ctx_identifiers} } = ctx; + // @_console.${log}({ ${logged_identifiers} }); + // debugger; + // } + // `); - block.chunks.create.push(b` - { - const { ${ctx_identifiers} } = ctx; - @_console.${log}({ ${logged_identifiers} }); - debugger; - } - `); + // block.chunks.create.push(b` + // { + // const { ${ctx_identifiers} } = ctx; + // @_console.${log}({ ${logged_identifiers} }); + // debugger; + // } + // `); } } } diff --git a/src/compiler/compile/render_dom/wrappers/EachBlock.ts b/src/compiler/compile/render_dom/wrappers/EachBlock.ts index 2ce1f11a4f5d..c29f9351327b 100644 --- a/src/compiler/compile/render_dom/wrappers/EachBlock.ts +++ b/src/compiler/compile/render_dom/wrappers/EachBlock.ts @@ -104,11 +104,12 @@ export default class EachBlockWrapper extends Wrapper { ? node.expression.node.elements.length : null; + // TODO // hack the sourcemap, so that if data is missing the bug // is easy to find let c = this.node.start + 2; while (renderer.component.source[c] !== 'e') c += 1; - renderer.component.code.overwrite(c, c + 4, 'length'); + // renderer.component.code.overwrite(c, c + 4, 'length'); const each_block_value = renderer.component.get_unique_name(`${this.var}_value`); const iterations = block.get_unique_name(`${this.var}_blocks`); diff --git a/src/compiler/compile/render_dom/wrappers/MustacheTag.ts b/src/compiler/compile/render_dom/wrappers/MustacheTag.ts index c3134a9be412..99413ee3148d 100644 --- a/src/compiler/compile/render_dom/wrappers/MustacheTag.ts +++ b/src/compiler/compile/render_dom/wrappers/MustacheTag.ts @@ -18,7 +18,7 @@ export default class MustacheTagWrapper extends Tag { render(block: Block, parent_node: string, parent_nodes: string) { const { init } = this.rename_this_method( block, - value => `@set_data(${this.var}, ${value});` + value => x`@set_data(${this.var}, ${value});` ); block.add_element( diff --git a/src/compiler/compile/render_dom/wrappers/RawMustacheTag.ts b/src/compiler/compile/render_dom/wrappers/RawMustacheTag.ts index b2c0fc86cf20..3a05a3c1d32f 100644 --- a/src/compiler/compile/render_dom/wrappers/RawMustacheTag.ts +++ b/src/compiler/compile/render_dom/wrappers/RawMustacheTag.ts @@ -46,7 +46,7 @@ export default class RawMustacheTagWrapper extends Tag { const { init } = this.rename_this_method( block, - content => `${html_tag}.p(${content});` + content => x`${html_tag}.p(${content});` ); const update_anchor = in_head ? 'null' : needs_anchor ? html_anchor : this.next ? this.next.var : 'null'; diff --git a/src/compiler/compile/render_dom/wrappers/shared/Tag.ts b/src/compiler/compile/render_dom/wrappers/shared/Tag.ts index b67617965a88..6ee900f2e99b 100644 --- a/src/compiler/compile/render_dom/wrappers/shared/Tag.ts +++ b/src/compiler/compile/render_dom/wrappers/shared/Tag.ts @@ -4,6 +4,7 @@ import Renderer from '../../Renderer'; import Block from '../../Block'; import MustacheTag from '../../../nodes/MustacheTag'; import RawMustacheTag from '../../../nodes/RawMustacheTag'; +import { Node } from '../../../../interfaces'; export default class Tag extends Wrapper { node: MustacheTag | RawMustacheTag; @@ -17,7 +18,7 @@ export default class Tag extends Wrapper { rename_this_method( block: Block, - update: ((value: string) => string) + update: ((value: Node) => Node) ) { const dependencies = this.node.expression.dynamic_dependencies(); const snippet = this.node.expression.node; diff --git a/src/compiler/compile/utils/invalidate.ts b/src/compiler/compile/utils/invalidate.ts index 55f5d499770f..2eae0766d724 100644 --- a/src/compiler/compile/utils/invalidate.ts +++ b/src/compiler/compile/utils/invalidate.ts @@ -1,66 +1,67 @@ import Component from '../Component'; -import MagicString from 'magic-string'; import { Node } from '../../interfaces'; -import { nodes_match } from '../../utils/nodes_match'; +// import { nodes_match } from '../../utils/nodes_match'; import { Scope } from './scope'; -export function invalidate(component: Component, scope: Scope, code: MagicString, node: Node, names: Set) { - const [head, ...tail] = Array.from(names).filter(name => { - const owner = scope.find_owner(name); - if (owner && owner !== component.instance_scope) return false; +export function invalidate(_component: Component, _scope: Scope, _node: Node, _names: Set) { + // const [head, ...tail] = Array.from(names).filter(name => { + // const owner = scope.find_owner(name); + // if (owner && owner !== component.instance_scope) return false; - const variable = component.var_lookup.get(name); + // const variable = component.var_lookup.get(name); - return variable && ( - !variable.hoistable && - !variable.global && - !variable.module && - ( - variable.referenced || - variable.is_reactive_dependency || - variable.export_name || - variable.name[0] === '$' - ) - ); - }); + // return variable && ( + // !variable.hoistable && + // !variable.global && + // !variable.module && + // ( + // variable.referenced || + // variable.is_reactive_dependency || + // variable.export_name || + // variable.name[0] === '$' + // ) + // ); + // }); - if (head) { - component.has_reactive_assignments = true; + // TODO - if (node.operator === '=' && nodes_match(node.left, node.right) && tail.length === 0) { - code.overwrite(node.start, node.end, component.invalidate(head)); - } else { - let suffix = ')'; + // if (head) { + // component.has_reactive_assignments = true; - if (head[0] === '$') { - code.prependRight(node.start, `${component.helper('set_store_value')}(${head.slice(1)}, `); - } else { - let prefix = `$$invalidate`; + // if (node.operator === '=' && nodes_match(node.left, node.right) && tail.length === 0) { + // code.overwrite(node.start, node.end, component.invalidate(head)); + // } else { + // let suffix = ')'; - const variable = component.var_lookup.get(head); - if (variable.subscribable && variable.reassigned) { - prefix = `$$subscribe_${head}($$invalidate`; - suffix += `)`; - } + // if (head[0] === '$') { + // code.prependRight(node.start, `${component.helper('set_store_value')}(${head.slice(1)}, `); + // } else { + // let prefix = `$$invalidate`; - code.prependRight(node.start, `${prefix}('${head}', `); - } + // const variable = component.var_lookup.get(head); + // if (variable.subscribable && variable.reassigned) { + // prefix = `$$subscribe_${head}($$invalidate`; + // suffix += `)`; + // } - const extra_args = tail.map(name => component.invalidate(name)); + // code.prependRight(node.start, `${prefix}('${head}', `); + // } - const pass_value = ( - extra_args.length > 0 || - (node.type === 'AssignmentExpression' && node.left.type !== 'Identifier') || - (node.type === 'UpdateExpression' && !node.prefix) - ); + // const extra_args = tail.map(name => component.invalidate(name)); - if (pass_value) { - extra_args.unshift(head); - } + // const pass_value = ( + // extra_args.length > 0 || + // (node.type === 'AssignmentExpression' && node.left.type !== 'Identifier') || + // (node.type === 'UpdateExpression' && !node.prefix) + // ); - suffix = `${extra_args.map(arg => `, ${arg}`).join('')}${suffix}`; + // if (pass_value) { + // extra_args.unshift(head); + // } - code.appendLeft(node.end, suffix); - } - } + // suffix = `${extra_args.map(arg => `, ${arg}`).join('')}${suffix}`; + + // code.appendLeft(node.end, suffix); + // } + // } } \ No newline at end of file diff --git a/src/compiler/utils/indentation.ts b/src/compiler/utils/indentation.ts deleted file mode 100644 index 54ededc37d99..000000000000 --- a/src/compiler/utils/indentation.ts +++ /dev/null @@ -1,57 +0,0 @@ -import MagicString from 'magic-string'; -import { Node } from '../interfaces'; -import { walk } from 'estree-walker'; -import repeat from './repeat'; - -export function remove_indentation(code: MagicString, node: Node) { - const indent = code.getIndentString(); - const pattern = new RegExp(`^${indent}`, 'gm'); - - const excluded = []; - - walk(node, { - enter(node) { - if (node.type === 'TemplateElement') { - excluded.push(node); - } - } - }); - - const str = code.original.slice(node.start, node.end); - - let match; - while (match = pattern.exec(str)) { - const index = node.start + match.index; - while (excluded[0] && excluded[0].end < index) excluded.shift(); - if (excluded[0] && excluded[0].start < index) continue; - - code.remove(index, index + indent.length); - } -} - -export function add_indentation(code: MagicString, node: Node, levels = 1) { - const base_indent = code.getIndentString(); - const indent = repeat(base_indent, levels); - const pattern = /\n/gm; - - const excluded = []; - - walk(node, { - enter(node) { - if (node.type === 'TemplateElement') { - excluded.push(node); - } - } - }); - - const str = code.original.slice(node.start, node.end); - - let match; - while (match = pattern.exec(str)) { - const index = node.start + match.index; - while (excluded[0] && excluded[0].end < index) excluded.shift(); - if (excluded[0] && excluded[0].start < index) continue; - - code.appendLeft(index + 1, indent); - } -} diff --git a/test/runtime/samples/_/main.svelte b/test/runtime/samples/_/main.svelte index 22b3c84db099..41e3ddf043a0 100644 --- a/test/runtime/samples/_/main.svelte +++ b/test/runtime/samples/_/main.svelte @@ -1,5 +1,5 @@

Hello {name}!

\ No newline at end of file From 9d947292a135cf259a6570d3d6205eeb6e42f9d5 Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Wed, 11 Sep 2019 20:05:32 -0400 Subject: [PATCH 08/93] bit more progress --- src/compiler/compile/nodes/EventHandler.ts | 2 +- .../compile/nodes/shared/Expression.ts | 398 +++++++++--------- src/compiler/compile/render_dom/index.ts | 8 +- .../compile/render_dom/wrappers/AwaitBlock.ts | 2 +- .../compile/render_dom/wrappers/EachBlock.ts | 4 +- .../render_dom/wrappers/Element/Attribute.ts | 9 +- .../render_dom/wrappers/Element/Binding.ts | 2 +- .../wrappers/Element/StyleAttribute.ts | 4 +- .../render_dom/wrappers/Element/index.ts | 12 +- .../wrappers/InlineComponent/index.ts | 6 +- .../compile/render_dom/wrappers/Title.ts | 4 +- .../compile/render_dom/wrappers/shared/Tag.ts | 4 +- .../render_dom/wrappers/shared/add_actions.ts | 2 +- test/runtime/samples/_/_config.js | 5 +- test/runtime/samples/_/main.svelte | 5 +- 15 files changed, 229 insertions(+), 238 deletions(-) diff --git a/src/compiler/compile/nodes/EventHandler.ts b/src/compiler/compile/nodes/EventHandler.ts index 688f7e85ceae..a1adfd345bb2 100644 --- a/src/compiler/compile/nodes/EventHandler.ts +++ b/src/compiler/compile/nodes/EventHandler.ts @@ -63,7 +63,7 @@ export default class EventHandler extends Node { // TODO move this? it is specific to render-dom render(block: Block) { - if (this.expression) return this.expression.render(block); + if (this.expression) this.expression.manipulate(block); // this.component.add_reference(this.handler_name); return `ctx.${this.handler_name}`; diff --git a/src/compiler/compile/nodes/shared/Expression.ts b/src/compiler/compile/nodes/shared/Expression.ts index 50ff97ef9325..ea133e322e29 100644 --- a/src/compiler/compile/nodes/shared/Expression.ts +++ b/src/compiler/compile/nodes/shared/Expression.ts @@ -1,7 +1,6 @@ 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'; @@ -12,7 +11,8 @@ import get_object from '../../utils/get_object'; import Block from '../../render_dom/Block'; import { INode } from '../interfaces'; import is_dynamic from '../../render_dom/wrappers/shared/is_dynamic'; -// import { invalidate } from '../../utils/invalidate'; +import { x } from 'code-red'; +import { invalidate } from '../../utils/invalidate'; const binary_operators: Record = { '**': 15, @@ -82,8 +82,6 @@ export default class Expression { declarations: Node[] = []; uses_context = false; - rendered: string; - // todo: owner type constructor(component: Component, owner: Owner, template_scope: TemplateScope, info, lazy?: boolean) { // TODO revert to direct property access in prod? @@ -224,193 +222,191 @@ export default class Expression { } // TODO move this into a render-dom wrapper? - render(_block?: Block) { - // TODO - - // if (this.rendered) return this.rendered; - - // const { - // component, - // declarations, - // scope_map: map, - // template_scope, - // owner, - // is_synthetic - // } = this; - // let scope = this.scope; - - // let function_expression; - - // let dependencies: Set; - // let contextual_dependencies: Set; - - // // rewrite code as appropriate - // walk(this.node, { - // enter(node: any, parent: any, key: string) { - // // don't manipulate shorthand props twice - // if (key === 'value' && parent.shorthand) return; - - // if (map.has(node)) { - // scope = map.get(node); - // } - - // if (is_reference(node, parent)) { - // const { name, nodes } = flatten_reference(node); - - // if (scope.has(name)) return; - // if (globals.has(name) && !component.var_lookup.has(name)) return; - - // if (function_expression) { - // if (template_scope.names.has(name)) { - // contextual_dependencies.add(name); - - // template_scope.dependencies_for_name.get(name).forEach(dependency => { - // dependencies.add(dependency); - // }); - // } else { - // dependencies.add(name); - // component.add_reference(name); // TODO is this redundant/misplaced? - // } - // } else if (!is_synthetic && is_contextual(component, template_scope, name)) { - // code.prependRight(node.start, key === 'key' && parent.shorthand - // ? `${name}: ctx.` - // : 'ctx.'); - // } - - // if (node.type === 'MemberExpression') { - // nodes.forEach(node => { - // code.addSourcemapLocation(node.start); - // code.addSourcemapLocation(node.end); - // }); - // } - - // this.skip(); - // } - - // if (!function_expression) { - // if (node.type === 'AssignmentExpression') { - // // TODO should this be a warning/error? `

{foo = 1}

` - // } - - // if (node.type === 'FunctionExpression' || node.type === 'ArrowFunctionExpression') { - // function_expression = node; - // dependencies = new Set(); - // contextual_dependencies = new Set(); - // } - // } - // }, - - // leave(node: Node, parent: Node) { - // if (map.has(node)) scope = scope.parent; - - // if (node === function_expression) { - // const id = component.get_unique_name( - // sanitize(get_function_name(node, owner)) - // ); - - // const args = contextual_dependencies.size > 0 - // ? [`{ ${Array.from(contextual_dependencies).join(', ')} }`] - // : []; - - // let original_params; - - // if (node.params.length > 0) { - // original_params = code.slice(node.params[0].start, node.params[node.params.length - 1].end); - // args.push(original_params); - // } - - // const body = code.slice(node.body.start, node.body.end).trim(); - - // const fn = node.type === 'FunctionExpression' - // ? b`${node.async ? 'async ' : ''}function${node.generator ? '*' : ''} ${id}(${args.join(', ')}) ${body}` - // : b`const ${id} = ${node.async ? 'async ' : ''}(${args.join(', ')}) => ${body};`; - - // if (dependencies.size === 0 && contextual_dependencies.size === 0) { - // // we can hoist this out of the component completely - // component.fully_hoisted.push(fn); - // code.overwrite(node.start, node.end, id.name); - - // component.add_var({ - // name: id.name, - // internal: true, - // hoistable: true, - // referenced: true - // }); - // } - - // else if (contextual_dependencies.size === 0) { - // // function can be hoisted inside the component init - // component.partly_hoisted.push(fn); - // code.overwrite(node.start, node.end, `ctx.${id}`); - - // component.add_var({ - // name: id.name, - // internal: true, - // referenced: true - // }); - // } - - // else { - // // we need a combo block/init recipe - // component.partly_hoisted.push(fn); - // code.overwrite(node.start, node.end, id.name); - - // component.add_var({ - // name: id.name, - // internal: true, - // referenced: true - // }); - - // declarations.push(b` - // function ${id}(${original_params ? '...args' : ''}) { - // return ctx.${id}(ctx${original_params ? ', ...args' : ''}); - // } - // `); - // } - - // if (parent && parent.method) { - // code.prependRight(node.start, ': '); - // } - - // function_expression = null; - // dependencies = null; - // contextual_dependencies = null; - // } - - // if (node.type === 'AssignmentExpression' || node.type === 'UpdateExpression') { - // const assignee = node.type === 'AssignmentExpression' ? node.left : node.argument; - - // // normally (`a = 1`, `b.c = 2`), there'll be a single name - // // (a or b). In destructuring cases (`[d, e] = [e, d]`) there - // // may be more, in which case we need to tack the extra ones - // // onto the initial function call - // const names = new Set(extract_names(assignee)); - - // const traced: Set = new Set(); - // names.forEach(name => { - // const dependencies = template_scope.dependencies_for_name.get(name); - // if (dependencies) { - // dependencies.forEach(name => traced.add(name)); - // } else { - // traced.add(name); - // } - // }); - - // invalidate(component, scope, code, node, traced); - // } - // } - // }); - - // if (declarations.length > 0) { - // block.maintain_context = true; - // declarations.forEach(declaration => { - // block.chunks.init.push(declaration); - // }); - // } - - throw new Error(`bad`); - - return this.rendered = `[✂${this.node.start}-${this.node.end}✂]`; + manipulate(block?: Block) { + const { + component, + declarations, + scope_map: map, + template_scope, + is_synthetic + } = this; + let scope = this.scope; + + let function_expression; + + let dependencies: Set; + let contextual_dependencies: Set; + + // TODO this feels a lil messy + let return_value = this.node; + + walk(this.node, { + enter(node: any, parent: any, key: string, index: number) { + // don't manipulate shorthand props twice + if (key === 'value' && parent.shorthand) return; + + if (map.has(node)) { + scope = map.get(node); + } + + if (is_reference(node, parent)) { + const { name } = flatten_reference(node); + + if (scope.has(name)) return; + if (globals.has(name) && !component.var_lookup.has(name)) return; + + if (function_expression) { + if (template_scope.names.has(name)) { + contextual_dependencies.add(name); + + template_scope.dependencies_for_name.get(name).forEach(dependency => { + dependencies.add(dependency); + }); + } else { + dependencies.add(name); + component.add_reference(name); // TODO is this redundant/misplaced? + } + } else if (!is_synthetic && is_contextual(component, template_scope, name)) { + const replaced = x`ctx.${node}`; + + if (parent) { + if (index !== null) { + // TODO can this happen? + parent[key][index] = replaced; + } else { + parent[key] = replaced; + } + } else { + return_value = replaced; + } + } + + this.skip(); + } + + if (!function_expression) { + if (node.type === 'AssignmentExpression') { + // TODO should this be a warning/error? `

{foo = 1}

` + } + + if (node.type === 'FunctionExpression' || node.type === 'ArrowFunctionExpression') { + function_expression = node; + dependencies = new Set(); + contextual_dependencies = new Set(); + } + } + }, + + leave(node: Node, _parent: Node) { + if (map.has(node)) scope = scope.parent; + + if (node === function_expression) { + // const id = component.get_unique_name( + // sanitize(get_function_name(node, owner)) + // ); + + // const args = contextual_dependencies.size > 0 + // ? [`{ ${Array.from(contextual_dependencies).join(', ')} }`] + // : []; + + // let original_params; + + // if (node.params.length > 0) { + // original_params = code.slice(node.params[0].start, node.params[node.params.length - 1].end); + // args.push(original_params); + // } + + // const body = code.slice(node.body.start, node.body.end).trim(); + + // const fn = node.type === 'FunctionExpression' + // ? b`${node.async ? 'async ' : ''}function${node.generator ? '*' : ''} ${id}(${args.join(', ')}) ${body}` + // : b`const ${id} = ${node.async ? 'async ' : ''}(${args.join(', ')}) => ${body};`; + + // if (dependencies.size === 0 && contextual_dependencies.size === 0) { + // // we can hoist this out of the component completely + // component.fully_hoisted.push(fn); + + // // code.overwrite(node.start, node.end, id.name); + + // component.add_var({ + // name: id.name, + // internal: true, + // hoistable: true, + // referenced: true + // }); + // } + + // else if (contextual_dependencies.size === 0) { + // // function can be hoisted inside the component init + // component.partly_hoisted.push(fn); + // code.overwrite(node.start, node.end, `ctx.${id}`); + + // component.add_var({ + // name: id.name, + // internal: true, + // referenced: true + // }); + // } + + // else { + // // we need a combo block/init recipe + // component.partly_hoisted.push(fn); + // code.overwrite(node.start, node.end, id.name); + + // component.add_var({ + // name: id.name, + // internal: true, + // referenced: true + // }); + + // declarations.push(b` + // function ${id}(${original_params ? '...args' : ''}) { + // return ctx.${id}(ctx${original_params ? ', ...args' : ''}); + // } + // `); + // } + + // if (parent && parent.method) { + // code.prependRight(node.start, ': '); + // } + + function_expression = null; + dependencies = null; + contextual_dependencies = null; + } + + if (node.type === 'AssignmentExpression' || node.type === 'UpdateExpression') { + const assignee = node.type === 'AssignmentExpression' ? node.left : node.argument; + + // normally (`a = 1`, `b.c = 2`), there'll be a single name + // (a or b). In destructuring cases (`[d, e] = [e, d]`) there + // may be more, in which case we need to tack the extra ones + // onto the initial function call + const names = new Set(extract_names(assignee)); + + const traced: Set = new Set(); + names.forEach(name => { + const dependencies = template_scope.dependencies_for_name.get(name); + if (dependencies) { + dependencies.forEach(name => traced.add(name)); + } else { + traced.add(name); + } + }); + + invalidate(component, scope, node, traced); + } + } + }); + + if (declarations.length > 0) { + block.maintain_context = true; + declarations.forEach(declaration => { + block.chunks.init.push(declaration); + }); + } + + return return_value; } } @@ -426,17 +422,17 @@ export default class Expression { // return 'func'; // } -// function is_contextual(component: Component, scope: TemplateScope, name: string) { -// if (name === '$$props') return true; +function is_contextual(component: Component, scope: TemplateScope, name: string) { + if (name === '$$props') return true; -// // if it's a name below root scope, it's contextual -// if (!scope.is_top_level(name)) return true; + // if it's a name below root scope, it's contextual + if (!scope.is_top_level(name)) return true; -// const variable = component.var_lookup.get(name); + const variable = component.var_lookup.get(name); -// // hoistables, module declarations, and imports are non-contextual -// if (!variable || variable.hoistable) return false; + // hoistables, module declarations, and imports are non-contextual + if (!variable || variable.hoistable) return false; -// // assume contextual -// return true; -// } + // assume contextual + return true; +} diff --git a/src/compiler/compile/render_dom/index.ts b/src/compiler/compile/render_dom/index.ts index d765dbc7d571..31469be6eb19 100644 --- a/src/compiler/compile/render_dom/index.ts +++ b/src/compiler/compile/render_dom/index.ts @@ -77,12 +77,12 @@ export default function dom( const set = (uses_props || writable_props.length > 0 || component.slots.size > 0) ? x` ${$$props} => { - ${uses_props && component.invalidate('$$props', `$$props = @assign(@assign({}, $$props), $$new_props)`)} + ${uses_props && component.invalidate('$$props', b`$$props = @assign(@assign({}, $$props), $$new_props)`)} ${writable_props.map(prop => - `if ('${prop.export_name}' in ${$$props}) ${component.invalidate(prop.name, `${prop.name} = ${$$props}.${prop.export_name}`)};` + b`if ('${prop.export_name}' in ${$$props}) ${component.invalidate(prop.name, `${prop.name} = ${$$props}.${prop.export_name}`)};` )} ${component.slots.size > 0 && - `if ('$$scope' in ${$$props}) ${component.invalidate('$$scope', `$$scope = ${$$props}.$$scope`)};`} + b`if ('$$scope' in ${$$props}) ${component.invalidate('$$scope', `$$scope = ${$$props}.$$scope`)};`} } ` : null; @@ -370,7 +370,7 @@ export default function dom( ${component.partly_hoisted.length > 0 && component.partly_hoisted.join('\n\n')} - ${set && `$$self.$set = ${set};`} + ${set && b`$$self.$set = ${set};`} ${capture_state && `$$self.$capture_state = ${capture_state};`} diff --git a/src/compiler/compile/render_dom/wrappers/AwaitBlock.ts b/src/compiler/compile/render_dom/wrappers/AwaitBlock.ts index 979bb553ce62..9eceea691d0d 100644 --- a/src/compiler/compile/render_dom/wrappers/AwaitBlock.ts +++ b/src/compiler/compile/render_dom/wrappers/AwaitBlock.ts @@ -127,7 +127,7 @@ export default class AwaitBlockWrapper extends Wrapper { const anchor = this.get_or_create_anchor(block, parent_node, parent_nodes); const update_mount_node = this.get_update_mount_node(anchor); - const snippet = this.node.expression.render(block); + const snippet = this.node.expression.manipulate(block); const info = block.get_unique_name(`info`); const promise = block.get_unique_name(`promise`); diff --git a/src/compiler/compile/render_dom/wrappers/EachBlock.ts b/src/compiler/compile/render_dom/wrappers/EachBlock.ts index c29f9351327b..7387ab27b0ff 100644 --- a/src/compiler/compile/render_dom/wrappers/EachBlock.ts +++ b/src/compiler/compile/render_dom/wrappers/EachBlock.ts @@ -111,7 +111,7 @@ export default class EachBlockWrapper extends Wrapper { while (renderer.component.source[c] !== 'e') c += 1; // renderer.component.code.overwrite(c, c + 4, 'length'); - const each_block_value = renderer.component.get_unique_name(`${this.var}_value`); + const each_block_value = renderer.component.get_unique_name(`${this.var.name}_value`); const iterations = block.get_unique_name(`${this.var}_blocks`); this.vars = { @@ -190,7 +190,7 @@ export default class EachBlockWrapper extends Wrapper { if (this.node.has_binding) this.context_props.push(`child_ctx.${this.vars.each_block_value} = list;`); if (this.node.has_binding || this.node.index) this.context_props.push(`child_ctx.${this.index_name} = i;`); - const snippet = this.node.expression.render(block); + const snippet = this.node.expression.manipulate(block); block.chunks.init.push(b`let ${this.vars.each_block_value} = ${snippet};`); diff --git a/src/compiler/compile/render_dom/wrappers/Element/Attribute.ts b/src/compiler/compile/render_dom/wrappers/Element/Attribute.ts index 457e84f1523b..76da9f0de96e 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/Attribute.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/Attribute.ts @@ -78,7 +78,7 @@ export default class AttributeWrapper { // DRY it out if that's possible without introducing crazy indirection if (this.node.chunks.length === 1) { // single {tag} — may be a non-string - value = (this.node.chunks[0] as Expression).render(block); + value = (this.node.chunks[0] as Expression).manipulate(block); } else { // '{foo} {bar}' — treat as string concatenation const prefix = this.node.chunks[0].type === 'Text' ? '' : `"" + `; @@ -207,10 +207,7 @@ export default class AttributeWrapper { return stringify(chunk.data); } - const rendered = chunk.render(); - return chunk.get_precedence() <= 13 - ? `(${rendered})` - : rendered; + return chunk.manipulate(); }); } @@ -223,7 +220,7 @@ export default class AttributeWrapper { return `="${value.map(chunk => { return chunk.type === 'Text' ? chunk.data.replace(/"/g, '\\"') - : `\${${chunk.render()}}`; + : `\${${chunk.manipulate()}}`; }).join('')}"`; } } diff --git a/src/compiler/compile/render_dom/wrappers/Element/Binding.ts b/src/compiler/compile/render_dom/wrappers/Element/Binding.ts index 3ea94364b084..c644608c88f2 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/Binding.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/Binding.ts @@ -64,7 +64,7 @@ export default class BindingWrapper { // view to model this.handler = get_event_handler(this, parent.renderer, block, this.object, contextless_snippet); - this.snippet = this.node.expression.render(block); + this.snippet = this.node.expression.manipulate(block); this.is_readonly = this.node.is_readonly; diff --git a/src/compiler/compile/render_dom/wrappers/Element/StyleAttribute.ts b/src/compiler/compile/render_dom/wrappers/Element/StyleAttribute.ts index c7135ce26718..1bf8a341d46b 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/StyleAttribute.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/StyleAttribute.ts @@ -35,10 +35,10 @@ export default class StyleAttributeWrapper extends AttributeWrapper { if (chunk.type === 'Text') { return stringify(chunk.data); } else { - const snippet = chunk.render(); + const snippet = chunk.manipulate(); add_to_set(prop_dependencies, chunk.dynamic_dependencies()); - return chunk.get_precedence() <= 13 ? `(${snippet})` : snippet; + return snippet; } }) .join(' + '); diff --git a/src/compiler/compile/render_dom/wrappers/Element/index.ts b/src/compiler/compile/render_dom/wrappers/Element/index.ts index f9ff501255b3..01f034242e80 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/index.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/index.ts @@ -601,7 +601,7 @@ export default class ElementWrapper extends Wrapper { : null; if (attr.is_spread) { - const snippet = attr.expression.render(block); + const snippet = attr.expression.manipulate(block); initial_props.push(snippet); @@ -654,7 +654,7 @@ export default class ElementWrapper extends Wrapper { // bidirectional transition const name = block.get_unique_name(`${this.var}_transition`); const snippet = intro.expression - ? intro.expression.render(block) + ? intro.expression.manipulate(block) : '{}'; block.add_variable(name); @@ -700,7 +700,7 @@ export default class ElementWrapper extends Wrapper { if (intro) { block.add_variable(intro_name); const snippet = intro.expression - ? intro.expression.render(block) + ? intro.expression.manipulate(block) : '{}'; const fn = component.qualify(intro.name); @@ -742,7 +742,7 @@ export default class ElementWrapper extends Wrapper { if (outro) { block.add_variable(outro_name); const snippet = outro.expression - ? outro.expression.render(block) + ? outro.expression.manipulate(block) : '{}'; const fn = component.qualify(outro.name); @@ -796,7 +796,7 @@ export default class ElementWrapper extends Wrapper { ${outro && `@add_transform(${this.var}, ${rect});`} `); - const params = this.node.animation.expression ? this.node.animation.expression.render(block) : '{}'; + const params = this.node.animation.expression ? this.node.animation.expression.manipulate(block) : '{}'; const name = component.qualify(this.node.animation.name); @@ -816,7 +816,7 @@ export default class ElementWrapper extends Wrapper { let snippet; let dependencies; if (expression) { - snippet = expression.render(block); + snippet = expression.manipulate(block); dependencies = expression.dependencies; } else { snippet = `${quote_prop_if_necessary(name)}`; diff --git a/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts b/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts index 1c0a8106c3a9..791cd9399ead 100644 --- a/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts +++ b/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts @@ -200,7 +200,7 @@ export default class InlineComponentWrapper extends Wrapper { : null; if (attr.is_spread) { - const value = attr.expression.render(block); + const value = attr.expression.manipulate(block); initial_props.push(value); let value_object = value; @@ -271,7 +271,7 @@ export default class InlineComponentWrapper extends Wrapper { const updating = block.get_unique_name(`updating_${binding.name}`); block.add_variable(updating); - const snippet = binding.expression.render(block); + const snippet = binding.expression.manipulate(block); statements.push(b` if (${snippet} !== void 0) { @@ -346,7 +346,7 @@ export default class InlineComponentWrapper extends Wrapper { const switch_value = block.get_unique_name('switch_value'); const switch_props = block.get_unique_name('switch_props'); - const snippet = this.node.expression.render(block); + const snippet = this.node.expression.manipulate(block); block.chunks.init.push(b` var ${switch_value} = ${snippet}; diff --git a/src/compiler/compile/render_dom/wrappers/Title.ts b/src/compiler/compile/render_dom/wrappers/Title.ts index 0ccd85b87293..1954294c2ac8 100644 --- a/src/compiler/compile/render_dom/wrappers/Title.ts +++ b/src/compiler/compile/render_dom/wrappers/Title.ts @@ -35,7 +35,7 @@ export default class TitleWrapper extends Wrapper { // single {tag} — may be a non-string // @ts-ignore todo: check this const { expression } = this.node.children[0]; - value = expression.render(block); + value = expression.manipulate(block); add_to_set(all_dependencies, expression.dependencies); } else { // '{foo} {bar}' — treat as string concatenation @@ -47,7 +47,7 @@ export default class TitleWrapper extends Wrapper { return stringify(chunk.data); } else { // @ts-ignore todo: check this - const snippet = chunk.expression.render(block); + const snippet = chunk.expression.manipulate(block); // @ts-ignore todo: check this chunk.expression.dependencies.forEach(d => { all_dependencies.add(d); diff --git a/src/compiler/compile/render_dom/wrappers/shared/Tag.ts b/src/compiler/compile/render_dom/wrappers/shared/Tag.ts index 6ee900f2e99b..08e0fc1c3563 100644 --- a/src/compiler/compile/render_dom/wrappers/shared/Tag.ts +++ b/src/compiler/compile/render_dom/wrappers/shared/Tag.ts @@ -21,9 +21,9 @@ export default class Tag extends Wrapper { update: ((value: Node) => Node) ) { const dependencies = this.node.expression.dynamic_dependencies(); - const snippet = this.node.expression.node; + const snippet = this.node.expression.manipulate(block); - const value = this.node.should_cache && block.get_unique_name(`${this.var}_value`); + const value = this.node.should_cache && block.get_unique_name(`${this.var.name}_value`); const content = this.node.should_cache ? value : snippet; if (this.node.should_cache) block.add_variable(value, snippet); // TODO may need to coerce snippet to string 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 485ae9b9fd40..6b7e2a039a1b 100644 --- a/src/compiler/compile/render_dom/wrappers/shared/add_actions.ts +++ b/src/compiler/compile/render_dom/wrappers/shared/add_actions.ts @@ -15,7 +15,7 @@ export default function add_actions( let dependencies; if (expression) { - snippet = expression.render(block); + snippet = expression.manipulate(block); dependencies = expression.dynamic_dependencies(); } diff --git a/test/runtime/samples/_/_config.js b/test/runtime/samples/_/_config.js index e7538c4ecfb8..9ea1f81777c4 100644 --- a/test/runtime/samples/_/_config.js +++ b/test/runtime/samples/_/_config.js @@ -1,6 +1,3 @@ export default { - solo: 1, - show: 1, - - html: '

Hello world!

' + html: '

1 + 2 = 3

' }; \ No newline at end of file diff --git a/test/runtime/samples/_/main.svelte b/test/runtime/samples/_/main.svelte index 41e3ddf043a0..19ec9ea8cedf 100644 --- a/test/runtime/samples/_/main.svelte +++ b/test/runtime/samples/_/main.svelte @@ -1,5 +1,6 @@ -

Hello {name}!

\ No newline at end of file +

{a} + {b} = {a + b}

\ No newline at end of file From 12e7b5ecf5ad9a6594dbe4fcbd6957f0dc9cd369 Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Wed, 11 Sep 2019 22:57:01 -0400 Subject: [PATCH 09/93] more --- package-lock.json | 28 ++- package.json | 2 +- src/compiler/compile/Component.ts | 8 +- .../compile/nodes/shared/Expression.ts | 179 ++++++++---------- src/compiler/compile/render_dom/Block.ts | 10 +- src/compiler/compile/render_dom/index.ts | 2 +- .../compile/render_dom/wrappers/EachBlock.ts | 6 +- .../render_dom/wrappers/Element/Binding.ts | 16 +- .../render_dom/wrappers/Element/index.ts | 2 +- .../wrappers/InlineComponent/index.ts | 2 +- .../compile/render_dom/wrappers/shared/Tag.ts | 2 +- .../render_dom/wrappers/shared/add_actions.ts | 19 +- src/compiler/compile/utils/invalidate.ts | 99 +++++----- src/compiler/parse/acorn.ts | 6 +- test/runtime/index.js | 2 +- test/runtime/samples/_/_config.js | 2 +- test/runtime/samples/action/_config.js | 2 +- 17 files changed, 201 insertions(+), 186 deletions(-) diff --git a/package-lock.json b/package-lock.json index ada0a223f88c..5e7b60bdc7ee 100644 --- a/package-lock.json +++ b/package-lock.json @@ -520,6 +520,12 @@ "source-map": "^0.7.3" }, "dependencies": { + "estree-walker": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz", + "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==", + "dev": true + }, "source-map": { "version": "0.7.3", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", @@ -1208,9 +1214,9 @@ "dev": true }, "estree-walker": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz", - "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==", + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.7.0.tgz", + "integrity": "sha512-6BzTIhsjm2jnqLO+O23aaiDGr9jsrgwT1ObAIEebwvbJthCoF5T1MtybbCx540r2U5fsn/8IIv7ZWqMqTHuu6Q==", "dev": true }, "esutils": { @@ -3103,6 +3109,14 @@ "magic-string": "^0.25.2", "resolve": "^1.11.0", "rollup-pluginutils": "^2.8.1" + }, + "dependencies": { + "estree-walker": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz", + "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==", + "dev": true + } } }, "rollup-plugin-json": { @@ -3170,6 +3184,14 @@ "dev": true, "requires": { "estree-walker": "^0.6.1" + }, + "dependencies": { + "estree-walker": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz", + "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==", + "dev": true + } } }, "run-async": { diff --git a/package.json b/package.json index f7d3d85a4e04..0ea531048bd7 100644 --- a/package.json +++ b/package.json @@ -69,7 +69,7 @@ "eslint": "^6.3.0", "eslint-plugin-import": "^2.18.2", "eslint-plugin-svelte3": "^2.7.3", - "estree-walker": "^0.6.1", + "estree-walker": "^0.7.0", "is-reference": "^1.1.3", "jsdom": "^15.1.1", "kleur": "^3.0.3", diff --git a/src/compiler/compile/Component.ts b/src/compiler/compile/Component.ts index 039309cd2837..4443c2679d46 100644 --- a/src/compiler/compile/Component.ts +++ b/src/compiler/compile/Component.ts @@ -810,11 +810,11 @@ export default class Component { const variable = this.var_lookup.get(name); if (variable && (variable.subscribable && variable.reassigned)) { - return `$$subscribe_${name}($$invalidate('${name}', ${value || name}))`; + return x`$$subscribe_${name}($$invalidate('${name}', ${value || name}))`; } if (name[0] === '$' && name[1] !== '$') { - return `${name.slice(1)}.set(${name})`; + return x`${name.slice(1)}.set(${name})`; } if ( @@ -845,9 +845,7 @@ export default class Component { }); }); - return Array.from(deps) - .map(n => `$$invalidate('${n}', ${n})`) - .join(', '); + return Array.from(deps).map(n => x`$$invalidate('${n}', ${n})`); } rewrite_props(_get_insert: (variable: Var) => string) { diff --git a/src/compiler/compile/nodes/shared/Expression.ts b/src/compiler/compile/nodes/shared/Expression.ts index ea133e322e29..900a0ba976ab 100644 --- a/src/compiler/compile/nodes/shared/Expression.ts +++ b/src/compiler/compile/nodes/shared/Expression.ts @@ -4,14 +4,14 @@ import is_reference from 'is-reference'; import flatten_reference from '../../utils/flatten_reference'; import { create_scopes, Scope, extract_names } from '../../utils/scope'; import { Node } from '../../../interfaces'; -import { globals } from '../../../utils/names'; +import { globals, sanitize } from '../../../utils/names'; import Wrapper from '../../render_dom/wrappers/shared/Wrapper'; import TemplateScope from './TemplateScope'; import get_object from '../../utils/get_object'; import Block from '../../render_dom/Block'; import { INode } from '../interfaces'; import is_dynamic from '../../render_dom/wrappers/shared/is_dynamic'; -import { x } from 'code-red'; +import { x, b } from 'code-red'; import { invalidate } from '../../utils/invalidate'; const binary_operators: Record = { @@ -228,6 +228,7 @@ export default class Expression { declarations, scope_map: map, template_scope, + owner, is_synthetic } = this; let scope = this.scope; @@ -237,11 +238,8 @@ export default class Expression { let dependencies: Set; let contextual_dependencies: Set; - // TODO this feels a lil messy - let return_value = this.node; - - walk(this.node, { - enter(node: any, parent: any, key: string, index: number) { + const node = walk(this.node, { + enter(node: any, parent: any, key: string) { // don't manipulate shorthand props twice if (key === 'value' && parent.shorthand) return; @@ -267,18 +265,7 @@ export default class Expression { component.add_reference(name); // TODO is this redundant/misplaced? } } else if (!is_synthetic && is_contextual(component, template_scope, name)) { - const replaced = x`ctx.${node}`; - - if (parent) { - if (index !== null) { - // TODO can this happen? - parent[key][index] = replaced; - } else { - parent[key] = replaced; - } - } else { - return_value = replaced; - } + this.replace(x`#ctx.${node}`); } this.skip(); @@ -297,78 +284,72 @@ export default class Expression { } }, - leave(node: Node, _parent: Node) { + leave(node: Node) { if (map.has(node)) scope = scope.parent; if (node === function_expression) { - // const id = component.get_unique_name( - // sanitize(get_function_name(node, owner)) - // ); - - // const args = contextual_dependencies.size > 0 - // ? [`{ ${Array.from(contextual_dependencies).join(', ')} }`] - // : []; - - // let original_params; - - // if (node.params.length > 0) { - // original_params = code.slice(node.params[0].start, node.params[node.params.length - 1].end); - // args.push(original_params); - // } - - // const body = code.slice(node.body.start, node.body.end).trim(); - - // const fn = node.type === 'FunctionExpression' - // ? b`${node.async ? 'async ' : ''}function${node.generator ? '*' : ''} ${id}(${args.join(', ')}) ${body}` - // : b`const ${id} = ${node.async ? 'async ' : ''}(${args.join(', ')}) => ${body};`; - - // if (dependencies.size === 0 && contextual_dependencies.size === 0) { - // // we can hoist this out of the component completely - // component.fully_hoisted.push(fn); - - // // code.overwrite(node.start, node.end, id.name); - - // component.add_var({ - // name: id.name, - // internal: true, - // hoistable: true, - // referenced: true - // }); - // } - - // else if (contextual_dependencies.size === 0) { - // // function can be hoisted inside the component init - // component.partly_hoisted.push(fn); - // code.overwrite(node.start, node.end, `ctx.${id}`); - - // component.add_var({ - // name: id.name, - // internal: true, - // referenced: true - // }); - // } - - // else { - // // we need a combo block/init recipe - // component.partly_hoisted.push(fn); - // code.overwrite(node.start, node.end, id.name); - - // component.add_var({ - // name: id.name, - // internal: true, - // referenced: true - // }); - - // declarations.push(b` - // function ${id}(${original_params ? '...args' : ''}) { - // return ctx.${id}(ctx${original_params ? ', ...args' : ''}); - // } - // `); - // } - - // if (parent && parent.method) { - // code.prependRight(node.start, ': '); - // } + const id = component.get_unique_name( + sanitize(get_function_name(node, owner)) + ); + + const declaration = b`const ${id} = ${node}`; + + if (dependencies.size === 0 && contextual_dependencies.size === 0) { + // we can hoist this out of the component completely + component.fully_hoisted.push(declaration); + node.name = id; + + this.replace(id as any); + + component.add_var({ + name: id.name, + internal: true, + hoistable: true, + referenced: true + }); + } + + else if (contextual_dependencies.size === 0) { + // function can be hoisted inside the component init + component.partly_hoisted.push(declaration); + node.name = id; + + this.replace(x`#ctx.${id}` as any); + + component.add_var({ + name: id.name, + internal: true, + referenced: true + }); + } + + else { + // we need a combo block/init recipe + component.partly_hoisted.push(declaration); + node.name = id; + + this.replace(id as any); + + component.add_var({ + name: id.name, + internal: true, + referenced: true + }); + + if (node.params.length > 0) { + declarations.push(b` + function ${id}(...args) { + return #ctx.${id}(#ctx, ...args); + } + `); + } else { + declarations.push(b` + function ${id}() { + return #ctx.${id}(#ctx); + } + `); + } + } function_expression = null; dependencies = null; @@ -394,7 +375,7 @@ export default class Expression { } }); - invalidate(component, scope, node, traced); + this.replace(invalidate(component, scope, node, traced)); } } }); @@ -406,21 +387,21 @@ export default class Expression { }); } - return return_value; + return node; } } -// function get_function_name(_node, parent) { -// if (parent.type === 'EventHandler') { -// return `${parent.name}_handler`; -// } +function get_function_name(_node, parent) { + if (parent.type === 'EventHandler') { + return `${parent.name}_handler`; + } -// if (parent.type === 'Action') { -// return `${parent.name}_function`; -// } + if (parent.type === 'Action') { + return `${parent.name}_function`; + } -// return 'func'; -// } + return 'func'; +} function is_contextual(component: Component, scope: TemplateScope, name: string) { if (name === '$$props') return true; diff --git a/src/compiler/compile/render_dom/Block.ts b/src/compiler/compile/render_dom/Block.ts index e1cc3d6a3d0d..cde43a89567a 100644 --- a/src/compiler/compile/render_dom/Block.ts +++ b/src/compiler/compile/render_dom/Block.ts @@ -114,7 +114,7 @@ export default class Block { this.get_unique_name = this.renderer.component.get_unique_name_maker(); - this.aliases = new Map().set('ctx', this.get_unique_name('ctx')); + this.aliases = new Map(); if (this.key) this.aliases.set('key', this.get_unique_name('key')); } @@ -304,9 +304,9 @@ export default class Block { if (this.chunks.update.length === 0 && !this.maintain_context) { properties.update = noop; } else { - const ctx = this.maintain_context ? x`new_ctx` : x`ctx`; + const ctx = this.maintain_context ? x`#new_ctx` : x`#ctx`; properties.update = x`function update(#changed, ${ctx}) { - ${this.maintain_context && b`ctx = ${ctx};`} + ${this.maintain_context && b`#ctx = ${ctx};`} ${this.chunks.update} }`; } @@ -385,7 +385,7 @@ export default class Block { ${dev ? 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 }); + @dispatch_dev("SvelteRegisterBlock", { block, id: ${this.name || 'create_fragment'}.name, type: "${this.type}", source: "${this.comment ? this.comment.replace(/"/g, '\\"') : ''}", ctx: #ctx }); return block;` : b` return ${return_value};` @@ -398,7 +398,7 @@ export default class Block { const key = this.key && { type: 'Identifier', name: this.get_unique_name('key') }; const id = { type: 'Identifier', name: this.name }; - const args: any[] = [x`ctx`]; + const args: any[] = [x`#ctx`]; if (key) args.unshift(key); diff --git a/src/compiler/compile/render_dom/index.ts b/src/compiler/compile/render_dom/index.ts index 31469be6eb19..c35d3d317dd8 100644 --- a/src/compiler/compile/render_dom/index.ts +++ b/src/compiler/compile/render_dom/index.ts @@ -368,7 +368,7 @@ export default function dom( ${renderer.binding_groups.length > 0 && `const $$binding_groups = [${renderer.binding_groups.map(_ => `[]`).join(', ')}];`} - ${component.partly_hoisted.length > 0 && component.partly_hoisted.join('\n\n')} + ${component.partly_hoisted} ${set && b`$$self.$set = ${set};`} diff --git a/src/compiler/compile/render_dom/wrappers/EachBlock.ts b/src/compiler/compile/render_dom/wrappers/EachBlock.ts index 7387ab27b0ff..35f6dc6e8dba 100644 --- a/src/compiler/compile/render_dom/wrappers/EachBlock.ts +++ b/src/compiler/compile/render_dom/wrappers/EachBlock.ts @@ -7,7 +7,7 @@ import FragmentWrapper from './Fragment'; import { b, x } from 'code-red'; import ElseBlock from '../../nodes/ElseBlock'; import { attach_head } from '../../utils/tail'; -import { Identifier } from '../../../interfaces'; +import { Identifier, Node } from '../../../interfaces'; export class ElseBlockWrapper extends Wrapper { node: ElseBlock; @@ -315,7 +315,7 @@ export default class EachBlockWrapper extends Wrapper { block: Block; parent_node: string; parent_nodes: string; - snippet: string; + snippet: Node; initial_anchor_node: Identifier; initial_mount_node: Identifier; update_anchor_node: Identifier; @@ -424,7 +424,7 @@ export default class EachBlockWrapper extends Wrapper { }: { block: Block; parent_nodes: string; - snippet: string; + snippet: Node; initial_anchor_node: Identifier; initial_mount_node: Identifier; update_anchor_node: Identifier; diff --git a/src/compiler/compile/render_dom/wrappers/Element/Binding.ts b/src/compiler/compile/render_dom/wrappers/Element/Binding.ts index c644608c88f2..09426db67a99 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/Binding.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/Binding.ts @@ -7,7 +7,7 @@ import Node from '../../../nodes/shared/Node'; import Renderer from '../../Renderer'; import flatten_reference from '../../../utils/flatten_reference'; import EachBlock from '../../../nodes/EachBlock'; -import { Node as INode } from '../../../../interfaces'; +import { Node as INode, Identifier } from '../../../../interfaces'; function get_tail(node: INode) { const end = node.end; @@ -26,7 +26,7 @@ export default class BindingWrapper { contextual_dependencies: Set; snippet?: string; }; - snippet: string; + snippet: INode; is_readonly: boolean; needs_lock: boolean; @@ -90,7 +90,7 @@ export default class BindingWrapper { return this.node.is_readonly_media_attribute(); } - render(block: Block, lock: string) { + render(block: Block, lock: Identifier) { if (this.is_readonly) return; const { parent } = this; @@ -167,14 +167,22 @@ export default class BindingWrapper { if (update_dom) { block.chunks.update.push( - update_conditions.length ? b`if (${update_conditions.join(' && ')}) ${update_dom}` : update_dom + update_conditions.length + ? b`if (${update_conditions.join(' && ')}) { + ${update_dom} + }` + : update_dom ); + + console.log('update_dom', JSON.stringify(block.chunks.update, null, ' ')); } if (this.node.name === 'innerHTML' || this.node.name === 'textContent') { block.chunks.mount.push(b`if (${this.snippet} !== void 0) ${update_dom}`); } else if (!/(currentTime|paused)/.test(this.node.name)) { block.chunks.mount.push(update_dom); + + console.log('update_dom', JSON.stringify(block.chunks.mount, null, ' ')); } } } diff --git a/src/compiler/compile/render_dom/wrappers/Element/index.ts b/src/compiler/compile/render_dom/wrappers/Element/index.ts index 01f034242e80..4aac73aac7ba 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/index.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/index.ts @@ -453,7 +453,7 @@ export default class ElementWrapper extends Wrapper { add_to_set(contextual_dependencies, binding.node.expression.contextual_dependencies); add_to_set(contextual_dependencies, binding.handler.contextual_dependencies); - binding.render(block, lock.name); + binding.render(block, lock); }); // media bindings — awkward special case. The native timeupdate events diff --git a/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts b/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts index 791cd9399ead..b8405b7df301 100644 --- a/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts +++ b/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts @@ -205,7 +205,7 @@ export default class InlineComponentWrapper extends Wrapper { let value_object = value; if (attr.expression.node.type !== 'ObjectExpression') { - value_object = `@get_spread_object(${value})`; + value_object = x`@get_spread_object(${value})`; } changes.push(condition ? `${condition} && ${value_object}` : value_object); } else { diff --git a/src/compiler/compile/render_dom/wrappers/shared/Tag.ts b/src/compiler/compile/render_dom/wrappers/shared/Tag.ts index 08e0fc1c3563..902074aab722 100644 --- a/src/compiler/compile/render_dom/wrappers/shared/Tag.ts +++ b/src/compiler/compile/render_dom/wrappers/shared/Tag.ts @@ -40,7 +40,7 @@ export default class Tag extends Wrapper { ? `(${changed_check}) && ${update_cached_value}` : changed_check; - block.chunks.update.push(b`if (${condition}) ${update(content)}`); + block.chunks.update.push(b`if (${condition}) ${update(content as Node)}`); } 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 6b7e2a039a1b..6eb25fcc3610 100644 --- a/src/compiler/compile/render_dom/wrappers/shared/add_actions.ts +++ b/src/compiler/compile/render_dom/wrappers/shared/add_actions.ts @@ -2,6 +2,7 @@ import { b } from 'code-red'; import Block from '../../Block'; import Action from '../../../nodes/Action'; import Component from '../../../Component'; +import { x } from 'code-red'; export default function add_actions( component: Component, @@ -28,16 +29,24 @@ export default function add_actions( const fn = component.qualify(action.name); block.chunks.mount.push( - b`${id} = ${fn}.call(null, ${target}${snippet ? `, ${snippet}` : ''}) || {};` + b`${id} = ${fn}.call(null, ${target}, ${snippet}) || {};` ); if (dependencies && dependencies.length > 0) { - let conditional = `typeof ${id}.update === 'function' && `; - const deps = dependencies.map(dependency => `changed.${dependency}`).join(' || '); - conditional += dependencies.length > 1 ? `(${deps})` : deps; + let condition = x`typeof ${id}.update === 'function'`; + + // TODO can this case be handled more elegantly? + if (dependencies.length > 0) { + let changed = x`#changed.${dependencies[0]}`; + for (let i = 1; i < dependencies.length; i += 1) { + changed = x`${changed} || #changed.${dependencies[i]}`; + } + + condition = x`${condition} && ${changed}`; + } block.chunks.update.push( - b`if (${conditional}) ${id}.update.call(null, ${snippet});` + b`if (${condition}) ${id}.update.call(null, ${snippet});` ); } diff --git a/src/compiler/compile/utils/invalidate.ts b/src/compiler/compile/utils/invalidate.ts index 2eae0766d724..053e64bf3e8f 100644 --- a/src/compiler/compile/utils/invalidate.ts +++ b/src/compiler/compile/utils/invalidate.ts @@ -1,67 +1,66 @@ import Component from '../Component'; import { Node } from '../../interfaces'; -// import { nodes_match } from '../../utils/nodes_match'; +import { nodes_match } from '../../utils/nodes_match'; import { Scope } from './scope'; +import { x } from 'code-red'; -export function invalidate(_component: Component, _scope: Scope, _node: Node, _names: Set) { - // const [head, ...tail] = Array.from(names).filter(name => { - // const owner = scope.find_owner(name); - // if (owner && owner !== component.instance_scope) return false; +export function invalidate(component: Component, scope: Scope, node: Node, names: Set) { + const [head, ...tail] = Array.from(names).filter(name => { + const owner = scope.find_owner(name); + if (owner && owner !== component.instance_scope) return false; - // const variable = component.var_lookup.get(name); + const variable = component.var_lookup.get(name); - // return variable && ( - // !variable.hoistable && - // !variable.global && - // !variable.module && - // ( - // variable.referenced || - // variable.is_reactive_dependency || - // variable.export_name || - // variable.name[0] === '$' - // ) - // ); - // }); + return variable && ( + !variable.hoistable && + !variable.global && + !variable.module && + ( + variable.referenced || + variable.is_reactive_dependency || + variable.export_name || + variable.name[0] === '$' + ) + ); + }); - // TODO + if (head) { + component.has_reactive_assignments = true; - // if (head) { - // component.has_reactive_assignments = true; + if (node.operator === '=' && nodes_match(node.left, node.right) && tail.length === 0) { + return component.invalidate(head); + } else { - // if (node.operator === '=' && nodes_match(node.left, node.right) && tail.length === 0) { - // code.overwrite(node.start, node.end, component.invalidate(head)); - // } else { - // let suffix = ')'; + // TODO stores + // if (head[0] === '$') { + // code.prependRight(node.start, `${component.helper('set_store_value')}(${head.slice(1)}, `); + // } else { + // let prefix = `$$invalidate`; - // if (head[0] === '$') { - // code.prependRight(node.start, `${component.helper('set_store_value')}(${head.slice(1)}, `); - // } else { - // let prefix = `$$invalidate`; + // const variable = component.var_lookup.get(head); + // if (variable.subscribable && variable.reassigned) { + // prefix = `$$subscribe_${head}($$invalidate`; + // suffix += `)`; + // } - // const variable = component.var_lookup.get(head); - // if (variable.subscribable && variable.reassigned) { - // prefix = `$$subscribe_${head}($$invalidate`; - // suffix += `)`; - // } + // code.prependRight(node.start, `${prefix}('${head}', `); + // } - // code.prependRight(node.start, `${prefix}('${head}', `); - // } + const extra_args = tail.map(name => component.invalidate(name)); - // const extra_args = tail.map(name => component.invalidate(name)); + const pass_value = ( + extra_args.length > 0 || + (node.type === 'AssignmentExpression' && node.left.type !== 'Identifier') || + (node.type === 'UpdateExpression' && !node.prefix) + ); - // const pass_value = ( - // extra_args.length > 0 || - // (node.type === 'AssignmentExpression' && node.left.type !== 'Identifier') || - // (node.type === 'UpdateExpression' && !node.prefix) - // ); + if (pass_value) { + extra_args.unshift(head); + } - // if (pass_value) { - // extra_args.unshift(head); - // } + return x`$$invalidate("${head}", ${node}, ${extra_args})`; + } + } - // suffix = `${extra_args.map(arg => `, ${arg}`).join('')}${suffix}`; - - // code.appendLeft(node.end, suffix); - // } - // } + return node; } \ No newline at end of file diff --git a/src/compiler/parse/acorn.ts b/src/compiler/parse/acorn.ts index c5cf5facdf84..308a99a42273 100644 --- a/src/compiler/parse/acorn.ts +++ b/src/compiler/parse/acorn.ts @@ -5,12 +5,10 @@ const Parser = acorn.Parser; export const parse = (source: string) => Parser.parse(source, { sourceType: 'module', // @ts-ignore TODO pending release of fixed types - ecmaVersion: 11, - preserveParens: true + ecmaVersion: 11 }); export const parse_expression_at = (source: string, index: number) => Parser.parseExpressionAt(source, index, { // @ts-ignore TODO pending release of fixed types - ecmaVersion: 11, - preserveParens: true + ecmaVersion: 11 }); \ No newline at end of file diff --git a/test/runtime/index.js b/test/runtime/index.js index 505ac4d139f6..b08f7c88e0c1 100644 --- a/test/runtime/index.js +++ b/test/runtime/index.js @@ -26,7 +26,7 @@ process.on('unhandledRejection', err => { unhandled_rejection = err; }); -describe("runtime", () => { +describe.only("runtime", () => { before(() => { svelte = loadSvelte(false); svelte$ = loadSvelte(true); diff --git a/test/runtime/samples/_/_config.js b/test/runtime/samples/_/_config.js index 9ea1f81777c4..c16f9b94f49f 100644 --- a/test/runtime/samples/_/_config.js +++ b/test/runtime/samples/_/_config.js @@ -1,3 +1,3 @@ export default { - html: '

1 + 2 = 3

' + html: '

1 + 2 = 3

' }; \ No newline at end of file diff --git a/test/runtime/samples/action/_config.js b/test/runtime/samples/action/_config.js index 07b4087dcca3..6aa972f1a81b 100644 --- a/test/runtime/samples/action/_config.js +++ b/test/runtime/samples/action/_config.js @@ -3,7 +3,7 @@ export default { `, - async test({ assert, component, target, window }) { + async test({ assert, target, window }) { const button = target.querySelector('button'); const eventEnter = new window.MouseEvent('mouseenter'); const eventLeave = new window.MouseEvent('mouseleave'); From 6514b142dc7889d9572b0e3b6355c2cb0f452486 Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Thu, 12 Sep 2019 09:26:59 -0400 Subject: [PATCH 10/93] more --- src/compiler/compile/Component.ts | 13 +++- src/compiler/compile/create_module.ts | 17 +++-- src/compiler/compile/nodes/Binding.ts | 2 +- src/compiler/compile/nodes/EventHandler.ts | 2 +- .../compile/nodes/shared/Expression.ts | 10 +++ src/compiler/compile/render_dom/Block.ts | 6 +- src/compiler/compile/render_dom/index.ts | 10 ++- .../compile/render_dom/wrappers/AwaitBlock.ts | 8 +- .../compile/render_dom/wrappers/EachBlock.ts | 73 +++++++++++-------- .../compile/render_dom/wrappers/shared/Tag.ts | 22 +++--- src/runtime/internal/Component.ts | 1 + 11 files changed, 100 insertions(+), 64 deletions(-) diff --git a/src/compiler/compile/Component.ts b/src/compiler/compile/Component.ts index 4443c2679d46..7f61df306a3e 100644 --- a/src/compiler/compile/Component.ts +++ b/src/compiler/compile/Component.ts @@ -300,8 +300,13 @@ export default class Component { walk(program, { enter: (node) => { if (node.type === 'Identifier' && node.name[0] === '@') { - const alias = this.helper(node.name.slice(1)); - node.name = alias.name; + if (node.name[1] === '_') { + const alias = this.global(node.name.slice(2)); + node.name = alias.name; + } else { + const alias = this.helper(node.name.slice(1)); + node.name = alias.name; + } } } }); @@ -1223,7 +1228,7 @@ export default class Component { } qualify(name) { - if (name === `$$props`) return `ctx.$$props`; + if (name === `$$props`) return `#ctx.$$props`; const variable = this.var_lookup.get(name); @@ -1233,7 +1238,7 @@ export default class Component { if (variable.hoistable) return name; - return `ctx.${name}`; + return `#ctx.${name}`; } warn_if_undefined(name: string, node, template_scope: TemplateScope) { diff --git a/src/compiler/compile/create_module.ts b/src/compiler/compile/create_module.ts index 2e2525883582..73ab84bdc196 100644 --- a/src/compiler/compile/create_module.ts +++ b/src/compiler/compile/create_module.ts @@ -58,10 +58,11 @@ function esm( source: { type: 'Literal', value: internal_path } } - const internal_globals = globals.length > 0 &&{ + const internal_globals = globals.length > 0 && { type: 'VariableDeclaration', kind: 'const', declarations: [{ + type: 'VariableDeclarator', id: { type: 'ObjectPattern', properties: globals.sort((a, b) => a.name < b.name ? -1 : 1).map(g => ({ @@ -70,10 +71,11 @@ function esm( shorthand: false, computed: false, key: { type: 'Identifier', name: g.name }, - value: { type: 'Identifier', name: g.alias } + value: g.alias, + kind: 'init' })) }, - init: { type: 'Identifier', name: helpers.find(({ name }) => name === 'globals').alias } + init: helpers.find(({ name }) => name === 'globals').alias }] }; @@ -135,7 +137,7 @@ function cjs( }] }; - const internal_globals = globals.length > 0 &&{ + const internal_globals = globals.length > 0 && { type: 'VariableDeclaration', kind: 'const', declarations: [{ @@ -148,10 +150,11 @@ function cjs( shorthand: false, computed: false, key: { type: 'Identifier', name: g.name }, - value: { type: 'Identifier', name: g.alias } + value: g.alias, + kind: 'init' })) }, - init: { type: 'Identifier', name: helpers.find(({ name }) => name === 'globals').alias } + init: helpers.find(({ name }) => name === 'globals').alias }] }; @@ -182,7 +185,7 @@ function cjs( program.body = b` "use strict"; ${internal_requires} - // ${internal_globals} + ${internal_globals} ${user_requires} ${program.body} diff --git a/src/compiler/compile/nodes/Binding.ts b/src/compiler/compile/nodes/Binding.ts index e099f4405a09..949b0c657ce7 100644 --- a/src/compiler/compile/nodes/Binding.ts +++ b/src/compiler/compile/nodes/Binding.ts @@ -68,7 +68,7 @@ export default class Binding extends Node { if (!this.expression.node.computed) prop = `'${prop}'`; obj = `[✂${this.expression.node.object.start}-${this.expression.node.object.end}✂]`; } else { - obj = 'ctx'; + obj = '#ctx'; prop = `'${name}'`; } diff --git a/src/compiler/compile/nodes/EventHandler.ts b/src/compiler/compile/nodes/EventHandler.ts index a1adfd345bb2..3abb2cff543f 100644 --- a/src/compiler/compile/nodes/EventHandler.ts +++ b/src/compiler/compile/nodes/EventHandler.ts @@ -66,6 +66,6 @@ export default class EventHandler extends Node { if (this.expression) this.expression.manipulate(block); // this.component.add_reference(this.handler_name); - return `ctx.${this.handler_name}`; + return `#ctx.${this.handler_name}`; } } diff --git a/src/compiler/compile/nodes/shared/Expression.ts b/src/compiler/compile/nodes/shared/Expression.ts index 900a0ba976ab..7b8ea6a925fc 100644 --- a/src/compiler/compile/nodes/shared/Expression.ts +++ b/src/compiler/compile/nodes/shared/Expression.ts @@ -325,6 +325,16 @@ export default class Expression { else { // we need a combo block/init recipe + node.params.unshift({ + type: 'ObjectPattern', + properties: Array.from(contextual_dependencies).map(name => ({ + type: 'Property', + kind: 'init', + key: { type: 'Identifier', name }, + value: { type: 'Identifier', name } + })) + }); + component.partly_hoisted.push(declaration); node.name = id; diff --git a/src/compiler/compile/render_dom/Block.ts b/src/compiler/compile/render_dom/Block.ts index cde43a89567a..f50b412f38a2 100644 --- a/src/compiler/compile/render_dom/Block.ts +++ b/src/compiler/compile/render_dom/Block.ts @@ -1,6 +1,5 @@ import Renderer from './Renderer'; import Wrapper from './wrappers/shared/Wrapper'; -import { escape } from '../utils/stringify'; import { b, x } from 'code-red'; import { Node, Identifier } from '../../interfaces'; @@ -397,16 +396,15 @@ export default class Block { 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 + // ${this.comment && `// ${escape(this.comment, { only_escape_at_symbol: true })}`} return b` - ${this.comment && `// ${escape(this.comment, { only_escape_at_symbol: true })}`} - function ${id}(${args}) { + function ${this.name}(${args}) { ${this.get_contents(key)} } `; diff --git a/src/compiler/compile/render_dom/index.ts b/src/compiler/compile/render_dom/index.ts index c35d3d317dd8..7d57a48f9115 100644 --- a/src/compiler/compile/render_dom/index.ts +++ b/src/compiler/compile/render_dom/index.ts @@ -9,6 +9,7 @@ import { stringify_props } from '../utils/stringify_props'; import add_to_set from '../utils/add_to_set'; import { extract_names } from '../utils/scope'; import { invalidate } from '../utils/invalidate'; +import Block from './Block'; export default function dom( component: Component, @@ -52,7 +53,12 @@ export default function dom( // TODO the deconflicted names of blocks are reversed... should set them here const blocks = renderer.blocks.slice().reverse(); - body.push(...blocks); + body.push(...blocks.map(block => { + // TODO this is a horrible mess — renderer.blocks + // contains a mixture of Blocks and Nodes + if ((block as Block).render) return (block as Block).render(); + return block; + })); if (options.dev && !options.hydratable) { block.chunks.claim.push( @@ -230,7 +236,7 @@ export default function dom( } body.push(b` - function create_fragment(ctx) { + function create_fragment(#ctx) { ${block.get_contents()} } diff --git a/src/compiler/compile/render_dom/wrappers/AwaitBlock.ts b/src/compiler/compile/render_dom/wrappers/AwaitBlock.ts index 9eceea691d0d..793b9935ab9e 100644 --- a/src/compiler/compile/render_dom/wrappers/AwaitBlock.ts +++ b/src/compiler/compile/render_dom/wrappers/AwaitBlock.ts @@ -137,7 +137,7 @@ export default class AwaitBlockWrapper extends Wrapper { block.maintain_context = true; const info_props = [ - 'ctx', + '#ctx', 'current: null', 'token: null', this.pending.block.name && `pending: ${this.pending.block.name}`, @@ -197,7 +197,7 @@ export default class AwaitBlockWrapper extends Wrapper { ); block.chunks.update.push( - b`${info}.ctx = ctx;` + b`${info}.ctx = #ctx;` ); if (this.pending.block.has_update_method) { @@ -205,7 +205,7 @@ export default class AwaitBlockWrapper extends Wrapper { if (${conditions.join(' && ')}) { // nothing } else { - ${info}.block.p(changed, @assign(@assign({}, ctx), ${info}.resolved)); + ${info}.block.p(changed, @assign(@assign({}, #ctx), ${info}.resolved)); } `); } else { @@ -216,7 +216,7 @@ export default class AwaitBlockWrapper extends Wrapper { } else { if (this.pending.block.has_update_method) { block.chunks.update.push(b` - ${info}.block.p(changed, @assign(@assign({}, ctx), ${info}.resolved)); + ${info}.block.p(changed, @assign(@assign({}, #ctx), ${info}.resolved)); `); } } diff --git a/src/compiler/compile/render_dom/wrappers/EachBlock.ts b/src/compiler/compile/render_dom/wrappers/EachBlock.ts index 35f6dc6e8dba..afc9f678bd67 100644 --- a/src/compiler/compile/render_dom/wrappers/EachBlock.ts +++ b/src/compiler/compile/render_dom/wrappers/EachBlock.ts @@ -59,7 +59,6 @@ export default class EachBlockWrapper extends Wrapper { fixed_length: number; data_length: string; view_length: string; - length: string; } context_props: string[]; @@ -104,27 +103,32 @@ export default class EachBlockWrapper extends Wrapper { ? node.expression.node.elements.length : null; - // TODO // hack the sourcemap, so that if data is missing the bug // is easy to find let c = this.node.start + 2; while (renderer.component.source[c] !== 'e') c += 1; + const length = { + type: 'Identifier', + name: 'length', + // TODO this format may be incorrect + start: c, + end: c + 4 + }; // renderer.component.code.overwrite(c, c + 4, 'length'); const each_block_value = renderer.component.get_unique_name(`${this.var.name}_value`); - const iterations = block.get_unique_name(`${this.var}_blocks`); + const iterations = block.get_unique_name(`${this.var.name}_blocks`); this.vars = { create_each_block: this.block.name, each_block_value, - get_each_context: renderer.component.get_unique_name(`get_${this.var}_context`), + get_each_context: renderer.component.get_unique_name(`get_${this.var.name}_context`), iterations, - length: `[✂${c}-${c+4}✂]`, // optimisation for array literal fixed_length, - data_length: fixed_length === null ? `${each_block_value}.[✂${c}-${c+4}✂]` : fixed_length, - view_length: fixed_length === null ? `${iterations}.[✂${c}-${c+4}✂]` : fixed_length + data_length: fixed_length === null ? x`${each_block_value}.${length}` : fixed_length, + view_length: fixed_length === null ? x`${iterations}.length` : fixed_length }; const store = @@ -185,18 +189,18 @@ export default class EachBlockWrapper extends Wrapper { ? !this.next.is_dom_node() : !parent_node || !this.parent.is_dom_node(); - this.context_props = this.node.contexts.map(prop => `child_ctx.${prop.key.name} = ${attach_head('list[i]', prop.tail)};`); + this.context_props = this.node.contexts.map(prop => b`child_ctx.${prop.key.name} = ${attach_head('list[i]', prop.tail)};`); - if (this.node.has_binding) this.context_props.push(`child_ctx.${this.vars.each_block_value} = list;`); - if (this.node.has_binding || this.node.index) this.context_props.push(`child_ctx.${this.index_name} = i;`); + if (this.node.has_binding) this.context_props.push(b`child_ctx.${this.vars.each_block_value} = list;`); + if (this.node.has_binding || this.node.index) this.context_props.push(b`child_ctx.${this.index_name} = i;`); const snippet = this.node.expression.manipulate(block); block.chunks.init.push(b`let ${this.vars.each_block_value} = ${snippet};`); renderer.blocks.push(b` - function ${this.vars.get_each_context}(ctx, list, i) { - const child_ctx = @_Object.create(ctx); + function ${this.vars.get_each_context}(#ctx, list, i) { + const child_ctx = @_Object.create(#ctx); ${this.context_props} return child_ctx; } @@ -251,7 +255,7 @@ export default class EachBlockWrapper extends Wrapper { // TODO neaten this up... will end up with an empty line in the block block.chunks.init.push(b` if (!${this.vars.data_length}) { - ${each_block_else} = ${this.else.block.name}(ctx); + ${each_block_else} = ${this.else.block.name}(#ctx); ${each_block_else}.c(); } `); @@ -265,9 +269,9 @@ export default class EachBlockWrapper extends Wrapper { if (this.else.block.has_update_method) { block.chunks.update.push(b` if (!${this.vars.data_length} && ${each_block_else}) { - ${each_block_else}.p(changed, ctx); + ${each_block_else}.p(changed, #ctx); } else if (!${this.vars.data_length}) { - ${each_block_else} = ${this.else.block.name}(ctx); + ${each_block_else} = ${this.else.block.name}(#ctx); ${each_block_else}.c(); ${each_block_else}.m(${update_mount_node}, ${update_anchor_node}); } else if (${each_block_else}) { @@ -283,7 +287,7 @@ export default class EachBlockWrapper extends Wrapper { ${each_block_else} = null; } } else if (!${each_block_else}) { - ${each_block_else} = ${this.else.block.name}(ctx); + ${each_block_else} = ${this.else.block.name}(#ctx); ${each_block_else}.c(); ${each_block_else}.m(${update_mount_node}, ${update_anchor_node}); } @@ -323,8 +327,8 @@ export default class EachBlockWrapper extends Wrapper { }) { const { create_each_block, - length, iterations, + data_length, view_length } = this.vars; @@ -347,12 +351,12 @@ export default class EachBlockWrapper extends Wrapper { } block.chunks.init.push(b` - const ${get_key} = ctx => ${ + const ${get_key} = #ctx => ${ // @ts-ignore todo: probably error this.node.key.render()}; - for (let #i = 0; #i < ${this.vars.each_block_value}.${length}; #i += 1) { - let child_ctx = ${this.vars.get_each_context}(ctx, ${this.vars.each_block_value}, #i); + for (let #i = 0; #i < ${data_length}; #i += 1) { + let child_ctx = ${this.vars.get_each_context}(#ctx, ${this.vars.each_block_value}, #i); let key = ${get_key}(child_ctx); ${lookup}.set(key, ${iterations}[#i] = ${create_each_block}(key, child_ctx)); } @@ -393,7 +397,7 @@ export default class EachBlockWrapper extends Wrapper { ${this.block.has_outros && `@group_outros();`} ${this.node.has_animation && `for (let #i = 0; #i < ${view_length}; #i += 1) ${iterations}[#i].r();`} - ${iterations} = @update_keyed_each(${iterations}, changed, ${get_key}, ${dynamic ? '1' : '0'}, ctx, ${this.vars.each_block_value}, ${lookup}, ${update_mount_node}, ${destroy}, ${create_each_block}, ${update_anchor_node}, ${this.vars.get_each_context}); + ${iterations} = @update_keyed_each(${iterations}, changed, ${get_key}, ${dynamic ? '1' : '0'}, #ctx, ${this.vars.each_block_value}, ${lookup}, ${update_mount_node}, ${destroy}, ${create_each_block}, ${update_anchor_node}, ${this.vars.get_each_context}); ${this.node.has_animation && `for (let #i = 0; #i < ${view_length}; #i += 1) ${iterations}[#i].a();`} ${this.block.has_outros && `@check_outros();`} `); @@ -432,7 +436,6 @@ export default class EachBlockWrapper extends Wrapper { }) { const { create_each_block, - length, iterations, fixed_length, data_length, @@ -443,7 +446,7 @@ export default class EachBlockWrapper extends Wrapper { let ${iterations} = []; for (let #i = 0; #i < ${data_length}; #i += 1) { - ${iterations}[#i] = ${create_each_block}(${this.vars.get_each_context}(ctx, ${this.vars.each_block_value}, #i)); + ${iterations}[#i] = ${create_each_block}(${this.vars.get_each_context}(#ctx, ${this.vars.each_block_value}, #i)); } `); @@ -473,13 +476,19 @@ export default class EachBlockWrapper extends Wrapper { all_dependencies.add(dependency); }); - const condition = Array.from(all_dependencies) - .map(dependency => `changed.${dependency}`) - .join(' || '); + let condition; + if (all_dependencies.size > 0) { + // TODO make this more elegant somehow? + const array = Array.from(all_dependencies); + let condition = x`#changed.${array[0]}`; + for (let i = 1; i < array.length; i += 1) { + condition = x`${condition} || #changed.${array[i]}`; + } + } const has_transitions = !!(this.block.has_intro_method || this.block.has_outro_method); - if (condition !== '') { + if (condition) { const for_loop_body = this.block.has_update_method ? b` if (${iterations}[#i]) { @@ -525,17 +534,17 @@ export default class EachBlockWrapper extends Wrapper { `); remove_old_blocks = b` @group_outros(); - for (#i = ${this.vars.each_block_value}.${length}; #i < ${view_length}; #i += 1) { + for (#i = ${data_length}; #i < ${view_length}; #i += 1) { ${out}(#i); } @check_outros(); `; } else { remove_old_blocks = b` - for (${this.block.has_update_method ? `` : `#i = ${this.vars.each_block_value}.${length}`}; #i < ${this.block.has_update_method ? view_length : '#old_length'}; #i += 1) { + for (${this.block.has_update_method ? `` : `#i = ${data_length}`}; #i < ${this.block.has_update_method ? view_length : '#old_length'}; #i += 1) { ${iterations}[#i].d(1); } - ${!fixed_length && `${view_length} = ${this.vars.each_block_value}.${length};`} + ${!fixed_length && `${view_length} = ${data_length};`} `; } @@ -546,8 +555,8 @@ export default class EachBlockWrapper extends Wrapper { ${this.vars.each_block_value} = ${snippet}; let #i; - for (#i = ${start}; #i < ${this.vars.each_block_value}.${length}; #i += 1) { - const child_ctx = ${this.vars.get_each_context}(ctx, ${this.vars.each_block_value}, #i); + for (#i = ${start}; #i < ${data_length}; #i += 1) { + const child_ctx = ${this.vars.get_each_context}(#ctx, ${this.vars.each_block_value}, #i); ${for_loop_body} } diff --git a/src/compiler/compile/render_dom/wrappers/shared/Tag.ts b/src/compiler/compile/render_dom/wrappers/shared/Tag.ts index 902074aab722..38ba3f2411ca 100644 --- a/src/compiler/compile/render_dom/wrappers/shared/Tag.ts +++ b/src/compiler/compile/render_dom/wrappers/shared/Tag.ts @@ -1,4 +1,4 @@ -import { b } from 'code-red'; +import { b, x } from 'code-red'; import Wrapper from './Wrapper'; import Renderer from '../../Renderer'; import Block from '../../Block'; @@ -29,16 +29,20 @@ export default class Tag extends Wrapper { if (this.node.should_cache) block.add_variable(value, snippet); // TODO may need to coerce snippet to string if (dependencies.length > 0) { - const changed_check = ( - (block.has_outros ? `!#current || ` : '') + - dependencies.map((dependency: string) => `changed.${dependency}`).join(' || ') - ); + let condition = x`#changed.${dependencies[0]}`; + for (let i = 1; i < dependencies.length; i += 1) { + condition = x`${condition} || #changed.${dependencies[i]}`; + } - const update_cached_value = `${value} !== (${value} = ${snippet} + "")`; + if (block.has_outros) { + condition = x`!#current || ${condition}`; + } - const condition = this.node.should_cache - ? `(${changed_check}) && ${update_cached_value}` - : changed_check; + const update_cached_value = x`${value} !== (${value} = ${snippet} + "")`; + + if (this.node.should_cache) { + condition = x`${condition} && ${update_cached_value}`; + } block.chunks.update.push(b`if (${condition}) ${update(content as Node)}`); } diff --git a/src/runtime/internal/Component.ts b/src/runtime/internal/Component.ts index ae80ae38c1f3..5b9007b6bcba 100644 --- a/src/runtime/internal/Component.ts +++ b/src/runtime/internal/Component.ts @@ -102,6 +102,7 @@ export function init(component, options, instance, create_fragment, not_equal, p $$.ctx = instance ? instance(component, props, (key, ret, value = ret) => { + console.log(`invalidating`, key, ret, value); if ($$.ctx && not_equal($$.ctx[key], $$.ctx[key] = value)) { if ($$.bound[key]) $$.bound[key](value); if (ready) make_dirty(component, key); From af1057b4a3e0db7e62e0afb692fb4c62bdbe3ac2 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Thu, 12 Sep 2019 12:53:31 -0400 Subject: [PATCH 11/93] various --- package-lock.json | 10 +- src/compiler/compile/Component.ts | 16 +-- src/compiler/compile/create_module.ts | 3 +- src/compiler/compile/nodes/Binding.ts | 5 +- src/compiler/compile/nodes/EventHandler.ts | 8 +- src/compiler/compile/render_dom/Block.ts | 4 +- src/compiler/compile/render_dom/index.ts | 105 +++++++++++------- .../compile/render_dom/wrappers/DebugTag.ts | 4 +- .../render_dom/wrappers/Element/Binding.ts | 4 +- .../render_dom/wrappers/Element/index.ts | 8 +- .../wrappers/InlineComponent/index.ts | 16 +-- .../compile/render_dom/wrappers/Slot.ts | 8 +- .../compile/render_dom/wrappers/Window.ts | 31 +++--- .../wrappers/shared/add_event_handlers.ts | 49 ++++---- .../render_dom/wrappers/shared/bind_this.ts | 18 +-- .../compile/render_ssr/handlers/Element.ts | 2 +- src/compiler/compile/utils/invalidate.ts | 5 +- src/runtime/internal/Component.ts | 1 - test/runtime/samples/action-this/main.svelte | 2 +- test/runtime/samples/action-update/_config.js | 2 +- 20 files changed, 167 insertions(+), 134 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5e7b60bdc7ee..827178a325c7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -330,11 +330,6 @@ "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", "dev": true }, - "astring": { - "version": "github:Rich-Harris/astring#ff83f5e4e75b304cdd428ada4a71372276b0084d", - "from": "github:Rich-Harris/astring#generic-handler", - "dev": true - }, "async-limiter": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", @@ -513,13 +508,16 @@ "dev": true, "requires": { "acorn": "^7.0.0", - "astring": "github:Rich-Harris/astring#ff83f5e4e75b304cdd428ada4a71372276b0084d", "estree-walker": "^0.6.1", "is-reference": "^1.1.3", "periscopic": "^1.0.0", "source-map": "^0.7.3" }, "dependencies": { + "astring": { + "version": "github:Rich-Harris/astring#ff83f5e4e75b304cdd428ada4a71372276b0084d", + "from": "github:Rich-Harris/astring#ff83f5e4e75b304cdd428ada4a71372276b0084d" + }, "estree-walker": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz", diff --git a/src/compiler/compile/Component.ts b/src/compiler/compile/Component.ts index 7f61df306a3e..7711fd268471 100644 --- a/src/compiler/compile/Component.ts +++ b/src/compiler/compile/Component.ts @@ -912,11 +912,13 @@ export default class Component { computed: false, kind: 'init', key: declarator.id, - value: { - type: 'AssignmentPattern', - left: declarator.id, - right: declarator.init - } + value: declarator.init + ? { + type: 'AssignmentPattern', + left: declarator.id, + right: declarator.init + } + : declarator.id }] }; @@ -1228,7 +1230,7 @@ export default class Component { } qualify(name) { - if (name === `$$props`) return `#ctx.$$props`; + if (name === `$$props`) return x`#ctx.$$props`; const variable = this.var_lookup.get(name); @@ -1238,7 +1240,7 @@ export default class Component { if (variable.hoistable) return name; - return `#ctx.${name}`; + return x`#ctx.${name}`; } warn_if_undefined(name: string, node, template_scope: TemplateScope) { diff --git a/src/compiler/compile/create_module.ts b/src/compiler/compile/create_module.ts index 73ab84bdc196..0a70b42f2d0f 100644 --- a/src/compiler/compile/create_module.ts +++ b/src/compiler/compile/create_module.ts @@ -173,7 +173,8 @@ function cjs( shorthand: false, computed: false, key: s.imported || { type: 'Identifier', name: 'default' }, - value: s.local + value: s.local, + kind: 'init' })) }, init: x`require("${edit_source(node.source.value, sveltePath)}")` diff --git a/src/compiler/compile/nodes/Binding.ts b/src/compiler/compile/nodes/Binding.ts index 949b0c657ce7..29992f940ff7 100644 --- a/src/compiler/compile/nodes/Binding.ts +++ b/src/compiler/compile/nodes/Binding.ts @@ -4,6 +4,7 @@ import Expression from './shared/Expression'; import Component from '../Component'; import TemplateScope from './shared/TemplateScope'; import {dimensions} from "../../utils/patterns"; +import { x } from 'code-red'; // TODO this should live in a specific binding const read_only_media_attributes = new Set([ @@ -68,8 +69,8 @@ export default class Binding extends Node { if (!this.expression.node.computed) prop = `'${prop}'`; obj = `[✂${this.expression.node.object.start}-${this.expression.node.object.end}✂]`; } else { - obj = '#ctx'; - prop = `'${name}'`; + obj = x`#ctx`; + prop = x`'${name}'`; } this.obj = obj; diff --git a/src/compiler/compile/nodes/EventHandler.ts b/src/compiler/compile/nodes/EventHandler.ts index 3abb2cff543f..0cd80005503f 100644 --- a/src/compiler/compile/nodes/EventHandler.ts +++ b/src/compiler/compile/nodes/EventHandler.ts @@ -1,7 +1,7 @@ import Node from './shared/Node'; import Expression from './shared/Expression'; import Component from '../Component'; -import { b } from 'code-red'; +import { b, x } from 'code-red'; import Block from '../render_dom/Block'; import { sanitize } from '../../utils/names'; import { Identifier } from '../../interfaces'; @@ -63,9 +63,11 @@ export default class EventHandler extends Node { // TODO move this? it is specific to render-dom render(block: Block) { - if (this.expression) this.expression.manipulate(block); + if (this.expression) { + return this.expression.manipulate(block); + } // this.component.add_reference(this.handler_name); - return `#ctx.${this.handler_name}`; + return x`#ctx.${this.handler_name}`; } } diff --git a/src/compiler/compile/render_dom/Block.ts b/src/compiler/compile/render_dom/Block.ts index f50b412f38a2..179c647ae15c 100644 --- a/src/compiler/compile/render_dom/Block.ts +++ b/src/compiler/compile/render_dom/Block.ts @@ -57,7 +57,7 @@ export default class Block { destroy: Node[]; }; - event_listeners: string[] = []; + event_listeners: Node[] = []; maintain_context: boolean; has_animation: boolean; @@ -430,7 +430,7 @@ export default class Block { } else { this.chunks.hydrate.push(b` ${dispose} = [ - ${this.event_listeners.join(',\n')} + ${this.event_listeners} ]; `); diff --git a/src/compiler/compile/render_dom/index.ts b/src/compiler/compile/render_dom/index.ts index 7d57a48f9115..5fd0d294ee5e 100644 --- a/src/compiler/compile/render_dom/index.ts +++ b/src/compiler/compile/render_dom/index.ts @@ -1,5 +1,4 @@ import { b, x } from 'code-red'; -import deindent from '../utils/deindent'; import { stringify, escape } from '../utils/stringify'; import Component from '../Component'; import Renderer from './Renderer'; @@ -99,44 +98,59 @@ export default function dom( const not_equal = component.component_options.immutable ? x`@not_equal` : x`@safe_not_equal`; let dev_props_check; let inject_state; let capture_state; - props.forEach(x => { - const variable = component.var_lookup.get(x.name); + props.forEach(prop => { + const variable = component.var_lookup.get(prop.name); if (!variable.writable || component.component_options.accessors) { - accessors.push(deindent` - get ${x.export_name}() { - return ${x.hoistable ? x.name : 'this.$$.ctx.' + x.name}; - } - `); + accessors.push({ + type: 'MethodDefinition', + kind: 'get', + key: { type: 'Identifier', name: prop.export_name }, + value: x`function() { + return ${prop.hoistable ? prop.name : x`this.$$.ctx.${prop.name}`} + }` + }); } else if (component.compile_options.dev) { - accessors.push(deindent` - get ${x.export_name}() { + accessors.push({ + type: 'MethodDefinition', + kind: 'get', + key: { type: 'Identifier', name: prop.export_name }, + value: x`function() { throw new @_Error("<${component.tag}>: Props cannot be read directly from the component instance unless compiling with 'accessors: true' or ''"); - } - `); + }` + }); } if (component.component_options.accessors) { - if (variable.writable && !renderer.readonly.has(x.name)) { - accessors.push(deindent` - set ${x.export_name}(${x.name}) { - this.$set({ ${x.name === x.export_name ? x.name : `${x.export_name}: ${x.name}`} }); + if (variable.writable && !renderer.readonly.has(prop.name)) { + accessors.push({ + type: 'MethodDefinition', + kind: 'set', + key: { type: 'Identifier', name: prop.export_name }, + value: x`function(${prop.name}) { + this.$set({ ${prop.export_name}: ${prop.name} }); @flush(); - } - `); + }` + }); } else if (component.compile_options.dev) { - accessors.push(deindent` - set ${x.export_name}(value) { - throw new @_Error("<${component.tag}>: Cannot set read-only property '${x.export_name}'"); - } - `); + accessors.push({ + type: 'MethodDefinition', + kind: 'set', + key: { type: 'Identifier', name: prop.export_name }, + value: x`function(value) { + throw new @_Error("<${component.tag}>: Cannot set read-only property '${prop.export_name}'"); + }` + }); } } else if (component.compile_options.dev) { - accessors.push(deindent` - set ${x.export_name}(value) { + accessors.push({ + type: 'MethodDefinition', + kind: 'set', + key: { type: 'Identifier', name: prop.export_name }, + value: x`function(value) { throw new @_Error("<${component.tag}>: Props cannot be set directly on the component instance unless compiling with 'accessors: true' or ''"); - } - `); + }` + }); } }); @@ -204,7 +218,7 @@ export default function dom( // onto the initial function call const names = new Set(extract_names(assignee)); - invalidate(component, scope, node, names); + this.replace(invalidate(component, scope, node, names)); } } }); @@ -405,7 +419,7 @@ export default function dom( }); if (options.customElement) { - body.push(b` + const declaration = b` class ${name} extends @SvelteElement { constructor(options) { super(); @@ -428,15 +442,24 @@ export default function dom( }`} } } + } + `[0]; + + if (props.length > 0) { + declaration.body.body.push({ + type: 'MethodDefinition', + kind: 'get', + static: true, + key: { type: 'Identifier', name: 'observedAttributes' }, + value: x`function() { + return [${props.map(prop => x`"${prop.export_name}"`)}]; + }` + }) + } - ${props.length > 0 && deindent` - static get observedAttributes() { - return ${JSON.stringify(props.map(x => x.export_name))}; - }`} + declaration.body.body.push(...accessors); - ${body.length > 0 && body.join('\n\n')} - } - `); + body.push(declaration); if (component.tag != null) { body.push(b` @@ -449,9 +472,7 @@ export default function dom( name: options.dev ? '@SvelteComponentDev' : '@SvelteComponent' }; - // TODO add accessors - - body.push(b` + const declaration = b` class ${name} extends ${superclass} { constructor(options) { super(${options.dev && `options`}); @@ -462,7 +483,11 @@ export default function dom( ${dev_props_check} } } - `); + `[0]; + + declaration.body.body.push(...accessors); + + body.push(declaration); } return flatten(body, []); diff --git a/src/compiler/compile/render_dom/wrappers/DebugTag.ts b/src/compiler/compile/render_dom/wrappers/DebugTag.ts index c7c0daf890f7..aa74f2f89dd0 100644 --- a/src/compiler/compile/render_dom/wrappers/DebugTag.ts +++ b/src/compiler/compile/render_dom/wrappers/DebugTag.ts @@ -63,7 +63,7 @@ export default class DebugTagWrapper extends Wrapper { // block.chunks.update.push(b` // if (${condition}) { - // const { ${ctx_identifiers} } = ctx; + // const { ${ctx_identifiers} } = #ctx; // @_console.${log}({ ${logged_identifiers} }); // debugger; // } @@ -71,7 +71,7 @@ export default class DebugTagWrapper extends Wrapper { // block.chunks.create.push(b` // { - // const { ${ctx_identifiers} } = ctx; + // const { ${ctx_identifiers} } = #ctx; // @_console.${log}({ ${logged_identifiers} }); // debugger; // } diff --git a/src/compiler/compile/render_dom/wrappers/Element/Binding.ts b/src/compiler/compile/render_dom/wrappers/Element/Binding.ts index 09426db67a99..994354037fb3 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/Binding.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/Binding.ts @@ -125,11 +125,11 @@ export default class BindingWrapper { const binding_group = get_binding_group(parent.renderer, this.node.expression.node); block.chunks.hydrate.push( - b`ctx.$$binding_groups[${binding_group}].push(${parent.var});` + b`#ctx.$$binding_groups[${binding_group}].push(${parent.var});` ); block.chunks.destroy.push( - b`ctx.$$binding_groups[${binding_group}].splice(ctx.$$binding_groups[${binding_group}].indexOf(${parent.var}), 1);` + b`#ctx.$$binding_groups[${binding_group}].splice(#ctx.$$binding_groups[${binding_group}].indexOf(${parent.var}), 1);` ); break; } diff --git a/src/compiler/compile/render_dom/wrappers/Element/index.ts b/src/compiler/compile/render_dom/wrappers/Element/index.ts index 4aac73aac7ba..f30fc912b630 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/index.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/index.ts @@ -480,21 +480,21 @@ export default class ElementWrapper extends Wrapper { ${animation_frame} = @raf(${handler}); ${needs_lock && `${lock} = true;`} } - ctx.${handler}.call(${this.var}${contextual_dependencies.size > 0 ? ', ctx' : ''}); + #ctx.${handler}.call(${this.var}${contextual_dependencies.size > 0 ? ', #ctx' : ''}); } `); } else { block.chunks.init.push(b` function ${handler}() { ${needs_lock && `${lock} = true;`} - ctx.${handler}.call(${this.var}${contextual_dependencies.size > 0 ? ', ctx' : ''}); + #ctx.${handler}.call(${this.var}${contextual_dependencies.size > 0 ? ', #ctx' : ''}); } `); } callee = handler; } else { - callee = `ctx.${handler}`; + callee = x`#ctx.${handler}`; } this.renderer.component.partly_hoisted.push(b` @@ -519,7 +519,7 @@ export default class ElementWrapper extends Wrapper { ); } else { block.event_listeners.push( - `@listen(${this.var}, "${name}", ${callee})` + x`@listen(${this.var}, "${name}", ${callee})` ); } }); diff --git a/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts b/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts index b8405b7df301..82c6862171f0 100644 --- a/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts +++ b/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts @@ -250,14 +250,14 @@ export default class InlineComponentWrapper extends Wrapper { } if (non_let_dependencies.length > 0) { - updates.push(`if (${non_let_dependencies.map(n => `changed.${n}`).join(' || ')}) ${name_changes}.$$scope = { changed, ctx };`); + updates.push(`if (${non_let_dependencies.map(n => `changed.${n}`).join(' || ')}) ${name_changes}.$$scope = { changed: #changed, ctx: #ctx };`); } const munged_bindings = this.node.bindings.map(binding => { component.has_reactive_assignments = true; if (binding.name === 'this') { - return bind_this(component, block, binding, this.var.name); + return bind_this(component, block, binding, this.var); } const id = component.get_unique_name(`${this.var}_${binding.name}_binding`); @@ -306,7 +306,7 @@ export default class InlineComponentWrapper extends Wrapper { block.chunks.init.push(b` function ${name}(${value}) { - ctx.${name}.call(null, ${value}, ctx); + #ctx.${name}.call(null, ${value}, #ctx); ${updating} = true; @add_flush_callback(() => ${updating} = false); } @@ -316,7 +316,7 @@ export default class InlineComponentWrapper extends Wrapper { } else { block.chunks.init.push(b` function ${id}(${value}) { - ctx.${name}.call(null, ${value}); + #ctx.${name}.call(null, ${value}); ${updating} = true; @add_flush_callback(() => ${updating} = false); } @@ -337,7 +337,7 @@ export default class InlineComponentWrapper extends Wrapper { const munged_handlers = this.node.handlers.map(handler => { let snippet = handler.render(block); - if (handler.modifiers.has('once')) snippet = `@once(${snippet})`; + if (handler.modifiers.has('once')) snippet = x`@once(${snippet})`; return `${name}.$on("${handler.name}", ${snippet});`; }); @@ -351,7 +351,7 @@ export default class InlineComponentWrapper extends Wrapper { block.chunks.init.push(b` var ${switch_value} = ${snippet}; - function ${switch_props}(ctx) { + function ${switch_props}(#ctx) { ${(this.node.attributes.length || this.node.bindings.length) && b` ${props && `let ${props} = ${attribute_object};`}`} ${statements} @@ -359,7 +359,7 @@ export default class InlineComponentWrapper extends Wrapper { } if (${switch_value}) { - var ${name} = new ${switch_value}(${switch_props}(ctx)); + var ${name} = new ${switch_value}(${switch_props}(#ctx)); ${munged_bindings} ${munged_handlers} @@ -403,7 +403,7 @@ export default class InlineComponentWrapper extends Wrapper { } if (${switch_value}) { - ${name} = new ${switch_value}(${switch_props}(ctx)); + ${name} = new ${switch_value}(${switch_props}(#ctx)); ${munged_bindings} ${munged_handlers} diff --git a/src/compiler/compile/render_dom/wrappers/Slot.ts b/src/compiler/compile/render_dom/wrappers/Slot.ts index 6bd1b24e07fc..aa05bd7fb904 100644 --- a/src/compiler/compile/render_dom/wrappers/Slot.ts +++ b/src/compiler/compile/render_dom/wrappers/Slot.ts @@ -110,8 +110,8 @@ export default class SlotWrapper extends Wrapper { const slot_definition = block.get_unique_name(`${sanitize(slot_name)}_slot_template`); 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 ${slot_definition} = #ctx.$$slots${quote_prop_if_necessary(slot_name)}; + const ${slot} = @create_slot(${slot_definition}, #ctx, ${get_slot_context}); `); const mount_before = block.chunks.mount.slice(); @@ -175,8 +175,8 @@ export default class SlotWrapper extends Wrapper { block.chunks.update.push(b` if (${slot} && ${slot}.p && ${update_conditions}) { ${slot}.p( - @get_slot_changes(${slot_definition}, ctx, changed, ${get_slot_changes}), - @get_slot_context(${slot_definition}, ctx, ${get_slot_context}) + @get_slot_changes(${slot_definition}, #ctx, changed, ${get_slot_changes}), + @get_slot_context(${slot_definition}, #ctx, ${get_slot_context}) ); } `); diff --git a/src/compiler/compile/render_dom/wrappers/Window.ts b/src/compiler/compile/render_dom/wrappers/Window.ts index 2bc6840a9d9d..bd7ea5441cf9 100644 --- a/src/compiler/compile/render_dom/wrappers/Window.ts +++ b/src/compiler/compile/render_dom/wrappers/Window.ts @@ -82,13 +82,12 @@ export default class WindowWrapper extends Wrapper { block.add_variable(clear_scrolling, x`() => { ${scrolling} = false }`); block.add_variable(scrolling_timeout); - const condition = [ - bindings.scrollX && `"${bindings.scrollX}" in this._state`, - bindings.scrollY && `"${bindings.scrollY}" in this._state` - ].filter(Boolean).join(' || '); + const condition = bindings.scrollX && bindings.scrollY + ? x`"${bindings.scrollX}" in this._state || "${bindings.scrollY}" in this._state` + : x`"${bindings.scrollX || bindings.scrollY}" in this._state`; - const scrollX = bindings.scrollX && `this._state.${bindings.scrollX}`; - const scrollY = bindings.scrollY && `this._state.${bindings.scrollY}`; + const scrollX = bindings.scrollX && x`this._state.${bindings.scrollX}`; + const scrollY = bindings.scrollY && x`this._state.${bindings.scrollY}`; renderer.meta_bindings.push(b` if (${condition}) { @@ -98,12 +97,12 @@ export default class WindowWrapper extends Wrapper { ${scrollY && `${scrollY} = @_window.pageYOffset;`} `); - block.event_listeners.push(b` + block.event_listeners.push(x` @listen(@_window, "${event}", () => { ${scrolling} = true; @_clearTimeout(${scrolling_timeout}); ${scrolling_timeout} = @_setTimeout(${clear_scrolling}, 100); - ctx.${id}(); + #ctx.${id}(); }) `); } else { @@ -113,8 +112,8 @@ export default class WindowWrapper extends Wrapper { ); }); - block.event_listeners.push(b` - @listen(@_window, "${event}", ctx.${id}) + block.event_listeners.push(x` + @listen(@_window, "${event}", #ctx.${id}) `); } @@ -131,7 +130,7 @@ export default class WindowWrapper extends Wrapper { `); block.chunks.init.push(b` - @add_render_callback(ctx.${id}); + @add_render_callback(#ctx.${id}); `); component.has_reactive_assignments = true; @@ -148,9 +147,9 @@ export default class WindowWrapper extends Wrapper { ${scrolling} = true; @_clearTimeout(${scrolling_timeout}); @_scrollTo(${ - bindings.scrollX ? `ctx.${bindings.scrollX}` : `@_window.pageXOffset` + bindings.scrollX ? `#ctx.${bindings.scrollX}` : `@_window.pageXOffset` }, ${ - bindings.scrollY ? `ctx.${bindings.scrollY}` : `@_window.pageYOffset` + bindings.scrollY ? `#ctx.${bindings.scrollY}` : `@_window.pageYOffset` }); ${scrolling_timeout} = @_setTimeout(${clear_scrolling}, 100); } @@ -175,12 +174,12 @@ export default class WindowWrapper extends Wrapper { `); block.chunks.init.push(b` - @add_render_callback(ctx.${id}); + @add_render_callback(#ctx.${id}); `); block.event_listeners.push( - `@listen(@_window, "online", ctx.${id})`, - `@listen(@_window, "offline", ctx.${id})` + x`@listen(@_window, "online", #ctx.${id})`, + x`@listen(@_window, "offline", #ctx.${id})` ); component.has_reactive_assignments = true; diff --git a/src/compiler/compile/render_dom/wrappers/shared/add_event_handlers.ts b/src/compiler/compile/render_dom/wrappers/shared/add_event_handlers.ts index 3f39f3314676..588611de6021 100644 --- a/src/compiler/compile/render_dom/wrappers/shared/add_event_handlers.ts +++ b/src/compiler/compile/render_dom/wrappers/shared/add_event_handlers.ts @@ -1,5 +1,6 @@ import Block from '../../Block'; import EventHandler from '../../../nodes/EventHandler'; +import { x } from 'code-red'; export default function add_event_handlers( block: Block, @@ -8,35 +9,37 @@ export default function add_event_handlers( ) { handlers.forEach(handler => { let snippet = handler.render(block); - if (handler.modifiers.has('preventDefault')) snippet = `@prevent_default(${snippet})`; - if (handler.modifiers.has('stopPropagation')) snippet = `@stop_propagation(${snippet})`; - if (handler.modifiers.has('self')) snippet = `@self(${snippet})`; + if (handler.modifiers.has('preventDefault')) snippet = x`@prevent_default(${snippet})`; + if (handler.modifiers.has('stopPropagation')) snippet = x`@stop_propagation(${snippet})`; + if (handler.modifiers.has('self')) snippet = x`@self(${snippet})`; - let opts_string = ''; + // let opts_string = ''; - if (block.renderer.options.dev) { - if (handler.modifiers.has('stopPropagation')) { - opts_string = ', true'; - } + // if (block.renderer.options.dev) { + // if (handler.modifiers.has('stopPropagation')) { + // opts_string = ', true'; + // } - if (handler.modifiers.has('preventDefault')) { - opts_string = ', true' + opts_string; - } else if (opts_string) { - opts_string = ', false' + opts_string; - } - } + // if (handler.modifiers.has('preventDefault')) { + // opts_string = ', true' + opts_string; + // } else if (opts_string) { + // opts_string = ', false' + opts_string; + // } + // } - const opts = ['passive', 'once', 'capture'].filter(mod => handler.modifiers.has(mod)); - if (opts.length) { - opts_string = (opts.length === 1 && opts[0] === 'capture') - ? ', true' - : `, { ${opts.map(opt => `${opt}: true`).join(', ')} }`; - } else if (opts_string) { - opts_string = ', false' + opts_string; - } + // const opts = ['passive', 'once', 'capture'].filter(mod => handler.modifiers.has(mod)); + // if (opts.length) { + // opts_string = (opts.length === 1 && opts[0] === 'capture') + // ? ', true' + // : `, { ${opts.map(opt => `${opt}: true`).join(', ')} }`; + // } else if (opts_string) { + // opts_string = ', false' + opts_string; + // } + + // TODO modifiers block.event_listeners.push( - `@listen(${target}, "${handler.name}", ${snippet}${opts_string})` + x`@listen(${target}, "${handler.name}", ${snippet})` ); }); } 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 24dd2b39723a..63d280e87bb4 100644 --- a/src/compiler/compile/render_dom/wrappers/shared/bind_this.ts +++ b/src/compiler/compile/render_dom/wrappers/shared/bind_this.ts @@ -5,8 +5,8 @@ import Block from '../../Block'; import Binding from '../../../nodes/Binding'; import { Identifier } from '../../../../interfaces'; -export default function bind_this(component: Component, block: Block, binding: Binding, variable: string) { - const fn = component.get_unique_name(`${variable}_binding`); +export default function bind_this(component: Component, block: Block, binding: Binding, variable: Identifier) { + const fn = component.get_unique_name(`${variable.name}_binding`); component.add_var({ name: fn.name, @@ -56,18 +56,18 @@ export default function bind_this(component: Component, block: Block, binding: B for (const arg of contextual_dependencies) { const id: Identifier = { type: 'Identifier', name: arg }; args.push(id); - block.add_variable(id, x`ctx.${id}`); + block.add_variable(id, x`#ctx.${id}`); } const assign = block.get_unique_name(`assign_${variable}`); const unassign = block.get_unique_name(`unassign_${variable}`); block.chunks.init.push(b` - const ${assign} = () => ctx.${fn}(${[variable].concat(args).join(', ')}); - const ${unassign} = () => ctx.${fn}(${['null'].concat(args).join(', ')}); + const ${assign} = () => #ctx.${fn}(${[variable].concat(args).join(', ')}); + const ${unassign} = () => #ctx.${fn}(${['null'].concat(args).join(', ')}); `); - const condition = Array.from(contextual_dependencies).map(name => `${name} !== ctx.${name}`).join(' || '); + const condition = Array.from(contextual_dependencies).map(name => `${name} !== #ctx.${name}`).join(' || '); // we push unassign and unshift assign so that references are // nulled out before they're created, to avoid glitches @@ -75,7 +75,7 @@ export default function bind_this(component: Component, block: Block, binding: B block.chunks.update.push(b` if (${condition}) { ${unassign}(); - ${args.map(a => `${a} = ctx.${a}`).join(', ')}; + ${args.map(a => `${a} = #ctx.${a}`).join(', ')}; ${assign}(); }` ); @@ -92,6 +92,6 @@ export default function bind_this(component: Component, block: Block, binding: B } `); - block.chunks.destroy.push(b`ctx.${fn}(null);`); - return b`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/handlers/Element.ts b/src/compiler/compile/render_ssr/handlers/Element.ts index 146324f2a40a..1b56a509394b 100644 --- a/src/compiler/compile/render_ssr/handlers/Element.ts +++ b/src/compiler/compile/render_ssr/handlers/Element.ts @@ -85,7 +85,7 @@ export default function(node: Element, renderer: Renderer, options: RenderOption const class_expression = node.classes.map((class_directive: Class) => { const { expression, name } = class_directive; - const snippet = expression ? snip(expression) : `ctx${quote_prop_if_necessary(name)}`; + const snippet = expression ? snip(expression) : `#ctx${quote_prop_if_necessary(name)}`; return `${snippet} ? "${name}" : ""`; }).join(', '); diff --git a/src/compiler/compile/utils/invalidate.ts b/src/compiler/compile/utils/invalidate.ts index 053e64bf3e8f..b21c9c7816c8 100644 --- a/src/compiler/compile/utils/invalidate.ts +++ b/src/compiler/compile/utils/invalidate.ts @@ -55,7 +55,10 @@ export function invalidate(component: Component, scope: Scope, node: Node, names ); if (pass_value) { - extra_args.unshift(head); + extra_args.unshift({ + type: 'Identifier', + name: head + }); } return x`$$invalidate("${head}", ${node}, ${extra_args})`; diff --git a/src/runtime/internal/Component.ts b/src/runtime/internal/Component.ts index 5b9007b6bcba..ae80ae38c1f3 100644 --- a/src/runtime/internal/Component.ts +++ b/src/runtime/internal/Component.ts @@ -102,7 +102,6 @@ export function init(component, options, instance, create_fragment, not_equal, p $$.ctx = instance ? instance(component, props, (key, ret, value = ret) => { - console.log(`invalidating`, key, ret, value); if ($$.ctx && not_equal($$.ctx[key], $$.ctx[key] = value)) { if ($$.bound[key]) $$.bound[key](value); if (ready) make_dirty(component, key); diff --git a/test/runtime/samples/action-this/main.svelte b/test/runtime/samples/action-this/main.svelte index 28d5444b321d..c7d74a8b9747 100644 --- a/test/runtime/samples/action-this/main.svelte +++ b/test/runtime/samples/action-this/main.svelte @@ -4,7 +4,7 @@ function foo(node) { const handler = () => { x += 1; - } + }; node.addEventListener('click', handler); handler(); diff --git a/test/runtime/samples/action-update/_config.js b/test/runtime/samples/action-update/_config.js index 305c890ca880..b5e90e4b1050 100644 --- a/test/runtime/samples/action-update/_config.js +++ b/test/runtime/samples/action-update/_config.js @@ -3,7 +3,7 @@ export default { `, - async test({ assert, component, target, window }) { + async test({ assert, target, window }) { const button = target.querySelector('button'); const enter = new window.MouseEvent('mouseenter'); const leave = new window.MouseEvent('mouseleave'); From e2d6ce1de5991f1b923df2b395c460067d530386 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Thu, 12 Sep 2019 14:35:37 -0400 Subject: [PATCH 12/93] various --- src/compiler/compile/render_dom/Block.ts | 2 +- .../compile/render_dom/wrappers/EachBlock.ts | 18 ++++++++---------- .../compile/render_dom/wrappers/IfBlock.ts | 2 +- .../render_dom/wrappers/shared/Wrapper.ts | 2 +- 4 files changed, 11 insertions(+), 13 deletions(-) diff --git a/src/compiler/compile/render_dom/Block.ts b/src/compiler/compile/render_dom/Block.ts index 179c647ae15c..65f32d072ded 100644 --- a/src/compiler/compile/render_dom/Block.ts +++ b/src/compiler/compile/render_dom/Block.ts @@ -394,7 +394,7 @@ export default class Block { } render() { - const key = this.key && { type: 'Identifier', name: this.get_unique_name('key') }; + const key = this.key && this.get_unique_name('key'); const args: any[] = [x`#ctx`]; diff --git a/src/compiler/compile/render_dom/wrappers/EachBlock.ts b/src/compiler/compile/render_dom/wrappers/EachBlock.ts index afc9f678bd67..4fd26d82c96b 100644 --- a/src/compiler/compile/render_dom/wrappers/EachBlock.ts +++ b/src/compiler/compile/render_dom/wrappers/EachBlock.ts @@ -209,7 +209,7 @@ export default class EachBlockWrapper extends Wrapper { const initial_anchor_node: Identifier = { type: 'Identifier', name: parent_node ? 'null' : 'anchor' }; const initial_mount_node: Identifier = { type: 'Identifier', name: parent_node || '#target' }; const update_anchor_node = needs_anchor - ? block.get_unique_name(`${this.var}_anchor`) + ? block.get_unique_name(`${this.var.name}_anchor`) : (this.next && this.next.var) || { type: 'Identifier', name: 'null' }; const update_mount_node: Identifier = this.get_update_mount_node((update_anchor_node as Identifier)); @@ -333,7 +333,7 @@ export default class EachBlockWrapper extends Wrapper { } = this.vars; const get_key = block.get_unique_name('get_key'); - const lookup = block.get_unique_name(`${this.var}_lookup`); + const lookup = block.get_unique_name(`${this.var.name}_lookup`); block.add_variable(iterations, x`[]`); block.add_variable(lookup, x`new @_Map()`); @@ -351,9 +351,7 @@ export default class EachBlockWrapper extends Wrapper { } block.chunks.init.push(b` - const ${get_key} = #ctx => ${ - // @ts-ignore todo: probably error - this.node.key.render()}; + const ${get_key} = #ctx => ${this.node.key.manipulate(block)}; for (let #i = 0; #i < ${data_length}; #i += 1) { let child_ctx = ${this.vars.get_each_context}(#ctx, ${this.vars.each_block_value}, #i); @@ -395,11 +393,11 @@ export default class EachBlockWrapper extends Wrapper { block.chunks.update.push(b` const ${this.vars.each_block_value} = ${snippet}; - ${this.block.has_outros && `@group_outros();`} - ${this.node.has_animation && `for (let #i = 0; #i < ${view_length}; #i += 1) ${iterations}[#i].r();`} - ${iterations} = @update_keyed_each(${iterations}, changed, ${get_key}, ${dynamic ? '1' : '0'}, #ctx, ${this.vars.each_block_value}, ${lookup}, ${update_mount_node}, ${destroy}, ${create_each_block}, ${update_anchor_node}, ${this.vars.get_each_context}); - ${this.node.has_animation && `for (let #i = 0; #i < ${view_length}; #i += 1) ${iterations}[#i].a();`} - ${this.block.has_outros && `@check_outros();`} + ${this.block.has_outros && b`@group_outros();`} + ${this.node.has_animation && b`for (let #i = 0; #i < ${view_length}; #i += 1) ${iterations}[#i].r();`} + ${iterations} = @update_keyed_each(${iterations}, #changed, ${get_key}, ${dynamic ? '1' : '0'}, #ctx, ${this.vars.each_block_value}, ${lookup}, ${update_mount_node}, ${destroy}, ${create_each_block}, ${update_anchor_node}, ${this.vars.get_each_context}); + ${this.node.has_animation && b`for (let #i = 0; #i < ${view_length}; #i += 1) ${iterations}[#i].a();`} + ${this.block.has_outros && b`@check_outros();`} `); if (this.block.has_outros) { diff --git a/src/compiler/compile/render_dom/wrappers/IfBlock.ts b/src/compiler/compile/render_dom/wrappers/IfBlock.ts index 6dc6ff5f3305..86899c8ea315 100644 --- a/src/compiler/compile/render_dom/wrappers/IfBlock.ts +++ b/src/compiler/compile/render_dom/wrappers/IfBlock.ts @@ -177,7 +177,7 @@ export default class IfBlockWrapper extends Wrapper { const needs_anchor = this.next ? !this.next.is_dom_node() : !parent_node || !this.parent.is_dom_node(); const anchor = needs_anchor - ? block.get_unique_name(`${name}_anchor`) + ? block.get_unique_name(`${this.var.name}_anchor`) : (this.next && this.next.var) || 'null'; const has_else = !(this.branches[this.branches.length - 1].condition); diff --git a/src/compiler/compile/render_dom/wrappers/shared/Wrapper.ts b/src/compiler/compile/render_dom/wrappers/shared/Wrapper.ts index cad5b8423501..9fd7991ced93 100644 --- a/src/compiler/compile/render_dom/wrappers/shared/Wrapper.ts +++ b/src/compiler/compile/render_dom/wrappers/shared/Wrapper.ts @@ -49,7 +49,7 @@ export default class Wrapper { // children need to be created first const needs_anchor = this.next ? !this.next.is_dom_node() : !parent_node || !this.parent.is_dom_node(); const anchor = needs_anchor - ? block.get_unique_name(`${this.var}_anchor`) + ? block.get_unique_name(`${this.var.name}_anchor`) : (this.next && this.next.var) || { type: 'Identifier', name: 'null' }; if (needs_anchor) { From d731766f3488bab42f14ad264f7092b592b937e3 Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Thu, 12 Sep 2019 21:53:33 -0400 Subject: [PATCH 13/93] attributes and innerHTML --- src/compiler/compile/Component.ts | 5 + src/compiler/compile/nodes/Attribute.ts | 8 +- .../render_dom/wrappers/Element/Attribute.ts | 51 ++++---- .../wrappers/Element/StyleAttribute.ts | 62 +++++----- .../render_dom/wrappers/Element/index.ts | 111 ++++++++++++------ .../render_dom/wrappers/shared/changed.ts | 7 ++ test/runtime/index.js | 1 + 7 files changed, 150 insertions(+), 95 deletions(-) create mode 100644 src/compiler/compile/render_dom/wrappers/shared/changed.ts diff --git a/src/compiler/compile/Component.ts b/src/compiler/compile/Component.ts index 7711fd268471..b6d5eb49ca51 100644 --- a/src/compiler/compile/Component.ts +++ b/src/compiler/compile/Component.ts @@ -300,6 +300,11 @@ export default class Component { walk(program, { enter: (node) => { if (node.type === 'Identifier' && node.name[0] === '@') { + // TODO temp + if (!/@\w+$/.test(node.name)) { + throw new Error(`wut "${node.name}"`); + } + if (node.name[1] === '_') { const alias = this.global(node.name.slice(2)); node.name = alias.name; diff --git a/src/compiler/compile/nodes/Attribute.ts b/src/compiler/compile/nodes/Attribute.ts index 94dea766ad44..92b6dde40595 100644 --- a/src/compiler/compile/nodes/Attribute.ts +++ b/src/compiler/compile/nodes/Attribute.ts @@ -1,4 +1,4 @@ -import { stringify } from '../utils/stringify'; +import { stringify, string_literal } from '../utils/stringify'; import add_to_set from '../utils/add_to_set'; import Component from '../Component'; import Node from './shared/Node'; @@ -82,11 +82,9 @@ export default class Attribute extends Node { if (this.chunks.length === 0) return `""`; if (this.chunks.length === 1) { - return this.chunks[0].type === 'Text' - ? stringify((this.chunks[0] as Text).data) - // @ts-ignore todo: probably error - : this.chunks[0].render(block); + ? string_literal((this.chunks[0] as Text).data) + : (this.chunks[0] as Expression).manipulate(block); } return (this.chunks[0].type === 'Text' ? '' : `"" + `) + diff --git a/src/compiler/compile/render_dom/wrappers/Element/Attribute.ts b/src/compiler/compile/render_dom/wrappers/Element/Attribute.ts index 76da9f0de96e..0af686e443a6 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/Attribute.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/Attribute.ts @@ -3,9 +3,10 @@ import Block from '../../Block'; import fix_attribute_casing from './fix_attribute_casing'; import ElementWrapper from './index'; import { stringify } from '../../../utils/stringify'; -import { b } from 'code-red'; +import { b, x } from 'code-red'; import Expression from '../../../nodes/shared/Expression'; import Text from '../../../nodes/Text'; +import { changed } from '../shared/changed'; export default class AttributeWrapper { node: Attribute; @@ -80,14 +81,14 @@ export default class AttributeWrapper { // single {tag} — may be a non-string value = (this.node.chunks[0] as Expression).manipulate(block); } else { - // '{foo} {bar}' — treat as string concatenation - const prefix = this.node.chunks[0].type === 'Text' ? '' : `"" + `; - - const text = this.node.name === 'class' + value = this.node.name === 'class' ? this.get_class_name_text() - : this.render_chunks().join(' + '); + : this.render_chunks().reduce((lhs, rhs) => x`${lhs} + ${rhs}`) - value = `${prefix}${text}`; + // '{foo} {bar}' — treat as string concatenation + if (this.node.chunks[0].type !== 'Text') { + value = x`"" + ${value}`; + } } const is_select_value_attribute = @@ -96,19 +97,19 @@ export default class AttributeWrapper { const should_cache = (this.node.should_cache() || is_select_value_attribute); const last = should_cache && block.get_unique_name( - `${element.var}_${name.replace(/[^a-zA-Z_$]/g, '_')}_value` + `${element.var.name}_${name.replace(/[^a-zA-Z_$]/g, '_')}_value` ); if (should_cache) block.add_variable(last); let updater; - const init = should_cache ? `${last} = ${value}` : value; + const init = should_cache ? x`${last} = ${value}` : value; if (is_legacy_input_type) { block.chunks.hydrate.push( b`@set_input_type(${element.var}, ${init});` ); - updater = `@set_input_type(${element.var}, ${should_cache ? last : value});`; + updater = b`@set_input_type(${element.var}, ${should_cache ? last : value});`; } else if (is_select_value_attribute) { // annoying special case const is_multiple_select = element.node.get_static_attribute_value('multiple'); @@ -141,27 +142,29 @@ export default class AttributeWrapper { 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};`; + ? b`@prop_dev(${element.var}, "${property_name}", ${should_cache ? last : value});` + : b`${element.var}.${property_name} = ${should_cache ? last : value};`; } else { block.chunks.hydrate.push( b`${method}(${element.var}, "${name}", ${init});` ); - updater = `${method}(${element.var}, "${name}", ${should_cache ? last : value});`; + updater = b`${method}(${element.var}, "${name}", ${should_cache ? last : value});`; } - const changed_check = ( - (block.has_outros ? `!#current || ` : '') + - dependencies.map(dependency => `changed.${dependency}`).join(' || ') - ); + let condition = changed(dependencies); - const update_cached_value = `${last} !== (${last} = ${value})`; + if (should_cache) { + condition = x`${condition} && (${last} !== (${last} = ${value}))`; + } - const condition = should_cache - ? (dependencies.length ? `(${changed_check}) && ${update_cached_value}` : update_cached_value) - : changed_check; + if (block.has_outros) { + condition = x`!#current || ${condition}`; + } - block.chunks.update.push(b`if (${condition}) ${updater}`); + block.chunks.update.push(b` + if (${condition}) { + ${updater} + }`); } else { const value = this.node.get_value(block); @@ -195,10 +198,10 @@ export default class AttributeWrapper { if (scoped_css && rendered.length === 2) { // we have a situation like class={possiblyUndefined} - rendered[0] = `@null_to_empty(${rendered[0]})`; + rendered[0] = x`@null_to_empty(${rendered[0]})`; } - return rendered.join(' + '); + return rendered.reduce((lhs, rhs) => x`${lhs} + ${rhs}`); } render_chunks() { diff --git a/src/compiler/compile/render_dom/wrappers/Element/StyleAttribute.ts b/src/compiler/compile/render_dom/wrappers/Element/StyleAttribute.ts index 1bf8a341d46b..4da35952dcaf 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/StyleAttribute.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/StyleAttribute.ts @@ -1,4 +1,4 @@ -import { b } from 'code-red'; +import { b, x } from 'code-red'; import Attribute from '../../../nodes/Attribute'; import Block from '../../Block'; import AttributeWrapper from './Attribute'; @@ -7,6 +7,7 @@ import { stringify } from '../../../utils/stringify'; import add_to_set from '../../../utils/add_to_set'; import Expression from '../../../nodes/shared/Expression'; import Text from '../../../nodes/Text'; +import { changed } from '../shared/changed'; export interface StyleProp { key: string; @@ -26,42 +27,45 @@ export default class StyleAttributeWrapper extends AttributeWrapper { let value; if (is_dynamic(prop.value)) { - const prop_dependencies = new Set(); - - value = - ((prop.value.length === 1 || prop.value[0].type === 'Text') ? '' : `"" + `) + - prop.value - .map((chunk) => { - if (chunk.type === 'Text') { - return stringify(chunk.data); - } else { - const snippet = chunk.manipulate(); - - add_to_set(prop_dependencies, chunk.dynamic_dependencies()); - return snippet; - } - }) - .join(' + '); + const prop_dependencies: Set = new Set(); + + value = prop.value + .map(chunk => { + if (chunk.type === 'Text') { + return stringify(chunk.data); + } else { + const snippet = chunk.manipulate(block); + + add_to_set(prop_dependencies, chunk.dynamic_dependencies()); + return snippet; + } + }) + .reduce((lhs, rhs) => x`${lhs} + ${rhs}`) + + if (prop.value.length === 1 || prop.value[0].type === 'Text') { + value = x`"" + ${value}`; + } if (prop_dependencies.size) { - const dependencies = Array.from(prop_dependencies); - const condition = ( - (block.has_outros ? `!#current || ` : '') + - dependencies.map(dependency => `changed.${dependency}`).join(' || ') - ); - - block.chunks.update.push( - b`if (${condition}) { - @set_style(${this.parent.var}, "${prop.key}", ${value}${prop.important ? ', 1' : ''}); - }` - ); + let condition = changed(Array.from(prop_dependencies)); + + if (block.has_outros) { + condition = x`!#current || ${condition}`; + } + + const update = b` + if (${condition}) { + @set_style(${this.parent.var}, "${prop.key}", ${value}, ${prop.important ? 1 : null}); + }`; + + block.chunks.update.push(update); } } else { value = stringify((prop.value[0] as Text).data); } block.chunks.hydrate.push( - b`@set_style(${this.parent.var}, "${prop.key}", ${value}${prop.important ? ', 1' : ''});` + 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 f30fc912b630..48b749848fc3 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/index.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/index.ts @@ -4,7 +4,7 @@ import Wrapper from '../shared/Wrapper'; import Block from '../../Block'; import { is_void, quote_prop_if_necessary, quote_name_if_necessary, sanitize } from '../../../../utils/names'; import FragmentWrapper from '../Fragment'; -import { escape_html, escape, string_literal } from '../../../utils/stringify'; +import { escape_html, string_literal } from '../../../utils/stringify'; import TextWrapper from '../Text'; import fix_attribute_casing from './fix_attribute_casing'; import { b, x } from 'code-red'; @@ -294,14 +294,24 @@ export default class ElementWrapper extends Wrapper { b`${node}.textContent = ${string_literal(this.fragment.nodes[0].data)};` ); } else { - const inner_html = escape( - this.fragment.nodes - .map(to_html) - .join('') - ); + const state = { + quasi: { + type: 'TemplateElement', + value: { raw: '' } + } + }; + + const literal = { + type: 'TemplateLiteral', + expressions: [], + quasis: [] + }; + + to_html((this.fragment.nodes as unknown as (ElementWrapper | TextWrapper)[]), block, literal, state); + literal.quasis.push(state.quasi); block.chunks.create.push( - b`${node}.innerHTML = \`${inner_html}\`;` + b`${node}.innerHTML = ${literal};` ); } } else { @@ -338,36 +348,6 @@ export default class ElementWrapper extends Wrapper { ); } - function to_html(wrapper: ElementWrapper | TextWrapper) { - if (wrapper.node.type === 'Text') { - if ((wrapper as TextWrapper).use_space()) return ' '; - - const parent = wrapper.node.parent as Element; - - const raw = parent && ( - parent.name === 'script' || - parent.name === 'style' - ); - - return (raw ? wrapper.node.data : escape_html(wrapper.node.data)) - .replace(/\\/g, '\\\\') - .replace(/`/g, '\\`') - .replace(/\$/g, '\\$'); - } - - if (wrapper.node.name === 'noscript') return ''; - - let open = `<${wrapper.node.name}`; - - (wrapper as ElementWrapper).attributes.forEach((attr: AttributeWrapper) => { - open += ` ${fix_attribute_casing(attr.node.name)}${attr.stringify()}`; - }); - - if (is_void(wrapper.node.name)) return open + '>'; - - return `${open}>${(wrapper as ElementWrapper).fragment.nodes.map(to_html).join('')}`; - } - if (renderer.options.dev) { const loc = renderer.locate(this.node.start); block.chunks.hydrate.push( @@ -836,3 +816,60 @@ export default class ElementWrapper extends Wrapper { }); } } + +function to_html(wrappers: (ElementWrapper | TextWrapper)[], block: Block, literal: any, state: any) { + wrappers.forEach(wrapper => { + if (wrapper.node.type === 'Text') { + if ((wrapper as TextWrapper).use_space()) state.quasi.value.raw += ' '; + + const parent = wrapper.node.parent as Element; + + const raw = parent && ( + parent.name === 'script' || + parent.name === 'style' + ); + + state.quasi.value.raw += (raw ? wrapper.node.data : escape_html(wrapper.node.data)) + .replace(/\\/g, '\\\\') + .replace(/`/g, '\\`') + .replace(/\$/g, '\\$'); + } + + else if (wrapper.node.name === 'noscript') { + // do nothing + } + + else { + // element + state.quasi.value.raw += `<${wrapper.node.name}`; + + (wrapper as ElementWrapper).attributes.forEach((attr: AttributeWrapper) => { + state.quasi.value.raw += ` ${fix_attribute_casing(attr.node.name)}="`; + + attr.node.chunks.forEach(chunk => { + if (chunk.type === 'Text') { + state.quasi.value.raw += chunk.data; + } else { + literal.quasis.push(state.quasi); + literal.expressions.push(chunk.manipulate(block)) + + state.quasi = { + type: 'TemplateElement', + value: { raw: '' } + }; + } + }); + + state.quasi.value.raw += `"`; + }); + + state.quasi.value.raw += '>'; + + if (!is_void(wrapper.node.name)) { + to_html((wrapper as ElementWrapper).fragment.nodes as (ElementWrapper | TextWrapper)[], block, literal, state); + + state.quasi.value.raw += ``; + } + } + }); +} \ No newline at end of file diff --git a/src/compiler/compile/render_dom/wrappers/shared/changed.ts b/src/compiler/compile/render_dom/wrappers/shared/changed.ts new file mode 100644 index 000000000000..b7dc12e53fbb --- /dev/null +++ b/src/compiler/compile/render_dom/wrappers/shared/changed.ts @@ -0,0 +1,7 @@ +import { x } from 'code-red'; + +export function changed(dependencies: string[]) { + return dependencies + .map(d => x`#changed.${d}`) + .reduce((lhs, rhs) => x`${lhs} || ${rhs}`); +} \ No newline at end of file diff --git a/test/runtime/index.js b/test/runtime/index.js index b08f7c88e0c1..c3583ddccf60 100644 --- a/test/runtime/index.js +++ b/test/runtime/index.js @@ -65,6 +65,7 @@ describe.only("runtime", () => { unhandled_rejection = null; + config.preserveIdentifiers = true; // TODO remove later compile = (config.preserveIdentifiers ? svelte : svelte$).compile; const cwd = path.resolve(`test/runtime/samples/${dir}`); From 605c5d271cedd36a3bab71a9efb41240a437d50a Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Fri, 13 Sep 2019 08:33:39 -0400 Subject: [PATCH 14/93] various --- src/compiler/compile/Component.ts | 5 ++ src/compiler/compile/render_dom/Block.ts | 11 +-- src/compiler/compile/render_dom/index.ts | 20 ++++- .../render_dom/wrappers/Element/Attribute.ts | 8 +- .../render_dom/wrappers/Element/Binding.ts | 82 ++++++++---------- .../render_dom/wrappers/Element/index.ts | 28 +++--- .../wrappers/InlineComponent/index.ts | 86 +++++++++++++------ .../compile/render_dom/wrappers/Title.ts | 2 +- 8 files changed, 141 insertions(+), 101 deletions(-) diff --git a/src/compiler/compile/Component.ts b/src/compiler/compile/Component.ts index b6d5eb49ca51..29e05c79879f 100644 --- a/src/compiler/compile/Component.ts +++ b/src/compiler/compile/Component.ts @@ -299,6 +299,11 @@ export default class Component { walk(program, { enter: (node) => { + if (node.type === 'Identifier' && !('name' in node)) { + console.log(node); + throw new Error('wtf'); + } + if (node.type === 'Identifier' && node.name[0] === '@') { // TODO temp if (!/@\w+$/.test(node.name)) { diff --git a/src/compiler/compile/render_dom/Block.ts b/src/compiler/compile/render_dom/Block.ts index 65f32d072ded..386611df7956 100644 --- a/src/compiler/compile/render_dom/Block.ts +++ b/src/compiler/compile/render_dom/Block.ts @@ -202,11 +202,6 @@ export default class Block { } add_variable(id: Identifier, init?: Node) { - if (id.name[0] === '#') { - // TODO is this still necessary? - id.name = this.alias(id.name.slice(1)).name; - } - this.variables.forEach(v => { if (v.id.name === id.name) { throw new Error( @@ -371,8 +366,7 @@ export default class Block { // TODO should code-red do this automatically? probably return_value.properties = return_value.properties.filter(prop => prop.value); - /* eslint-disable @typescript-eslint/indent,indent */ - return b` + const body = b` ${Array.from(this.variables.values()).map(({ id, init }) => { return init ? b`let ${id} = ${init}` @@ -390,7 +384,8 @@ export default class Block { return ${return_value};` } `; - /* eslint-enable @typescript-eslint/indent,indent */ + + return body; } render() { diff --git a/src/compiler/compile/render_dom/index.ts b/src/compiler/compile/render_dom/index.ts index 5fd0d294ee5e..8b4a3024dab8 100644 --- a/src/compiler/compile/render_dom/index.ts +++ b/src/compiler/compile/render_dom/index.ts @@ -4,7 +4,6 @@ import Component from '../Component'; import Renderer from './Renderer'; import { CompileOptions } from '../../interfaces'; import { walk } from 'estree-walker'; -import { stringify_props } from '../utils/stringify_props'; import add_to_set from '../utils/add_to_set'; import { extract_names } from '../utils/scope'; import { invalidate } from '../utils/invalidate'; @@ -372,6 +371,19 @@ export default function dom( `; } + const return_value = { + type: 'ObjectExpression', + properties: filtered_declarations.map(name => { + const id = { type: 'Identifier', name }; + return { + type: 'Property', + key: id, + value: id, + kind: 'init' + }; + }) + }; + body.push(b` function ${definition}(${args.join(', ')}) { ${reactive_store_declarations.length > 0 && `let ${reactive_store_declarations.join(', ')};`} @@ -406,7 +418,7 @@ export default function dom( ${fixed_reactive_declarations} - return ${stringify_props(filtered_declarations)}; + return ${return_value}; } `); } @@ -476,9 +488,9 @@ export default function dom( class ${name} extends ${superclass} { constructor(options) { super(${options.dev && `options`}); - ${should_add_css && `if (!@_document.getElementById("${component.stylesheet.id}-style")) ${add_css}();`} + ${should_add_css && b`if (!@_document.getElementById("${component.stylesheet.id}-style")) ${add_css}();`} @init(this, options, ${definition}, create_fragment, ${not_equal}, ${prop_names}); - ${options.dev && `@dispatch_dev("SvelteRegisterComponent", { component: this, tagName: "${name}", options, id: create_fragment.name });`} + ${options.dev && b`@dispatch_dev("SvelteRegisterComponent", { component: this, tagName: "${name}", options, id: create_fragment.name });`} ${dev_props_check} } diff --git a/src/compiler/compile/render_dom/wrappers/Element/Attribute.ts b/src/compiler/compile/render_dom/wrappers/Element/Attribute.ts index 0af686e443a6..8c1891aa320d 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/Attribute.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/Attribute.ts @@ -2,7 +2,7 @@ import Attribute from '../../../nodes/Attribute'; import Block from '../../Block'; import fix_attribute_casing from './fix_attribute_casing'; import ElementWrapper from './index'; -import { stringify } from '../../../utils/stringify'; +import { string_literal } from '../../../utils/stringify'; import { b, x } from 'code-red'; import Expression from '../../../nodes/shared/Expression'; import Text from '../../../nodes/Text'; @@ -172,8 +172,8 @@ export default class AttributeWrapper { is_legacy_input_type ? b`@set_input_type(${element.var}, ${value});` : property_name - ? b`${element.var}.${property_name} = ${value};` - : b`${method}(${element.var}, "${name}", ${value === true ? '""' : value});` + ? b`${element.var}.${property_name} = ${value === true ? { type: 'Literal', value: true } : value};` + : b`${method}(${element.var}, "${name}", ${value === true ? x`""` : value});` ); block.chunks.hydrate.push(statement); @@ -207,7 +207,7 @@ export default class AttributeWrapper { render_chunks() { return this.node.chunks.map((chunk) => { if (chunk.type === 'Text') { - return stringify(chunk.data); + return string_literal(chunk.data); } return chunk.manipulate(); diff --git a/src/compiler/compile/render_dom/wrappers/Element/Binding.ts b/src/compiler/compile/render_dom/wrappers/Element/Binding.ts index 994354037fb3..4ad6ae1a0d9a 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/Binding.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/Binding.ts @@ -8,12 +8,7 @@ import Renderer from '../../Renderer'; import flatten_reference from '../../../utils/flatten_reference'; import EachBlock from '../../../nodes/EachBlock'; import { Node as INode, Identifier } from '../../../../interfaces'; - -function get_tail(node: INode) { - const end = node.end; - while (node.type === 'MemberExpression') node = node.object; - return { start: node.end, end }; -} +import { changed } from '../shared/changed'; export default class BindingWrapper { node: Binding; @@ -22,9 +17,9 @@ export default class BindingWrapper { object: string; handler: { uses_context: boolean; - mutation: string; + mutation: Node; contextual_dependencies: Set; - snippet?: string; + snippet?: Node; }; snippet: INode; is_readonly: boolean; @@ -59,7 +54,7 @@ export default class BindingWrapper { // TODO unfortunate code is necessary because we need to use `ctx` // inside the fragment, but not inside the '; -function get_context(parser: Parser, attributes: Node[], start: number) { +function get_context(parser: Parser, attributes: any[], start: number): string { const context = attributes.find(attribute => attribute.name === 'context'); if (!context) return 'default'; @@ -28,7 +29,7 @@ function get_context(parser: Parser, attributes: Node[], start: number) { return value; } -export default function read_script(parser: Parser, start: number, attributes: Node[]) { +export default function read_script(parser: Parser, start: number, attributes: Node[]) : Script { const script_start = parser.index; const script_end = parser.template.indexOf(script_closing_tag, script_start); @@ -41,7 +42,7 @@ export default function read_script(parser: Parser, start: number, attributes: N repeat(' ', script_start) + parser.template.slice(script_start, script_end); parser.index = script_end + script_closing_tag.length; - let ast; + let ast: Program; try { ast = acorn.parse(source); @@ -49,8 +50,11 @@ export default function read_script(parser: Parser, start: number, attributes: N parser.acorn_error(err); } - ast.start = script_start; + // TODO is this necessary? + (ast as any).start = script_start; + return { + type: 'Script', start, end: parser.index, context: get_context(parser, attributes, start), diff --git a/src/compiler/parse/read/style.ts b/src/compiler/parse/read/style.ts index a14356e05bad..4a16475d6b19 100644 --- a/src/compiler/parse/read/style.ts +++ b/src/compiler/parse/read/style.ts @@ -1,9 +1,10 @@ import parse from 'css-tree/lib/parser/index.js'; import { walk } from 'estree-walker'; import { Parser } from '../index'; -import { Node } from '../../interfaces'; +import { Node } from 'estree'; +import { Style } from '../../interfaces'; -export default function read_style(parser: Parser, start: number, attributes: Node[]) { +export default function read_style(parser: Parser, start: number, attributes: Node[]): Style { const content_start = parser.index; const styles = parser.read_until(/<\/style>/); const content_end = parser.index; @@ -30,7 +31,7 @@ export default function read_style(parser: Parser, start: number, attributes: No // tidy up AST walk(ast, { - enter: (node: Node) => { + enter: (node: any) => { // `any` because this isn't an ESTree node // replace `ref:a` nodes if (node.type === 'Selector') { for (let i = 0; i < node.children.length; i += 1) { @@ -58,6 +59,7 @@ export default function read_style(parser: Parser, start: number, attributes: No const end = parser.index; return { + type: 'Style', start, end, attributes, @@ -65,12 +67,12 @@ export default function read_style(parser: Parser, start: number, attributes: No content: { start: content_start, end: content_end, - styles, - }, + styles + } }; } -function is_ref_selector(a: Node, b: Node) { +function is_ref_selector(a: any, b: any) { // TODO add CSS node types if (!b) return false; return ( diff --git a/src/compiler/parse/state/mustache.ts b/src/compiler/parse/state/mustache.ts index 8de35cee4834..4a1578ada5d4 100644 --- a/src/compiler/parse/state/mustache.ts +++ b/src/compiler/parse/state/mustache.ts @@ -4,9 +4,9 @@ import { closing_tag_omitted } from '../utils/html'; import { whitespace } from '../../utils/patterns'; import { trim_start, trim_end } from '../../utils/trim'; import { Parser } from '../index'; -import { Node } from '../../interfaces'; +import { TemplateNode } from '../../interfaces'; -function trim_whitespace(block: Node, trim_before: boolean, trim_after: boolean) { +function trim_whitespace(block: TemplateNode, trim_before: boolean, trim_after: boolean) { if (!block.children || block.children.length === 0) return; // AwaitBlock const first_child = block.children[0]; @@ -175,7 +175,7 @@ export default function mustache(parser: Parser) { parser.eat('}', true); } - const then_block: Node = { + const then_block: TemplateNode = { start, end: null, type: 'ThenBlock', @@ -200,7 +200,7 @@ export default function mustache(parser: Parser) { parser.eat('}', true); } - const catch_block: Node = { + const catch_block: TemplateNode = { start, end: null, type: 'CatchBlock', @@ -232,7 +232,7 @@ export default function mustache(parser: Parser) { const expression = read_expression(parser); - const block: Node = type === 'AwaitBlock' ? + const block: TemplateNode = type === 'AwaitBlock' ? { start, end: null, diff --git a/src/compiler/parse/state/tag.ts b/src/compiler/parse/state/tag.ts index 21a7b3caea37..6b187d141b7b 100644 --- a/src/compiler/parse/state/tag.ts +++ b/src/compiler/parse/state/tag.ts @@ -4,7 +4,7 @@ import read_style from '../read/style'; import { decode_character_references, closing_tag_omitted } from '../utils/html'; import { is_void } from '../../utils/names'; import { Parser } from '../index'; -import { Directive, DirectiveType, Node, Text } from '../../interfaces'; +import { Directive, DirectiveType, TemplateNode, Text } from '../../interfaces'; import fuzzymatch from '../../utils/fuzzymatch'; import list from '../../utils/list'; @@ -112,7 +112,7 @@ export default function tag(parser: Parser) { : name === 'title' && parent_is_head(parser.stack) ? 'Title' : name === 'slot' && !parser.customElement ? 'Slot' : 'Element'; - const element: Node = { + const element: TemplateNode = { start, end: null, // filled in later type, @@ -406,7 +406,7 @@ function read_attribute(parser: Parser, unique_names: Set) { end: directive.end, type: 'Identifier', name: directive.name - }; + } as any; } return directive; @@ -447,7 +447,7 @@ function read_attribute_value(parser: Parser) { return value; } -function read_sequence(parser: Parser, done: () => boolean): Node[] { +function read_sequence(parser: Parser, done: () => boolean): TemplateNode[] { let current_chunk: Text = { start: parser.index, end: null, @@ -464,7 +464,7 @@ function read_sequence(parser: Parser, done: () => boolean): Node[] { } } - const chunks: Node[] = []; + const chunks: TemplateNode[] = []; while (parser.index < parser.template.length) { const index = parser.index; From fe7d0d371be0d1e9223be0459b71783e374ce3f8 Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Sat, 14 Sep 2019 22:12:32 -0400 Subject: [PATCH 20/93] ... --- src/compiler/compile/Component.ts | 2 +- src/compiler/compile/render_dom/index.ts | 79 ++++++++++--------- .../render_dom/wrappers/Element/Attribute.ts | 3 +- .../compile/render_dom/wrappers/IfBlock.ts | 19 ++--- .../wrappers/InlineComponent/index.ts | 58 ++++++++------ .../render_dom/wrappers/shared/bind_this.ts | 12 +-- .../compile/utils/flatten_reference.ts | 2 +- src/compiler/compile/utils/snip.ts | 2 +- 8 files changed, 98 insertions(+), 79 deletions(-) diff --git a/src/compiler/compile/Component.ts b/src/compiler/compile/Component.ts index 4262b07fddcb..59f2e2a33e7a 100644 --- a/src/compiler/compile/Component.ts +++ b/src/compiler/compile/Component.ts @@ -838,7 +838,7 @@ export default class Component { } if (value) { - return `$$invalidate('${name}', ${value})`; + return x`$$invalidate('${name}', ${value})`; } // if this is a reactive declaration, invalidate dependencies recursively diff --git a/src/compiler/compile/render_dom/index.ts b/src/compiler/compile/render_dom/index.ts index fedbbbf4630c..ac9d33f95a07 100644 --- a/src/compiler/compile/render_dom/index.ts +++ b/src/compiler/compile/render_dom/index.ts @@ -1,4 +1,4 @@ -import { b, x } from 'code-red'; +import { b, x, p } from 'code-red'; import { stringify, escape } from '../utils/stringify'; import Component from '../Component'; import Renderer from './Renderer'; @@ -8,7 +8,7 @@ import add_to_set from '../utils/add_to_set'; import { extract_names } from '../utils/scope'; import { invalidate } from '../utils/invalidate'; import Block from './Block'; -import { ClassDeclaration, FunctionExpression } from 'estree'; +import { ClassDeclaration, FunctionExpression, Node } from 'estree'; export default function dom( component: Component, @@ -82,12 +82,12 @@ export default function dom( const set = (uses_props || writable_props.length > 0 || component.slots.size > 0) ? x` ${$$props} => { - ${uses_props && component.invalidate('$$props', b`$$props = @assign(@assign({}, $$props), $$new_props)`)} + ${uses_props && component.invalidate('$$props', x`$$props = @assign(@assign({}, $$props), $$new_props)`)} ${writable_props.map(prop => b`if ('${prop.export_name}' in ${$$props}) ${component.invalidate(prop.name, `${prop.name} = ${$$props}.${prop.export_name}`)};` )} ${component.slots.size > 0 && - b`if ('$$scope' in ${$$props}) ${component.invalidate('$$scope', `$$scope = ${$$props}.$$scope`)};`} + b`if ('$$scope' in ${$$props}) ${component.invalidate('$$scope', x`$$scope = ${$$props}.$$scope`)};`} } ` : null; @@ -261,9 +261,9 @@ export default function dom( const filtered_declarations = component.vars .filter(v => ((v.referenced || v.export_name) && !v.hoistable)) - .map(v => v.name); + .map(v => p`${v.name}`); - if (uses_props) filtered_declarations.push(`$$props: $$props = ${component.helper('exclude_internal_props')}($$props)`); + if (uses_props) filtered_declarations.push(p`$$props: $$props = ${component.helper('exclude_internal_props')}($$props)`); const filtered_props = props.filter(prop => { const variable = component.var_lookup.get(prop.name); @@ -276,11 +276,11 @@ export default function dom( const reactive_stores = component.vars.filter(variable => variable.name[0] === '$' && variable.name[1] !== '$'); if (component.slots.size > 0) { - filtered_declarations.push('$$slots', '$$scope'); + filtered_declarations.push(p`$$slots`, p`$$scope`); } if (renderer.binding_groups.length > 0) { - filtered_declarations.push(`$$binding_groups`); + filtered_declarations.push(p`$$binding_groups`); } const has_definition = ( @@ -319,31 +319,30 @@ export default function dom( .map(({ name }) => `$$self.$$.on_destroy.push(() => $$unsubscribe_${name.slice(1)}());`); if (has_definition) { - const reactive_declarations = []; + const reactive_declarations: (Node | Node[]) = []; const fixed_reactive_declarations = []; // not really 'reactive' but whatever - component.reactive_declarations - .forEach(_d => { - // const dependencies = Array.from(d.dependencies); - // const uses_props = !!dependencies.find(n => n === '$$props'); - - // const condition = !uses_props && dependencies - // .filter(n => { - // const variable = component.var_lookup.get(n); - // return variable && (variable.writable || variable.mutated); - // }) - // .map(n => `$$dirty.${n}`).join(' || '); - - throw new Error(`bad`); - // let snippet = `[✂${d.node.body.start}-${d.node.end}✂]`; - // if (condition) snippet = `if (${condition}) { ${snippet} }`; - - // if (condition || uses_props) { - // reactive_declarations.push(snippet); - // } else { - // fixed_reactive_declarations.push(snippet); - // } - }); + component.reactive_declarations.forEach(d => { + const dependencies = Array.from(d.dependencies); + const uses_props = !!dependencies.find(n => n === '$$props'); + + const condition = !uses_props && dependencies + .filter(n => { + const variable = component.var_lookup.get(n); + return variable && (variable.writable || variable.mutated); + }) + .map(n => x`$$dirty.${n}`) + .reduce((lhs, rhs) => x`${lhs} || ${rhs}`); + + let statement = d.node; + if (condition) statement = b`if (${condition}) { ${statement} }`[0]; + + if (condition || uses_props) { + reactive_declarations.push(statement); + } else { + fixed_reactive_declarations.push(statement); + } + }); const injected = Array.from(component.injected_reactive_declaration_vars).filter(name => { const variable = component.var_lookup.get(name); @@ -365,7 +364,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 = b` - const writable_props = [${writable_props.map(prop => `'${prop.export_name}'`).join(', ')}]; + const writable_props = [${writable_props.map(prop => `'${prop.export_name}'`)}]; @_Object.keys($$props).forEach(key => { if (!writable_props.includes(key) && !key.startsWith('$$')) @_console.warn(\`<${component.tag}> was created with unknown prop '\${key}'\`); }); @@ -374,13 +373,17 @@ export default function dom( const return_value = { type: 'ObjectExpression', - properties: filtered_declarations.map(name => { - const id = { type: 'Identifier', name }; + properties: filtered_declarations + }; + + const reactive_dependencies = { + type: 'ObjectPattern', + properties: Array.from(all_reactive_dependencies).map(name => { return { type: 'Property', - key: id, - value: id, - kind: 'init' + kind: 'init', + key: { type: 'Identifier', name }, + value: { type: 'Literal', value: 1 } }; }) }; @@ -412,7 +415,7 @@ export default function dom( ${injected.length && `let ${injected.join(', ')};`} ${reactive_declarations.length > 0 && b` - $$self.$$.update = ($$dirty = { ${Array.from(all_reactive_dependencies).map(n => `${n}: 1`).join(', ')} }) => { + $$self.$$.update = ($$dirty = ${reactive_dependencies}) => { ${reactive_declarations} }; `} diff --git a/src/compiler/compile/render_dom/wrappers/Element/Attribute.ts b/src/compiler/compile/render_dom/wrappers/Element/Attribute.ts index fbe273046fd0..3c28820a9e5b 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/Attribute.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/Attribute.ts @@ -7,6 +7,7 @@ import { b, x } from 'code-red'; import Expression from '../../../nodes/shared/Expression'; import Text from '../../../nodes/Text'; import { changed } from '../shared/changed'; +import { Literal } from 'estree'; export default class AttributeWrapper { node: Attribute; @@ -173,7 +174,7 @@ export default class AttributeWrapper { ? b`@set_input_type(${element.var}, ${value});` : property_name ? b`${element.var}.${property_name} = ${value};` - : b`${method}(${element.var}, "${name}", ${value});` + : b`${method}(${element.var}, "${name}", ${value.type === 'Literal' && (value as Literal).value === true ? x`""` : value});` ); block.chunks.hydrate.push(statement); diff --git a/src/compiler/compile/render_dom/wrappers/IfBlock.ts b/src/compiler/compile/render_dom/wrappers/IfBlock.ts index 595a04c32459..22aa83a5d783 100644 --- a/src/compiler/compile/render_dom/wrappers/IfBlock.ts +++ b/src/compiler/compile/render_dom/wrappers/IfBlock.ts @@ -341,8 +341,8 @@ export default class IfBlockWrapper extends Wrapper { const if_blocks = block.get_unique_name(`if_blocks`); const if_current_block_type_index = has_else - ? '' - : `if (~${current_block_type_index}) `; + ? nodes => nodes + : nodes => b`if (~${current_block_type_index}) { ${nodes} }`; block.add_variable(current_block_type_index); block.add_variable(name); @@ -350,7 +350,7 @@ export default class IfBlockWrapper extends Wrapper { /* eslint-disable @typescript-eslint/indent,indent */ block.chunks.init.push(b` const ${if_block_creators} = [ - ${this.branches.map(branch => branch.block.name).join(',\n')} + ${this.branches.map(branch => branch.block.name)} ]; const ${if_blocks} = []; @@ -393,9 +393,10 @@ export default class IfBlockWrapper extends Wrapper { const initial_mount_node = parent_node || '#target'; const anchor_node = parent_node ? 'null' : 'anchor'; - throw new Error(`womp womp`); block.chunks.mount.push( - b`${if_current_block_type_index}${if_blocks}[${current_block_type_index}].m(${initial_mount_node}, ${anchor_node});` + if_current_block_type_index( + b`${if_blocks}[${current_block_type_index}].m(${initial_mount_node}, ${anchor_node});` + ) ); if (this.needs_update) { @@ -442,7 +443,7 @@ export default class IfBlockWrapper extends Wrapper { let ${previous_block_index} = ${current_block_type_index}; ${current_block_type_index} = ${select_block_type}(#changed, #ctx); if (${current_block_type_index} === ${previous_block_index}) { - ${if_current_block_type_index}${if_blocks}[${current_block_type_index}].p(#changed, #ctx); + ${if_current_block_type_index(b`${if_blocks}[${current_block_type_index}].p(#changed, #ctx);`)} } else { ${change_block} } @@ -460,9 +461,9 @@ export default class IfBlockWrapper extends Wrapper { block.chunks.update.push(b`${name}.p(#changed, #ctx);`); } - block.chunks.destroy.push(b` - ${if_current_block_type_index}${if_blocks}[${current_block_type_index}].d(${detaching}); - `); + block.chunks.destroy.push( + if_current_block_type_index(b`${if_blocks}[${current_block_type_index}].d(${detaching});`) + ); } render_simple( diff --git a/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts b/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts index c07858314b3f..7f63716d46e0 100644 --- a/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts +++ b/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts @@ -3,7 +3,7 @@ import Renderer from '../../Renderer'; import Block from '../../Block'; import InlineComponent from '../../../nodes/InlineComponent'; import FragmentWrapper from '../Fragment'; -import { quote_name_if_necessary, quote_prop_if_necessary, sanitize } from '../../../../utils/names'; +import { quote_name_if_necessary, sanitize } from '../../../../utils/names'; import add_to_set from '../../../utils/add_to_set'; import { b, x } from 'code-red'; import Attribute from '../../../nodes/Attribute'; @@ -15,7 +15,7 @@ import TemplateScope from '../../../nodes/shared/TemplateScope'; import is_dynamic from '../shared/is_dynamic'; import bind_this from '../shared/bind_this'; import { changed } from '../shared/changed'; -import { Node, Identifier } from 'estree'; +import { Node, Identifier, Expression } from 'estree'; export default class InlineComponentWrapper extends Wrapper { var: Identifier; @@ -124,7 +124,7 @@ export default class InlineComponentWrapper extends Wrapper { const uses_spread = !!this.node.attributes.find(a => a.is_spread); - let attribute_object; + let attribute_object = x`{}`; if (this.node.attributes.length > 0 || this.node.bindings.length > 0 || this.slots.size > 0) { if (!uses_spread && this.node.bindings.length === 0) { @@ -165,7 +165,7 @@ export default class InlineComponentWrapper extends Wrapper { value: attr.get_value(block) } }).concat(initial_props.properties) - }; + } as Expression; } component_opts.properties.push({ @@ -175,13 +175,13 @@ export default class InlineComponentWrapper extends Wrapper { value: attribute_object }); } else { + props = block.get_unique_name(`${name.name}_props`); component_opts.properties.push({ type: 'Property', kind: 'init', key: { type: 'Identifier', name: 'props' }, value: props }); - props = block.get_unique_name(`${name}_props`); } } @@ -241,7 +241,7 @@ export default class InlineComponentWrapper extends Wrapper { const { name, dependencies } = attr; const condition = dependencies.size > 0 && (dependencies.size !== all_dependencies.size) - ? `(${Array.from(dependencies).map(d => `changed.${d}`).join(' || ')})` + ? changed(Array.from(dependencies)) : null; if (attr.is_spread) { @@ -254,16 +254,16 @@ export default class InlineComponentWrapper extends Wrapper { } changes.push(condition ? `${condition} && ${value_object}` : value_object); } else { - const obj = `{ ${quote_name_if_necessary(name)}: ${attr.get_value(block)} }`; + const obj = x`{ ${quote_name_if_necessary(name)}: ${attr.get_value(block)} }`; initial_props.push(obj); - changes.push(condition ? `${condition} && ${obj}` : `${levels}[${i}]`); + changes.push(condition ? x`${condition} && ${obj}` : x`${levels}[${i}]`); } }); block.chunks.init.push(b` const ${levels} = [ - ${initial_props.join(',\n')} + ${initial_props} ]; `); @@ -278,7 +278,7 @@ export default class InlineComponentWrapper extends Wrapper { updates.push(b` const ${name_changes} = ${condition} ? @get_spread_update(${levels}, [ - ${changes.join(',\n')} + ${changes} ]) : {} `); } else { @@ -293,7 +293,7 @@ export default class InlineComponentWrapper extends Wrapper { const condition = changed(dependencies); updates.push(b` - if (${condition}) ${name_changes}${quote_prop_if_necessary(attribute.name)} = ${attribute.get_value(block)}; + if (${condition}) ${name_changes}.${attribute.name} = ${attribute.get_value(block)}; `); } }); @@ -301,7 +301,10 @@ export default class InlineComponentWrapper extends Wrapper { } if (non_let_dependencies.length > 0) { - updates.push(b`if (${changed(non_let_dependencies)} ${name_changes}.$$scope = { changed: #changed, ctx: #ctx };`); + updates.push(b` + if (${changed(non_let_dependencies)}) { + ${name_changes}.$$scope = { changed: #changed, ctx: #ctx }; + }`); } const munged_bindings = this.node.bindings.map(binding => { @@ -311,7 +314,7 @@ export default class InlineComponentWrapper extends Wrapper { return bind_this(component, block, binding, this.var); } - const id = component.get_unique_name(`${this.var}_${binding.name}_binding`); + const id = component.get_unique_name(`${this.var.name}_${binding.name}_binding`); component.add_var({ name: id.name, @@ -326,13 +329,13 @@ export default class InlineComponentWrapper extends Wrapper { statements.push(b` if (${snippet} !== void 0) { - ${props}${quote_prop_if_necessary(binding.name)} = ${snippet}; + ${props}.${binding.name} = ${snippet}; }` ); updates.push(b` - if (!${updating} && ${[...binding.expression.dependencies].map((dependency: string) => `changed.${dependency}`).join(' || ')}) { - ${name_changes}${quote_prop_if_necessary(binding.name)} = ${snippet}; + if (!${updating} && ${changed(Array.from(binding.expression.dependencies))}) { + ${name_changes}.${binding.name} = ${snippet}; } `); @@ -353,11 +356,22 @@ export default class InlineComponentWrapper extends Wrapper { const value = block.get_unique_name('value'); const args: any[] = [value]; if (contextual_dependencies.length > 0) { - args.push(x`{ ${contextual_dependencies.join(', ')} }`); + args.push({ + type: 'ObjectPattern', + properties: contextual_dependencies.map(name => { + const id = { type: 'Identifier', name }; + return { + type: 'Property', + kind: 'init', + key: id, + value: id + }; + }) + }); block.chunks.init.push(b` - function ${name}(${value}) { - #ctx.${name}.call(null, ${value}, #ctx); + function ${id}(${value}) { + #ctx.${id}.call(null, ${value}, #ctx); ${updating} = true; @add_flush_callback(() => ${updating} = false); } @@ -367,7 +381,7 @@ export default class InlineComponentWrapper extends Wrapper { } else { block.chunks.init.push(b` function ${id}(${value}) { - #ctx.${name}.call(null, ${value}); + #ctx.${id}.call(null, ${value}); ${updating} = true; @add_flush_callback(() => ${updating} = false); } @@ -375,7 +389,7 @@ export default class InlineComponentWrapper extends Wrapper { } const body = b` - function ${id}(${args.join(', ')}) { + function ${id}(${args}) { ${lhs} = ${value}; ${component.invalidate(dependencies[0])}; } @@ -383,7 +397,7 @@ export default class InlineComponentWrapper extends Wrapper { component.partly_hoisted.push(body); - return `@binding_callbacks.push(() => @bind(${this.var}, '${binding.name}', ${id}));`; + return b`@binding_callbacks.push(() => @bind(${this.var}, '${binding.name}', ${id}));`; }); const munged_handlers = this.node.handlers.map(handler => { 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 382fedf212c5..2a4fab1473fb 100644 --- a/src/compiler/compile/render_dom/wrappers/shared/bind_this.ts +++ b/src/compiler/compile/render_dom/wrappers/shared/bind_this.ts @@ -44,7 +44,7 @@ export default function bind_this(component: Component, block: Block, binding: B if (contextual_dependencies.length) { component.partly_hoisted.push(b` - function ${fn}(${['$$value', ...contextual_dependencies].join(', ')}) { + function ${fn}(${['$$value', ...contextual_dependencies]}) { if (${lhs} === $$value) return; @binding_callbacks[$$value ? 'unshift' : 'push'](() => { ${body} @@ -59,12 +59,12 @@ export default function bind_this(component: Component, block: Block, binding: B block.add_variable(id, x`#ctx.${id}`); } - const assign = block.get_unique_name(`assign_${variable}`); - const unassign = block.get_unique_name(`unassign_${variable}`); + const assign = block.get_unique_name(`assign_${variable.name}`); + const unassign = block.get_unique_name(`unassign_${variable.name}`); block.chunks.init.push(b` - const ${assign} = () => #ctx.${fn}(${[variable].concat(args).join(', ')}); - const ${unassign} = () => #ctx.${fn}(${['null'].concat(args).join(', ')}); + const ${assign} = () => #ctx.${fn}(${[variable].concat(args)}); + const ${unassign} = () => #ctx.${fn}(${['null'].concat(args)}); `); const condition = Array.from(contextual_dependencies).map(name => `${name} !== #ctx.${name}`).join(' || '); @@ -75,7 +75,7 @@ export default function bind_this(component: Component, block: Block, binding: B block.chunks.update.push(b` if (${condition}) { ${unassign}(); - ${args.map(a => `${a} = #ctx.${a}`).join(', ')}; + ${args.map(a => b`${a} = #ctx.${a}`)}; ${assign}(); }` ); diff --git a/src/compiler/compile/utils/flatten_reference.ts b/src/compiler/compile/utils/flatten_reference.ts index 1a1d13d0a6cb..9ea42fd00a31 100644 --- a/src/compiler/compile/utils/flatten_reference.ts +++ b/src/compiler/compile/utils/flatten_reference.ts @@ -3,7 +3,7 @@ import { Node, Identifier } from 'estree'; export default function flatten_reference(node: Node) { // TODO temporary (#3539) if ((node as any).type === 'Expression') { - throw new Error('bad'); + throw new Error('flatten_reference bad'); } const nodes = []; diff --git a/src/compiler/compile/utils/snip.ts b/src/compiler/compile/utils/snip.ts index 7a2e12f8e5e7..87163b18d9bc 100644 --- a/src/compiler/compile/utils/snip.ts +++ b/src/compiler/compile/utils/snip.ts @@ -1,4 +1,4 @@ export function snip(expression) { - throw new Error(`bad`); + throw new Error(`snip bad`); return `[✂${expression.node.start}-${expression.node.end}✂]`; } \ No newline at end of file From e12a30ae50ab940e2e7601e05b7438409765c84e Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Sat, 14 Sep 2019 23:08:41 -0400 Subject: [PATCH 21/93] various --- .../compile/nodes/shared/Expression.ts | 14 +++++++--- .../compile/render_dom/wrappers/EachBlock.ts | 23 +++++----------- .../render_dom/wrappers/Element/index.ts | 3 +-- .../compile/render_dom/wrappers/IfBlock.ts | 7 ++--- .../wrappers/InlineComponent/index.ts | 18 +++++-------- .../compile/render_dom/wrappers/Slot.ts | 6 ++--- .../compile/render_dom/wrappers/Title.ts | 27 +++++++++++-------- test/test.js | 2 ++ 8 files changed, 48 insertions(+), 52 deletions(-) diff --git a/src/compiler/compile/nodes/shared/Expression.ts b/src/compiler/compile/nodes/shared/Expression.ts index 00fa38c890a7..39c106072822 100644 --- a/src/compiler/compile/nodes/shared/Expression.ts +++ b/src/compiler/compile/nodes/shared/Expression.ts @@ -238,9 +238,11 @@ export default class Expression { let contextual_dependencies: Set; const node = walk(this.node, { - enter(node: any, parent: any, key: string) { - // don't manipulate shorthand props twice - if (key === 'value' && parent.shorthand) return; + enter(node: any, parent: any) { + if (node.type === 'Property' && node.shorthand) { + node.value = JSON.parse(JSON.stringify(node.value)); + node.shorthand = false; + } if (map.has(node)) { scope = map.get(node); @@ -283,7 +285,7 @@ export default class Expression { } }, - leave(node: Node) { + leave(node: Node, parent: Node) { if (map.has(node)) scope = scope.parent; if (node === function_expression) { @@ -366,6 +368,10 @@ export default class Expression { function_expression = null; dependencies = null; contextual_dependencies = null; + + if (parent && parent.type === 'Property') { + parent.method = false; + } } if (node.type === 'AssignmentExpression' || node.type === 'UpdateExpression') { diff --git a/src/compiler/compile/render_dom/wrappers/EachBlock.ts b/src/compiler/compile/render_dom/wrappers/EachBlock.ts index 629e20ff8ded..d73d6dcffd2b 100644 --- a/src/compiler/compile/render_dom/wrappers/EachBlock.ts +++ b/src/compiler/compile/render_dom/wrappers/EachBlock.ts @@ -7,6 +7,7 @@ import FragmentWrapper from './Fragment'; import { b, x } from 'code-red'; import ElseBlock from '../../nodes/ElseBlock'; import { Identifier, Node } from 'estree'; +import { changed } from './shared/changed'; export class ElseBlockWrapper extends Wrapper { node: ElseBlock; @@ -268,7 +269,7 @@ export default class EachBlockWrapper extends Wrapper { if (this.else.block.has_update_method) { block.chunks.update.push(b` if (!${this.vars.data_length} && ${each_block_else}) { - ${each_block_else}.p(changed, #ctx); + ${each_block_else}.p(#changed, #ctx); } else if (!${this.vars.data_length}) { ${each_block_else} = ${this.else.block.name}(#ctx); ${each_block_else}.c(); @@ -473,23 +474,13 @@ export default class EachBlockWrapper extends Wrapper { all_dependencies.add(dependency); }); - let condition; - if (all_dependencies.size > 0) { - // TODO make this more elegant somehow? - const array = Array.from(all_dependencies); - let condition = x`#changed.${array[0]}`; - for (let i = 1; i < array.length; i += 1) { - condition = x`${condition} || #changed.${array[i]}`; - } - } - - const has_transitions = !!(this.block.has_intro_method || this.block.has_outro_method); + if (all_dependencies.size) { + const has_transitions = !!(this.block.has_intro_method || this.block.has_outro_method); - if (condition) { const for_loop_body = this.block.has_update_method ? b` if (${iterations}[#i]) { - ${iterations}[#i].p(changed, child_ctx); + ${iterations}[#i].p(#changed, child_ctx); ${has_transitions && b`@transition_in(${this.vars.iterations}[#i], 1);`} } else { ${iterations}[#i] = ${create_each_block}(child_ctx); @@ -541,7 +532,7 @@ export default class EachBlockWrapper extends Wrapper { for (${this.block.has_update_method ? `` : `#i = ${data_length}`}; #i < ${this.block.has_update_method ? view_length : '#old_length'}; #i += 1) { ${iterations}[#i].d(1); } - ${!fixed_length && `${view_length} = ${data_length};`} + ${!fixed_length && b`${view_length} = ${data_length};`} `; } @@ -562,7 +553,7 @@ export default class EachBlockWrapper extends Wrapper { `; block.chunks.update.push(b` - if (${condition}) { + if (${changed(Array.from(all_dependencies))}) { ${update} } `); diff --git a/src/compiler/compile/render_dom/wrappers/Element/index.ts b/src/compiler/compile/render_dom/wrappers/Element/index.ts index 30e1622a88dd..aa9ee0c04102 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/index.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/index.ts @@ -809,8 +809,7 @@ export default class ElementWrapper extends Wrapper { 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; + const condition = changed(all_dependencies); block.chunks.update.push(b` if (${condition}) { diff --git a/src/compiler/compile/render_dom/wrappers/IfBlock.ts b/src/compiler/compile/render_dom/wrappers/IfBlock.ts index 22aa83a5d783..85623896f1f4 100644 --- a/src/compiler/compile/render_dom/wrappers/IfBlock.ts +++ b/src/compiler/compile/render_dom/wrappers/IfBlock.ts @@ -10,6 +10,7 @@ import { b, x } from 'code-red'; import { walk } from 'estree-walker'; import { is_head } from './shared/is_head'; import { Identifier, Node } from 'estree'; +import { changed } from './shared/changed'; function is_else_if(node: ElseBlock) { return ( @@ -260,7 +261,7 @@ export default class IfBlockWrapper extends Wrapper { ? b` ${snippet && ( dependencies.length > 0 - ? b`if ((${condition} == null) || ${dependencies.map(n => `changed.${n}`).join(' || ')}) ${condition} = !!(${snippet})` + ? b`if ((${condition} == null) || ${changed(dependencies)}) ${condition} = !!(${snippet})` : b`if (${condition} == null) ${condition} = !!(${snippet})` )} if (${condition}) return ${block.name};` @@ -360,7 +361,7 @@ export default class IfBlockWrapper extends Wrapper { function ${select_block_type}(#changed, #ctx) { ${this.branches.map(({ dependencies, condition, snippet }, i) => condition ? b` - ${snippet && b`if ((${condition} == null) || ${dependencies.map(n => `changed.${n}`).join(' || ')}) ${condition} = !!(${snippet})`} + ${snippet && b`if ((${condition} == null) || ${changed(dependencies)}) ${condition} = !!(${snippet})`} if (${condition}) return ${String(i)};` : b`return ${i};`)} ${!has_else && b`return -1;`} @@ -516,7 +517,7 @@ export default class IfBlockWrapper extends Wrapper { `; if (branch.snippet) { - block.chunks.update.push(b`if (${branch.dependencies.map(n => `changed.${n}`).join(' || ')}) ${branch.condition} = ${branch.snippet}`); + block.chunks.update.push(b`if (${changed(branch.dependencies)}) ${branch.condition} = ${branch.snippet}`); } // no `p()` here — we don't want to update outroing nodes, diff --git a/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts b/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts index 7f63716d46e0..188e62f787b5 100644 --- a/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts +++ b/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts @@ -252,7 +252,7 @@ export default class InlineComponentWrapper extends Wrapper { if (attr.expression.node.type !== 'ObjectExpression') { value_object = x`@get_spread_object(${value})`; } - changes.push(condition ? `${condition} && ${value_object}` : value_object); + changes.push(condition ? x`${condition} && ${value_object}` : value_object); } else { const obj = x`{ ${quote_name_if_necessary(name)}: ${attr.get_value(block)} }`; initial_props.push(obj); @@ -404,7 +404,7 @@ export default class InlineComponentWrapper extends Wrapper { let snippet = handler.render(block); if (handler.modifiers.has('once')) snippet = x`@once(${snippet})`; - return `${name}.$on("${handler.name}", ${snippet});`; + return b`${name}.$on("${handler.name}", ${snippet});`; }); if (this.node.name === 'svelte:component') { @@ -418,7 +418,7 @@ export default class InlineComponentWrapper extends Wrapper { function ${switch_props}(#ctx) { ${(this.node.attributes.length || this.node.bindings.length) && b` - ${props && `let ${props} = ${attribute_object};`}`} + ${props && b`let ${props} = ${attribute_object};`}`} ${statements} return ${component_opts}; } @@ -479,6 +479,8 @@ export default class InlineComponentWrapper extends Wrapper { } else { ${name} = null; } + } else if (${switch_value}) { + ${updates.length && b`${name}.$set(${name_changes});`} } `); @@ -486,14 +488,6 @@ export default class InlineComponentWrapper extends Wrapper { if (${name}) @transition_in(${name}.$$.fragment, #local); `); - if (updates.length) { - block.chunks.update.push(b` - else if (${switch_value}) { - ${name}.$set(${name_changes}); - } - `); - } - block.chunks.outro.push( b`if (${name}) @transition_out(${name}.$$.fragment, #local);` ); @@ -501,7 +495,7 @@ export default class InlineComponentWrapper extends Wrapper { block.chunks.destroy.push(b`if (${name}) @destroy_component(${name}, ${parent_node ? null : 'detaching'});`); } else { const expression = this.node.name === 'svelte:self' - ? '__svelte:self__' // TODO conflict-proof this + ? component.name : component.qualify(this.node.name); block.chunks.init.push(b` diff --git a/src/compiler/compile/render_dom/wrappers/Slot.ts b/src/compiler/compile/render_dom/wrappers/Slot.ts index c49ffa2a7d09..db53685be089 100644 --- a/src/compiler/compile/render_dom/wrappers/Slot.ts +++ b/src/compiler/compile/render_dom/wrappers/Slot.ts @@ -11,6 +11,7 @@ import { stringify_props } from '../../utils/stringify_props'; import Expression from '../../nodes/shared/Expression'; import is_dynamic from './shared/is_dynamic'; import { Identifier } from 'estree'; +import { changed } from './shared/changed'; export default class SlotWrapper extends Wrapper { node: Slot; @@ -163,11 +164,8 @@ export default class SlotWrapper extends Wrapper { return is_dynamic(variable); }); - let update_conditions = dynamic_dependencies.map(name => `changed.${name}`).join(' || '); - if (dynamic_dependencies.length > 1) update_conditions = `(${update_conditions})`; - block.chunks.update.push(b` - if (${slot} && ${slot}.p && ${update_conditions}) { + if (${slot} && ${slot}.p && ${changed(dynamic_dependencies)}) { ${slot}.p( @get_slot_changes(${slot_definition}, #ctx, changed, ${get_slot_changes}), @get_slot_context(${slot_definition}, #ctx, ${get_slot_context}) diff --git a/src/compiler/compile/render_dom/wrappers/Title.ts b/src/compiler/compile/render_dom/wrappers/Title.ts index b7a0bcaa6b22..d8535173fa73 100644 --- a/src/compiler/compile/render_dom/wrappers/Title.ts +++ b/src/compiler/compile/render_dom/wrappers/Title.ts @@ -1,4 +1,4 @@ -import { b } from 'code-red'; +import { b, x } from 'code-red'; import Wrapper from './shared/Wrapper'; import Renderer from '../Renderer'; import Block from '../Block'; @@ -7,6 +7,7 @@ import { stringify } from '../../utils/stringify'; import add_to_set from '../../utils/add_to_set'; import Text from '../../nodes/Text'; import { Identifier } from 'estree'; +import { changed } from './shared/changed'; export default class TitleWrapper extends Wrapper { node: Title; @@ -28,7 +29,7 @@ export default class TitleWrapper extends Wrapper { if (is_dynamic) { let value; - const all_dependencies = new Set(); + const all_dependencies: Set = new Set(); // TODO some of this code is repeated in Tag.ts — would be good to // DRY it out if that's possible without introducing crazy indirection @@ -72,22 +73,26 @@ export default class TitleWrapper extends Wrapper { block.chunks.init.push( b`@_document.title = ${init};` ); + const updater = b`@_document.title = ${this.node.should_cache ? last : value};`; if (all_dependencies.size) { const dependencies = Array.from(all_dependencies); - const changed_check = ( - (block.has_outros ? `!#current || ` : '') + - dependencies.map(dependency => `changed.${dependency}`).join(' || ') - ); - const update_cached_value = `${last} !== (${last} = ${value})`; + let condition = changed(dependencies); + + if (block.has_outros) { + condition = x`!#current || ${condition}`; + } - const condition = this.node.should_cache ? - (dependencies.length ? `(${changed_check}) && ${update_cached_value}` : update_cached_value) : - changed_check; + if (this.node.should_cache) { + condition = x`${condition} && (${last} !== (${last} = ${value}))`; + } - block.chunks.update.push(b`if (${condition}) ${updater}`); + block.chunks.update.push(b` + if (${condition}) { + ${updater} + }`); } } else { const value = this.node.children.length > 0 diff --git a/test/test.js b/test/test.js index f18c01c149f2..9480ae7836c8 100644 --- a/test/test.js +++ b/test/test.js @@ -6,6 +6,8 @@ require('./setup'); require('./helpers'); require('../internal'); +console.clear(); + glob('*/index.js', { cwd: 'test' }).forEach((file) => { require('./' + file); }); From 9e1bc908d324b7ff35f1c0e7848a5de9ebfd43d7 Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Sun, 15 Sep 2019 00:08:56 -0400 Subject: [PATCH 22/93] ... --- src/compiler/compile/nodes/Element.ts | 2 +- src/compiler/compile/nodes/InlineComponent.ts | 2 +- src/compiler/compile/nodes/Let.ts | 11 ++-- src/compiler/compile/render_dom/index.ts | 14 ++--- .../wrappers/InlineComponent/index.ts | 2 +- .../compile/render_dom/wrappers/Slot.ts | 26 +++++---- .../wrappers/shared/get_context_merger.ts | 29 ++++++++-- .../compile/render_ssr/handlers/Slot.ts | 4 +- src/compiler/compile/utils/get_slot_data.ts | 54 +++++++++++++------ 9 files changed, 98 insertions(+), 46 deletions(-) diff --git a/src/compiler/compile/nodes/Element.ts b/src/compiler/compile/nodes/Element.ts index 593f303a2fc5..2981741fa06c 100644 --- a/src/compiler/compile/nodes/Element.ts +++ b/src/compiler/compile/nodes/Element.ts @@ -201,7 +201,7 @@ export default class Element extends Node { this.scope = scope.child(); this.lets.forEach(l => { - const dependencies = new Set([l.name]); + const dependencies = new Set([l.name.name]); l.names.forEach(name => { this.scope.add(name, dependencies, this); diff --git a/src/compiler/compile/nodes/InlineComponent.ts b/src/compiler/compile/nodes/InlineComponent.ts index 6db6f1b32798..0bd1c9a6a712 100644 --- a/src/compiler/compile/nodes/InlineComponent.ts +++ b/src/compiler/compile/nodes/InlineComponent.ts @@ -90,7 +90,7 @@ export default class InlineComponent extends Node { this.scope = scope.child(); this.lets.forEach(l => { - const dependencies = new Set([l.name]); + const dependencies = new Set([l.name.name]); l.names.forEach(name => { this.scope.add(name, dependencies, this); diff --git a/src/compiler/compile/nodes/Let.ts b/src/compiler/compile/nodes/Let.ts index 8401d277eb92..1e8014285ac2 100644 --- a/src/compiler/compile/nodes/Let.ts +++ b/src/compiler/compile/nodes/Let.ts @@ -1,20 +1,21 @@ import Node from './shared/Node'; import Component from '../Component'; import { walk } from 'estree-walker'; +import { Identifier } from 'estree'; const applicable = new Set(['Identifier', 'ObjectExpression', 'ArrayExpression', 'Property']); export default class Let extends Node { type: 'Let'; - name: string; - value: string; + name: Identifier; + value: Identifier; names: string[] = []; constructor(component: Component, parent, scope, info) { super(component, parent, scope, info); - this.name = info.name; - this.value = info.expression && `[✂${info.expression.start}-${info.expression.end}✂]`; + this.name = { type: 'Identifier', name: info.name }; + this.value = info.expression.node; if (info.expression) { walk(info.expression, { @@ -32,7 +33,7 @@ export default class Let extends Node { } }); } else { - this.names.push(this.name); + this.names.push(this.name.name); } } } \ No newline at end of file diff --git a/src/compiler/compile/render_dom/index.ts b/src/compiler/compile/render_dom/index.ts index ac9d33f95a07..066a30563ee8 100644 --- a/src/compiler/compile/render_dom/index.ts +++ b/src/compiler/compile/render_dom/index.ts @@ -244,9 +244,9 @@ export default function dom( }); } - const args = ['$$self']; + const args = [x`$$self`]; if (props.length > 0 || component.has_reactive_assignments || component.slots.size > 0) { - args.push('$$props', '$$invalidate'); + args.push(x`$$props`, x`$$invalidate`); } body.push(b` @@ -355,10 +355,10 @@ export default function dom( const store = component.var_lookup.get(name); if (store && store.reassigned) { - return `${$name}, $$unsubscribe_${name} = @noop, $$subscribe_${name} = () => ($$unsubscribe_${name}(), $$unsubscribe_${name} = @subscribe(${name}, $$value => { ${$name} = $$value; $$invalidate('${$name}', ${$name}); }), ${name})`; + return b`let ${$name}, $$unsubscribe_${name} = @noop, $$subscribe_${name} = () => ($$unsubscribe_${name}(), $$unsubscribe_${name} = @subscribe(${name}, $$value => { ${$name} = $$value; $$invalidate('${$name}', ${$name}); }), ${name})`; } - return $name; + return b`let ${$name};`; }); let unknown_props_check; @@ -389,8 +389,8 @@ export default function dom( }; body.push(b` - function ${definition}(${args.join(', ')}) { - ${reactive_store_declarations.length > 0 && `let ${reactive_store_declarations.join(', ')};`} + function ${definition}(${args}) { + ${reactive_store_declarations} ${reactive_store_subscriptions} @@ -400,7 +400,7 @@ export default function dom( ${unknown_props_check} - ${component.slots.size && x`let { $$slots = {}, $$scope } = $$props;`} + ${component.slots.size && b`let { $$slots = {}, $$scope } = $$props;`} ${renderer.binding_groups.length > 0 && `const $$binding_groups = [${renderer.binding_groups.map(_ => `[]`).join(', ')}];`} diff --git a/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts b/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts index 188e62f787b5..5031bb8cde1a 100644 --- a/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts +++ b/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts @@ -19,7 +19,7 @@ import { Node, Identifier, Expression } from 'estree'; export default class InlineComponentWrapper extends Wrapper { var: Identifier; - slots: Map = new Map(); + slots: Map = new Map(); node: InlineComponent; fragment: FragmentWrapper; diff --git a/src/compiler/compile/render_dom/wrappers/Slot.ts b/src/compiler/compile/render_dom/wrappers/Slot.ts index db53685be089..f903e5cd2e88 100644 --- a/src/compiler/compile/render_dom/wrappers/Slot.ts +++ b/src/compiler/compile/render_dom/wrappers/Slot.ts @@ -3,14 +3,13 @@ import Renderer from '../Renderer'; import Block from '../Block'; import Slot from '../../nodes/Slot'; import FragmentWrapper from './Fragment'; -import { b } from 'code-red'; +import { b, p, x } from 'code-red'; import { sanitize } from '../../../utils/names'; import add_to_set from '../../utils/add_to_set'; import get_slot_data from '../../utils/get_slot_data'; -import { stringify_props } from '../../utils/stringify_props'; import Expression from '../../nodes/shared/Expression'; import is_dynamic from './shared/is_dynamic'; -import { Identifier } from 'estree'; +import { Identifier, ObjectExpression } from 'estree'; import { changed } from './shared/changed'; export default class SlotWrapper extends Wrapper { @@ -67,8 +66,8 @@ export default class SlotWrapper extends Wrapper { get_slot_changes = renderer.component.get_unique_name(`get_${sanitize(slot_name)}_slot_changes`); get_slot_context = renderer.component.get_unique_name(`get_${sanitize(slot_name)}_slot_context`); - const context_props = get_slot_data(this.node.values, false); - const changes_props = []; + const context = get_slot_data(this.node.values, false); + const changes = x`{}` as ObjectExpression; const dependencies = new Set(); @@ -92,15 +91,22 @@ export default class SlotWrapper extends Wrapper { }); if (dynamic_dependencies.length > 0) { - changes_props.push(`${attribute.name}: ${dynamic_dependencies.join(' || ')}`); + const expression = dynamic_dependencies + .map(name => ({ type: 'Identifier', name } as any)) + .reduce((lhs, rhs) => x`${lhs} || ${rhs}`); + + changes.properties.push(p`${attribute.name}: ${expression}`); } }); - const arg = dependencies.size > 0 ? `{ ${Array.from(dependencies).join(', ')} }` : ''; + const arg = dependencies.size > 0 && { + type: 'ObjectPattern', + properties: Array.from(dependencies).map(name => p`${name}`) + }; renderer.blocks.push(b` - const ${get_slot_changes} = (${arg}) => (${stringify_props(changes_props)}); - const ${get_slot_context} = (${arg}) => (${stringify_props(context_props)}); + const ${get_slot_changes} = (${arg}) => (${changes}); + const ${get_slot_context} = (${arg}) => (${context}); `); } else { get_slot_changes = 'null'; @@ -167,7 +173,7 @@ export default class SlotWrapper extends Wrapper { block.chunks.update.push(b` if (${slot} && ${slot}.p && ${changed(dynamic_dependencies)}) { ${slot}.p( - @get_slot_changes(${slot_definition}, #ctx, changed, ${get_slot_changes}), + @get_slot_changes(${slot_definition}, #ctx, #changed, ${get_slot_changes}), @get_slot_context(${slot_definition}, #ctx, ${get_slot_context}) ); } diff --git a/src/compiler/compile/render_dom/wrappers/shared/get_context_merger.ts b/src/compiler/compile/render_dom/wrappers/shared/get_context_merger.ts index fafdd2895167..eeec59384761 100644 --- a/src/compiler/compile/render_dom/wrappers/shared/get_context_merger.ts +++ b/src/compiler/compile/render_dom/wrappers/shared/get_context_merger.ts @@ -1,9 +1,20 @@ import Let from '../../../nodes/Let'; +import { x } from 'code-red'; export function get_context_merger(lets: Let[]) { if (lets.length === 0) return null; - const input = lets.map(l => l.value ? `${l.name}: ${l.value}` : l.name).join(', '); + console.log(lets); + + const input = { + type: 'ObjectPattern', + properties: lets.map(l => ({ + type: 'Property', + kind: 'init', + key: l.name, + value: l.value || l.name + })) + }; const names = new Set(); lets.forEach(l => { @@ -12,7 +23,19 @@ export function get_context_merger(lets: Let[]) { }); }); - const output = Array.from(names).join(', '); + const output = { + type: 'ObjectExpression', + properties: Array.from(names).map(name => { + const id = { type: 'Identifier', name }; + + return { + type: 'Property', + kind: 'init', + key: id, + value: id + }; + }) + }; - return `({ ${input} }) => ({ ${output} })`; + return x`(${input}) => (${output})`; } \ No newline at end of file diff --git a/src/compiler/compile/render_ssr/handlers/Slot.ts b/src/compiler/compile/render_ssr/handlers/Slot.ts index ef0699ee80da..9eec56b359e1 100644 --- a/src/compiler/compile/render_ssr/handlers/Slot.ts +++ b/src/compiler/compile/render_ssr/handlers/Slot.ts @@ -8,9 +8,7 @@ export default function(node: Slot, renderer: Renderer, options: RenderOptions) const slot_data = get_slot_data(node.values, true); - const arg = slot_data.length > 0 ? `{ ${slot_data.join(', ')} }` : '{}'; - - renderer.append(`\${$$slots${prop} ? $$slots${prop}(${arg}) : \``); + renderer.append(`\${$$slots${prop} ? $$slots${prop}(${slot_data}) : \``); renderer.render(node.children, options); diff --git a/src/compiler/compile/utils/get_slot_data.ts b/src/compiler/compile/utils/get_slot_data.ts index ee64d8f1a054..cb42cece7e94 100644 --- a/src/compiler/compile/utils/get_slot_data.ts +++ b/src/compiler/compile/utils/get_slot_data.ts @@ -1,19 +1,43 @@ -import { snip } from './snip'; -import { stringify_attribute } from './stringify_attribute'; import Attribute from '../nodes/Attribute'; +import { p, x } from 'code-red'; +import { string_literal } from './stringify'; export default function get_slot_data(values: Map, is_ssr: boolean) { - return Array.from(values.values()) - .filter(attribute => attribute.name !== 'name') - .map(attribute => { - const value = attribute.is_true - ? 'true' - : attribute.chunks.length === 0 - ? '""' - : attribute.chunks.length === 1 && attribute.chunks[0].type !== 'Text' - ? snip(attribute.chunks[0]) - : '`' + stringify_attribute(attribute, is_ssr) + '`'; - - return `${attribute.name}: ${value}`; - }); + return { + type: 'ObjectExpression', + properties: Array.from(values.values()) + .filter(attribute => attribute.name !== 'name') + .map(attribute => { + if (is_ssr) { + throw new Error(`TODO SSR`); + } + + const value = get_value(attribute); + + // const value = attribute.is_true + // ? x`true` + // : attribute.chunks.length === 0 + // ? x`""` + // : attribute.chunks.length === 1 && attribute.chunks[0].type !== 'Text' + // ? snip(attribute.chunks[0]) + // : '`' + stringify_attribute(attribute, is_ssr) + '`'; + + return p`${attribute.name}: ${value}`; + }) + } +} + +function get_value(attribute: Attribute) { + if (attribute.is_true) return x`true`; + if (attribute.chunks.length === 0) return x`""`; + + let value = attribute.chunks + .map(chunk => chunk.type === 'Text' ? string_literal(chunk.data) : chunk.node) + .reduce((lhs, rhs) => x`${lhs} + ${rhs}`); + + if (attribute.chunks.length > 1 && attribute.chunks[0].type !== 'Text') { + value = x`"" + ${value}`; + } + + return value; } \ No newline at end of file From 6616b17c7a5050b54bbc18677318e03f3ce0ec6b Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Sun, 15 Sep 2019 22:48:49 -0400 Subject: [PATCH 23/93] more stuff --- src/compiler/compile/Component.ts | 20 ++++++------------- src/compiler/compile/nodes/Let.ts | 12 ++++++++++- .../wrappers/shared/get_context_merger.ts | 2 -- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/compiler/compile/Component.ts b/src/compiler/compile/Component.ts index 59f2e2a33e7a..6e5cf286e69c 100644 --- a/src/compiler/compile/Component.ts +++ b/src/compiler/compile/Component.ts @@ -44,16 +44,6 @@ childKeys.EachBlock = childKeys.IfBlock = ['children', 'else']; childKeys.Attribute = ['value']; childKeys.ExportNamedDeclaration = ['declaration', 'specifiers']; -function remove_node( - body: Node[], - node: Node -) { - const i = body.indexOf(node); - if (i === -1) throw new Error('node not in list'); - - body.splice(i, 1); -} - export default class Component { stats: Stats; warnings: Warning[]; @@ -478,13 +468,15 @@ export default class Component { } extract_imports(content) { - content.body.forEach(node => { + let i = content.body.length; + while (i--) { + const node = content.body[i]; + if (node.type === 'ImportDeclaration') { - // imports need to be hoisted out of the IIFE - remove_node(content.body, node); + content.body.splice(i, 1); this.imports.push(node); } - }); + } } extract_exports(content) { diff --git a/src/compiler/compile/nodes/Let.ts b/src/compiler/compile/nodes/Let.ts index 1e8014285ac2..de8f73cdd24c 100644 --- a/src/compiler/compile/nodes/Let.ts +++ b/src/compiler/compile/nodes/Let.ts @@ -15,9 +15,10 @@ export default class Let extends Node { super(component, parent, scope, info); this.name = { type: 'Identifier', name: info.name }; - this.value = info.expression.node; if (info.expression) { + this.value = info.expression; + walk(info.expression, { enter: node => { if (!applicable.has(node.type)) { @@ -30,6 +31,15 @@ export default class Let extends Node { if (node.type === 'Identifier') { this.names.push(node.name); } + + // slightly unfortunate hack + if (node.type === 'ArrayExpression') { + (node as any).type = 'ArrayPattern'; + } + + if (node.type === 'ObjectExpression') { + (node as any).type = 'ObjectPattern'; + } } }); } else { diff --git a/src/compiler/compile/render_dom/wrappers/shared/get_context_merger.ts b/src/compiler/compile/render_dom/wrappers/shared/get_context_merger.ts index eeec59384761..8c27e8b503d1 100644 --- a/src/compiler/compile/render_dom/wrappers/shared/get_context_merger.ts +++ b/src/compiler/compile/render_dom/wrappers/shared/get_context_merger.ts @@ -4,8 +4,6 @@ import { x } from 'code-red'; export function get_context_merger(lets: Let[]) { if (lets.length === 0) return null; - console.log(lets); - const input = { type: 'ObjectPattern', properties: lets.map(l => ({ From 67ae2e7c6fc4503224ffdf8b44dc9036a22bef43 Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Sun, 15 Sep 2019 23:14:28 -0400 Subject: [PATCH 24/93] maybe fix TS stuff --- package-lock.json | 16 +++++++++------- package.json | 2 +- src/compiler/compile/nodes/EventHandler.ts | 2 +- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/package-lock.json b/package-lock.json index dccb96164fc6..eda9045a264a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -330,6 +330,11 @@ "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", "dev": true }, + "astring": { + "version": "github:Rich-Harris/astring#00fa527b66cc1b57efb2a4b9052dd4e190ae3590", + "from": "github:Rich-Harris/astring#generic-handler", + "dev": true + }, "async-limiter": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", @@ -502,21 +507,18 @@ "dev": true }, "code-red": { - "version": "0.0.9", - "resolved": "https://registry.npmjs.org/code-red/-/code-red-0.0.9.tgz", - "integrity": "sha512-xQVOUxMYfFXgkW/VA1raehj+YH8CV98c8XG5cFhpeEYoO8fIjr4KM4E0Ov6lLC2rSu5qtMWmrcA1gveZwg8r1w==", + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/code-red/-/code-red-0.0.10.tgz", + "integrity": "sha512-c2m4f0/DZGowlcJiEHeryAmSqNnGFQFvE00aODYwONpzzQpxZN9RDJU3Dx0sjx379RCV8f0mg37sNFMQGECRag==", "dev": true, "requires": { "acorn": "^7.0.0", + "astring": "github:Rich-Harris/astring#00fa527b66cc1b57efb2a4b9052dd4e190ae3590", "is-reference": "^1.1.3", "periscopic": "^1.0.0", "source-map": "^0.7.3" }, "dependencies": { - "astring": { - "version": "github:Rich-Harris/astring#00fa527b66cc1b57efb2a4b9052dd4e190ae3590", - "from": "github:Rich-Harris/astring#00fa527b66cc1b57efb2a4b9052dd4e190ae3590" - }, "source-map": { "version": "0.7.3", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", diff --git a/package.json b/package.json index f86ff68cd035..3dc4dbc06bbd 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,7 @@ "acorn": "^7.0.0", "agadoo": "^1.0.1", "c8": "^5.0.1", - "code-red": "0.0.9", + "code-red": "0.0.10", "codecov": "^3.5.0", "css-tree": "1.0.0-alpha22", "eslint": "^6.3.0", diff --git a/src/compiler/compile/nodes/EventHandler.ts b/src/compiler/compile/nodes/EventHandler.ts index ecd19e5739cb..11c030a55e08 100644 --- a/src/compiler/compile/nodes/EventHandler.ts +++ b/src/compiler/compile/nodes/EventHandler.ts @@ -39,7 +39,7 @@ export default class EventHandler extends Node { node = declarator && declarator.init; } - if ((node.type === 'FunctionExpression' || node.type === 'ArrowFunctionExpression') && node.params.length === 0) { + if (node && (node.type === 'FunctionExpression' || node.type === 'ArrowFunctionExpression') && node.params.length === 0) { this.can_make_passive = true; } } From 032cab95f533f0c8817131ad1aa02d2fc9b8f4b9 Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Tue, 17 Sep 2019 20:26:49 -0400 Subject: [PATCH 25/93] prevent duplicate manipulations --- src/compiler/compile/nodes/shared/Expression.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/compiler/compile/nodes/shared/Expression.ts b/src/compiler/compile/nodes/shared/Expression.ts index 39c106072822..f4ed48a05633 100644 --- a/src/compiler/compile/nodes/shared/Expression.ts +++ b/src/compiler/compile/nodes/shared/Expression.ts @@ -81,6 +81,8 @@ export default class Expression { declarations: (Node | Node[])[] = []; uses_context = false; + manipulated: Node; + // todo: owner type constructor(component: Component, owner: Owner, template_scope: TemplateScope, info, lazy?: boolean) { // TODO revert to direct property access in prod? @@ -222,6 +224,10 @@ export default class Expression { // TODO move this into a render-dom wrapper? manipulate(block?: Block) { + // TODO ideally we wouldn't end up calling this method + // multiple times + if (this.manipulated) return this.manipulated; + const { component, declarations, @@ -405,7 +411,7 @@ export default class Expression { }); } - return node; + return (this.manipulated = node); } } From d386efdb0d151475b51627442deff32d5ef0adb7 Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Tue, 17 Sep 2019 20:36:45 -0400 Subject: [PATCH 26/93] fix filename var --- src/compiler/compile/render_dom/index.ts | 6 +++--- test/runtime/index.js | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/compiler/compile/render_dom/index.ts b/src/compiler/compile/render_dom/index.ts index 066a30563ee8..2abfc1a3088d 100644 --- a/src/compiler/compile/render_dom/index.ts +++ b/src/compiler/compile/render_dom/index.ts @@ -26,8 +26,8 @@ export default function dom( const body = []; - if (component.compile_options.dev) { - body.push(b`const ${renderer.file_var} = ${component.file && stringify(component.file, { only_escape_at_symbol: true })};`); + if (component.compile_options.dev && component.file) { + body.push(b`const ${renderer.file_var} = "${component.file}";`); } const css = component.stylesheet.render(options.filename, !options.customElement); @@ -364,7 +364,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 = b` - const writable_props = [${writable_props.map(prop => `'${prop.export_name}'`)}]; + const writable_props = [${writable_props.map(prop => x`'${prop.export_name}'`)}]; @_Object.keys($$props).forEach(key => { if (!writable_props.includes(key) && !key.startsWith('$$')) @_console.warn(\`<${component.tag}> was created with unknown prop '\${key}'\`); }); diff --git a/test/runtime/index.js b/test/runtime/index.js index c3583ddccf60..28ef9e4d789d 100644 --- a/test/runtime/index.js +++ b/test/runtime/index.js @@ -3,7 +3,7 @@ import * as path from "path"; import * as fs from "fs"; import { rollup } from 'rollup'; import * as virtual from 'rollup-plugin-virtual'; -import { clear_loops, flush, set_now, set_raf, component_subscribe } from "../../internal"; +import { clear_loops, flush, set_now, set_raf } from "../../internal"; import { showOutput, @@ -229,7 +229,7 @@ describe.only("runtime", () => { }), { name: 'svelte-packages', - resolveId: (importee, importer) => { + resolveId: (importee) => { if (importee.startsWith('svelte/')) { return importee.replace('svelte', process.cwd()) + '/index.mjs'; } From 3f2f1b1dbdb05de6e51a607e62ce45771e483614 Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Tue, 17 Sep 2019 20:44:39 -0400 Subject: [PATCH 27/93] fix some transition stuff --- src/compiler/compile/render_dom/wrappers/EachBlock.ts | 2 +- test/runtime/samples/transition-js-nested-each/_config.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/compiler/compile/render_dom/wrappers/EachBlock.ts b/src/compiler/compile/render_dom/wrappers/EachBlock.ts index d73d6dcffd2b..a6ee015d3574 100644 --- a/src/compiler/compile/render_dom/wrappers/EachBlock.ts +++ b/src/compiler/compile/render_dom/wrappers/EachBlock.ts @@ -539,7 +539,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 = b` - ${!this.block.has_update_method && `const #old_length = ${this.vars.each_block_value}.length;`} + ${!this.block.has_update_method && b`const #old_length = ${this.vars.each_block_value}.length;`} ${this.vars.each_block_value} = ${snippet}; let #i; diff --git a/test/runtime/samples/transition-js-nested-each/_config.js b/test/runtime/samples/transition-js-nested-each/_config.js index 3d2fe3c32e57..c21024dd6995 100644 --- a/test/runtime/samples/transition-js-nested-each/_config.js +++ b/test/runtime/samples/transition-js-nested-each/_config.js @@ -4,7 +4,7 @@ export default { things: ['a'] }, - test({ assert, component, target, window, raf }) { + test({ assert, component, target, raf }) { component.x = true; const div = target.querySelector('div'); From 9d60236f32ffad9e9fc9ba31dc96520bcc4ea68c Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Tue, 17 Sep 2019 22:14:36 -0400 Subject: [PATCH 28/93] various --- src/compiler/compile/Component.ts | 58 +++++-------------- src/compiler/compile/render_dom/index.ts | 27 +++++---- .../compile/render_dom/wrappers/EachBlock.ts | 2 +- src/compiler/compile/render_ssr/index.ts | 30 +++++----- src/compiler/compile/utils/invalidate.ts | 25 ++++---- 5 files changed, 56 insertions(+), 86 deletions(-) diff --git a/src/compiler/compile/Component.ts b/src/compiler/compile/Component.ts index 6e5cf286e69c..4d26867565e4 100644 --- a/src/compiler/compile/Component.ts +++ b/src/compiler/compile/Component.ts @@ -68,8 +68,6 @@ export default class Component { var_lookup: Map = new Map(); imports: ImportDeclaration[] = []; - module_javascript: string; - javascript: string; hoistable_nodes: Set = new Set(); node_for_declaration: Map = new Map(); @@ -530,7 +528,10 @@ export default class Component { } extract_javascript(script) { - const nodes_to_include = script.content.body.filter(node => { + if (!script) return null; + + return script.content.body.filter(node => { + if (!node) return false; if (this.hoistable_nodes.has(node)) return false; if (this.reactive_declaration_nodes.has(node)) return false; if (node.type === 'ImportDeclaration') return false; @@ -538,38 +539,6 @@ export default class Component { return false; return true; }); - - return nodes_to_include; - - if (nodes_to_include.length === 0) return null; - - let a = script.content.start; - while (/\s/.test(this.source[a])) a += 1; - - // let b = a; - - // let result = ''; - - // script.content.body.forEach(node => { - // if ( - // this.hoistable_nodes.has(node) || - // this.reactive_declaration_nodes.has(node) - // ) { - // if (a !== b) result += `[✂${a}-${b}✂]`; - // a = node.end; - // } - - // b = node.end; - // }); - - // while (/\s/.test(this.source[a - 1])) a -= 1; - - // b = script.content.end; - // while (/\s/.test(this.source[b - 1])) b -= 1; - - // if (a < b) result += `[✂${a}-${b}✂]`; - - // return result || null; } walk_module_js() { @@ -625,7 +594,6 @@ export default class Component { this.extract_imports(script.content); this.extract_exports(script.content); - this.module_javascript = this.extract_javascript(script); } walk_instance_js_pre_template() { @@ -728,7 +696,6 @@ export default class Component { this.hoist_instance_declarations(); this.extract_reactive_declarations(); this.extract_reactive_store_references(); - this.javascript = this.extract_javascript(script); } // TODO merge this with other walks that are independent @@ -812,7 +779,7 @@ export default class Component { const variable = this.var_lookup.get(name); if (variable && (variable.subscribable && variable.reassigned)) { - return x`$$subscribe_${name}($$invalidate('${name}', ${value || name}))`; + return x`${`$$subscribe_${name}`}($$invalidate('${name}', ${value || name}))`; } if (name[0] === '$' && name[1] !== '$') { @@ -850,7 +817,7 @@ export default class Component { return Array.from(deps).map(n => x`$$invalidate('${n}', ${n})`); } - rewrite_props(_get_insert: (variable: Var) => string) { + rewrite_props(get_insert: (variable: Var) => Node[]) { // TODO const component = this; @@ -858,7 +825,7 @@ export default class Component { let scope = instance_scope; walk(this.ast.instance.content, { - enter(node) { + enter(node, parent, key, index) { if (/Function/.test(node.type)) { return this.skip(); } @@ -896,9 +863,11 @@ export default class Component { const variable = component.var_lookup.get(name); if (variable.export_name) { - // const insert = variable.subscribable - // ? get_insert(variable) - // : null; + const insert = variable.subscribable + ? get_insert(variable) + : null; + + parent[key].splice(index + 1, 0, insert); declarator.id = { type: 'ObjectPattern', @@ -920,6 +889,9 @@ export default class Component { }; declarator.init = x`$$props`; + } else if (variable.subscribable) { + const insert = get_insert(variable); + parent[key].splice(index + 1, 0, ...insert); } }); } diff --git a/src/compiler/compile/render_dom/index.ts b/src/compiler/compile/render_dom/index.ts index 2abfc1a3088d..b0b4d8bce234 100644 --- a/src/compiler/compile/render_dom/index.ts +++ b/src/compiler/compile/render_dom/index.ts @@ -163,7 +163,7 @@ export default function dom( const { ctx } = this.$$; const props = ${options.customElement ? `this.attributes` : `options.props || {}`}; ${expected.map(prop => b` - if (ctx.${prop.name} === undefined && !('${prop.export_name}' in props)) { + if (#ctx.${prop.name} === undefined && !('${prop.export_name}' in props)) { @_console.warn("<${component.tag}> was created without expected prop '${prop.export_name}'"); }`)} `; @@ -182,7 +182,7 @@ export default function dom( const writable_vars = component.vars.filter(variable => !variable.module && variable.writable); inject_state = (uses_props || writable_vars.length > 0) ? x` ${$$props} => { - ${uses_props && component.invalidate('$$props', `$$props = @assign(@assign({}, $$props), $$new_props)`)} + ${uses_props && component.invalidate('$$props', x`$$props = @assign(@assign({}, $$props), $$new_props)`)} ${writable_vars.map(prop => b` if ('${prop.name}' in $$props) ${component.invalidate(prop.name, `${prop.name} = ${$$props}.${prop.name}`)}; `)} @@ -226,18 +226,17 @@ export default function dom( component.rewrite_props(({ name, reassigned }) => { const value = `$${name}`; - const callback = `$value => { ${value} = $$value; $$invalidate('${value}', ${value}) }`; - if (reassigned) { - return `$$subscribe_${name}()`; + return b`${`$$subscribe_${name}`}()`; } const component_subscribe = component.helper('component_subscribe'); + const callback = x`$$value => { ${value} = $$value; $$invalidate('${value}', ${value}) }`; - let insert = `${component_subscribe}($$self, ${name}, $${callback})`; + let insert = b`${component_subscribe}($$self, ${name}, $${callback})`; if (component.compile_options.dev) { const validate_store = component.helper('validate_store'); - insert = `${validate_store}(${name}, '${name}'); ${insert}`; + insert = b`${validate_store}(${name}, '${name}'); ${insert}`; } return insert; @@ -254,7 +253,7 @@ export default function dom( ${block.get_contents()} } - ${component.module_javascript} + ${component.extract_javascript(component.ast.module)} ${component.fully_hoisted} `); @@ -283,8 +282,10 @@ export default function dom( filtered_declarations.push(p`$$binding_groups`); } + const instance_javascript = component.extract_javascript(component.ast.instance); + const has_definition = ( - component.javascript || + instance_javascript || filtered_props.length > 0 || uses_props || component.partly_hoisted.length > 0 || @@ -316,7 +317,7 @@ export default function dom( const variable = component.var_lookup.get(store.name.slice(1)); return variable && variable.reassigned; }) - .map(({ name }) => `$$self.$$.on_destroy.push(() => $$unsubscribe_${name.slice(1)}());`); + .map(({ name }) => b`$$self.$$.on_destroy.push(() => ${`$$unsubscribe_${name.slice(1)}`}());`); if (has_definition) { const reactive_declarations: (Node | Node[]) = []; @@ -355,7 +356,9 @@ export default function dom( const store = component.var_lookup.get(name); if (store && store.reassigned) { - return b`let ${$name}, $$unsubscribe_${name} = @noop, $$subscribe_${name} = () => ($$unsubscribe_${name}(), $$unsubscribe_${name} = @subscribe(${name}, $$value => { ${$name} = $$value; $$invalidate('${$name}', ${$name}); }), ${name})`; + const unsubscribe = `$$unsubscribe_${name}`; + const subscribe = `$$subscribe_${name}`; + return b`let ${$name}, ${unsubscribe} = @noop, ${subscribe} = () => (${unsubscribe}(), ${unsubscribe} = @subscribe(${name}, $$value => { ${$name} = $$value; $$invalidate('${$name}', ${$name}); }), ${name})`; } return b`let ${$name};`; @@ -396,7 +399,7 @@ export default function dom( ${resubscribable_reactive_store_unsubscribers} - ${component.javascript} + ${instance_javascript} ${unknown_props_check} diff --git a/src/compiler/compile/render_dom/wrappers/EachBlock.ts b/src/compiler/compile/render_dom/wrappers/EachBlock.ts index a6ee015d3574..40a5ace9d4a9 100644 --- a/src/compiler/compile/render_dom/wrappers/EachBlock.ts +++ b/src/compiler/compile/render_dom/wrappers/EachBlock.ts @@ -529,7 +529,7 @@ export default class EachBlockWrapper extends Wrapper { `; } else { remove_old_blocks = b` - for (${this.block.has_update_method ? `` : `#i = ${data_length}`}; #i < ${this.block.has_update_method ? view_length : '#old_length'}; #i += 1) { + for (${this.block.has_update_method ? `` : x`#i = ${data_length}`}; #i < ${this.block.has_update_method ? view_length : '#old_length'}; #i += 1) { ${iterations}[#i].d(1); } ${!fixed_length && b`${view_length} = ${data_length};`} diff --git a/src/compiler/compile/render_ssr/index.ts b/src/compiler/compile/render_ssr/index.ts index 81f8c719d3f6..a5d1a8273340 100644 --- a/src/compiler/compile/render_ssr/index.ts +++ b/src/compiler/compile/render_ssr/index.ts @@ -41,24 +41,24 @@ export default function ssr( // TODO remove this, just use component.vars everywhere const props = component.vars.filter(variable => !variable.module && variable.export_name); - if (component.javascript) { - component.rewrite_props(({ name }) => { - const value = `$${name}`; + component.rewrite_props(({ name }) => { + const value = `$${name}`; - const get_store_value = component.helper('get_store_value'); + const get_store_value = component.helper('get_store_value'); - let insert = `${value} = ${get_store_value}(${name})`; - if (component.compile_options.dev) { - const validate_store = component.helper('validate_store'); - insert = `${validate_store}(${name}, '${name}'); ${insert}`; - } + let insert = b`${value} = ${get_store_value}(${name})`; + if (component.compile_options.dev) { + const validate_store = component.helper('validate_store'); + insert = b`${validate_store}(${name}, '${name}'); ${insert}`; + } - return insert; - }); - } + return insert; + }); + + const instance_javascript = component.extract_javascript(component.ast.instance); // TODO only do this for props with a default value - const parent_bindings = component.javascript + const parent_bindings = instance_javascript ? props.map(prop => { return `if ($$props.${prop.export_name} === void 0 && $$bindings.${prop.export_name} && ${prop.name} !== void 0) $$bindings.${prop.export_name}(${prop.name});`; }) @@ -129,7 +129,7 @@ export default function ssr( return name; }) .join(', ')};`, - component.javascript, + instance_javascript, parent_bindings.join('\n'), css.code && `$$result.css.add(#css);`, main @@ -142,7 +142,7 @@ export default function ssr( map: ${css.map ? stringify(css.map.toString()) : 'null'} };`} - ${component.module_javascript} + ${component.extract_javascript(component.ast.module)} ${component.fully_hoisted} diff --git a/src/compiler/compile/utils/invalidate.ts b/src/compiler/compile/utils/invalidate.ts index e41e1e3b56c9..ab08e8e4446d 100644 --- a/src/compiler/compile/utils/invalidate.ts +++ b/src/compiler/compile/utils/invalidate.ts @@ -30,21 +30,9 @@ export function invalidate(component: Component, scope: Scope, node: Node, names if (node.type === 'AssignmentExpression' && node.operator === '=' && nodes_match(node.left, node.right) && tail.length === 0) { return component.invalidate(head); } else { + let callee = head[0] === '$' ? `@set_store_value` : `$$invalidate`; - // TODO stores - // if (head[0] === '$') { - // code.prependRight(node.start, `${component.helper('set_store_value')}(${head.slice(1)}, `); - // } else { - // let prefix = `$$invalidate`; - - // const variable = component.var_lookup.get(head); - // if (variable.subscribable && variable.reassigned) { - // prefix = `$$subscribe_${head}($$invalidate`; - // suffix += `)`; - // } - - // code.prependRight(node.start, `${prefix}('${head}', `); - // } + const variable = component.var_lookup.get(head); const extra_args = tail.map(name => component.invalidate(name)); @@ -61,7 +49,14 @@ export function invalidate(component: Component, scope: Scope, node: Node, names }); } - return x`$$invalidate("${head}", ${node}, ${extra_args})`; + let invalidate = x`${callee}("${head}", ${node}, ${extra_args})`; + + if (variable.subscribable && variable.reassigned) { + const subscribe = `$$subscribe_${head}`; + invalidate = x`${subscribe}(${invalidate})}`; + } + + return invalidate; } } From 2bf4b9c870e8ecb72c55ef6c2c1379374bb34abe Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Tue, 17 Sep 2019 23:29:29 -0400 Subject: [PATCH 29/93] update code-red --- package-lock.json | 6 +++--- package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index eda9045a264a..dcbdf879b377 100644 --- a/package-lock.json +++ b/package-lock.json @@ -507,9 +507,9 @@ "dev": true }, "code-red": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/code-red/-/code-red-0.0.10.tgz", - "integrity": "sha512-c2m4f0/DZGowlcJiEHeryAmSqNnGFQFvE00aODYwONpzzQpxZN9RDJU3Dx0sjx379RCV8f0mg37sNFMQGECRag==", + "version": "0.0.11", + "resolved": "https://registry.npmjs.org/code-red/-/code-red-0.0.11.tgz", + "integrity": "sha512-GY5N9XC10+FZclzAGdrGFF47alu+I1xCcpM/eoYmpQZmAvOp1HkOgMLsxCtmuB94q84I693yN7SGGtu9sfOslA==", "dev": true, "requires": { "acorn": "^7.0.0", diff --git a/package.json b/package.json index 3dc4dbc06bbd..20f1fde6588a 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,7 @@ "acorn": "^7.0.0", "agadoo": "^1.0.1", "c8": "^5.0.1", - "code-red": "0.0.10", + "code-red": "0.0.11", "codecov": "^3.5.0", "css-tree": "1.0.0-alpha22", "eslint": "^6.3.0", From ec238d746ac6b02d878bb61a9d702eb5f08131ec Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Tue, 17 Sep 2019 23:29:40 -0400 Subject: [PATCH 30/93] couple of fixes --- .../compile/render_dom/wrappers/Title.ts | 39 +++++++++---------- .../render_dom/wrappers/shared/bind_this.ts | 18 +++++---- 2 files changed, 29 insertions(+), 28 deletions(-) diff --git a/src/compiler/compile/render_dom/wrappers/Title.ts b/src/compiler/compile/render_dom/wrappers/Title.ts index d8535173fa73..148d66dfdabf 100644 --- a/src/compiler/compile/render_dom/wrappers/Title.ts +++ b/src/compiler/compile/render_dom/wrappers/Title.ts @@ -3,11 +3,12 @@ import Wrapper from './shared/Wrapper'; import Renderer from '../Renderer'; import Block from '../Block'; import Title from '../../nodes/Title'; -import { stringify } from '../../utils/stringify'; +import { stringify, string_literal } from '../../utils/stringify'; import add_to_set from '../../utils/add_to_set'; import Text from '../../nodes/Text'; import { Identifier } from 'estree'; import { changed } from './shared/changed'; +import MustacheTag from '../../nodes/MustacheTag'; export default class TitleWrapper extends Wrapper { node: Title; @@ -41,25 +42,21 @@ export default class TitleWrapper extends Wrapper { add_to_set(all_dependencies, expression.dependencies); } else { // '{foo} {bar}' — treat as string concatenation - value = - (this.node.children[0].type === 'Text' ? '' : `"" + `) + - this.node.children - .map((chunk) => { - if (chunk.type === 'Text') { - return stringify(chunk.data); - } else { - // @ts-ignore todo: check this - const snippet = chunk.expression.manipulate(block); - // @ts-ignore todo: check this - chunk.expression.dependencies.forEach(d => { - all_dependencies.add(d); - }); - - // @ts-ignore todo: check this - return chunk.expression.get_precedence() <= 13 ? `(${snippet})` : snippet; - } - }) - .join(' + '); + value = this.node.children + .map(chunk => { + if (chunk.type === 'Text') return string_literal(chunk.data); + + (chunk as MustacheTag).expression.dependencies.forEach(d => { + all_dependencies.add(d); + }); + + return (chunk as MustacheTag).expression.manipulate(block); + }) + .reduce((lhs, rhs) => x`${lhs} + ${rhs}`); + + if (this.node.children[0].type !== 'Text') { + value = x`"" + ${value}`; + } } const last = this.node.should_cache && block.get_unique_name( @@ -68,7 +65,7 @@ export default class TitleWrapper extends Wrapper { if (this.node.should_cache) block.add_variable(last); - const init = this.node.should_cache ? `${last} = ${value}` : value; + const init = this.node.should_cache ? x`${last} = ${value}` : value; block.chunks.init.push( b`@_document.title = ${init};` 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 2a4fab1473fb..8c32e6026d51 100644 --- a/src/compiler/compile/render_dom/wrappers/shared/bind_this.ts +++ b/src/compiler/compile/render_dom/wrappers/shared/bind_this.ts @@ -40,11 +40,14 @@ export default function bind_this(component: Component, block: Block, binding: B `; } - const contextual_dependencies = Array.from(binding.expression.contextual_dependencies); + const contextual_dependencies: Identifier[] = Array.from(binding.expression.contextual_dependencies).map(name => ({ + type: 'Identifier', + name + })); if (contextual_dependencies.length) { component.partly_hoisted.push(b` - function ${fn}(${['$$value', ...contextual_dependencies]}) { + function ${fn}($$value, ${contextual_dependencies}) { if (${lhs} === $$value) return; @binding_callbacks[$$value ? 'unshift' : 'push'](() => { ${body} @@ -53,8 +56,7 @@ export default function bind_this(component: Component, block: Block, binding: B `); const args = []; - for (const arg of contextual_dependencies) { - const id: Identifier = { type: 'Identifier', name: arg }; + for (const id of contextual_dependencies) { args.push(id); block.add_variable(id, x`#ctx.${id}`); } @@ -63,11 +65,13 @@ export default function bind_this(component: Component, block: Block, binding: B const unassign = block.get_unique_name(`unassign_${variable.name}`); block.chunks.init.push(b` - const ${assign} = () => #ctx.${fn}(${[variable].concat(args)}); - const ${unassign} = () => #ctx.${fn}(${['null'].concat(args)}); + const ${assign} = () => #ctx.${fn}(${variable}, ${args}); + const ${unassign} = () => #ctx.${fn}(null, ${args}); `); - const condition = Array.from(contextual_dependencies).map(name => `${name} !== #ctx.${name}`).join(' || '); + const condition = Array.from(contextual_dependencies) + .map(name => x`${name} !== #ctx.${name}`) + .reduce((lhs, rhs) => x`${lhs} || ${rhs}`); // we push unassign and unshift assign so that references are // nulled out before they're created, to avoid glitches From f30e02adf79d31e064406977e34984917f551c58 Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Wed, 18 Sep 2019 09:26:04 -0400 Subject: [PATCH 31/93] various --- package-lock.json | 6 +-- package.json | 2 +- src/compiler/compile/Component.ts | 46 +++++++++++++------ src/compiler/compile/render_dom/index.ts | 27 +++++------ .../compile/render_dom/wrappers/EachBlock.ts | 6 +-- .../wrappers/Element/StyleAttribute.ts | 12 ++--- .../render_dom/wrappers/Element/index.ts | 19 ++++++-- .../render_dom/wrappers/RawMustacheTag.ts | 2 +- .../render_dom/wrappers/shared/bind_this.ts | 4 +- src/compiler/utils/names.ts | 2 +- 10 files changed, 79 insertions(+), 47 deletions(-) diff --git a/package-lock.json b/package-lock.json index dcbdf879b377..e1b1d459928d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -507,9 +507,9 @@ "dev": true }, "code-red": { - "version": "0.0.11", - "resolved": "https://registry.npmjs.org/code-red/-/code-red-0.0.11.tgz", - "integrity": "sha512-GY5N9XC10+FZclzAGdrGFF47alu+I1xCcpM/eoYmpQZmAvOp1HkOgMLsxCtmuB94q84I693yN7SGGtu9sfOslA==", + "version": "0.0.12", + "resolved": "https://registry.npmjs.org/code-red/-/code-red-0.0.12.tgz", + "integrity": "sha512-5R8zbm2z5CmHp2iSmV/kSDhXcdISJwBr898jIPeASEdsGrjFpT4Jhky0J659jLsZL9gzDBGn32rvR0YWDXzAvw==", "dev": true, "requires": { "acorn": "^7.0.0", diff --git a/package.json b/package.json index 20f1fde6588a..9725d7153061 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,7 @@ "acorn": "^7.0.0", "agadoo": "^1.0.1", "c8": "^5.0.1", - "code-red": "0.0.11", + "code-red": "0.0.12", "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 4d26867565e4..5c4780c8c16a 100644 --- a/src/compiler/compile/Component.ts +++ b/src/compiler/compile/Component.ts @@ -2,7 +2,7 @@ import { walk, childKeys } from 'estree-walker'; import { getLocator } from 'locate-character'; import Stats from '../Stats'; -import { globals, reserved } from '../utils/names'; +import { globals, reserved, is_valid } from '../utils/names'; import { namespaces, valid_namespaces } from '../utils/namespaces'; import create_module from './create_module'; import { @@ -24,7 +24,7 @@ import TemplateScope from './nodes/shared/TemplateScope'; import fuzzymatch from '../utils/fuzzymatch'; import get_object from './utils/get_object'; import Slot from './nodes/Slot'; -import { Node, ImportDeclaration, Identifier, Program, ExpressionStatement, AssignmentExpression } from 'estree'; +import { Node, ImportDeclaration, Identifier, Program, ExpressionStatement, AssignmentExpression, Literal } from 'estree'; import add_to_set from './utils/add_to_set'; import check_graph_for_cycles from './utils/check_graph_for_cycles'; import { print, x } from 'code-red'; @@ -285,24 +285,44 @@ export default class Component { const program: any = { type: 'Program', body: result }; walk(program, { - enter: (node) => { + enter: (node, parent, key) => { if (node.type === 'Identifier' && !('name' in node)) { console.log(node); throw new Error('wtf'); } - if (node.type === 'Identifier' && node.name[0] === '@') { - // TODO temp - if (!/@\w+$/.test(node.name)) { - throw new Error(`wut "${node.name}"`); + if (node.type === 'Identifier') { + if (node.name[0] === '@') { + // TODO temp + if (!/@\w+$/.test(node.name)) { + throw new Error(`wut "${node.name}"`); + } + + if (node.name[1] === '_') { + const alias = this.global(node.name.slice(2)); + node.name = alias.name; + } else { + const alias = this.helper(node.name.slice(1)); + node.name = alias.name; + } } - if (node.name[1] === '_') { - const alias = this.global(node.name.slice(2)); - node.name = alias.name; - } else { - const alias = this.helper(node.name.slice(1)); - node.name = alias.name; + else if (node.name[0] !== '#' && !is_valid(node.name)) { + // this hack allows x`foo.${bar}` where bar could be invalid + const literal: Literal = { type: 'Literal', value: node.name }; + + if (parent.type === 'Property' && key === 'key') { + parent.key = literal; + } + + else if (parent.type === 'MemberExpression' && key === 'property') { + parent.property = literal; + parent.computed = true; + } + + else { + console.log(node); + } } } } diff --git a/src/compiler/compile/render_dom/index.ts b/src/compiler/compile/render_dom/index.ts index b0b4d8bce234..eeb4d3b2b492 100644 --- a/src/compiler/compile/render_dom/index.ts +++ b/src/compiler/compile/render_dom/index.ts @@ -41,8 +41,8 @@ export default function dom( body.push(b` function ${add_css}() { var style = @element("style"); - style.id = '${component.stylesheet.id}-style'; - style.textContent = ${styles}; + style.id = "${component.stylesheet.id}-style"; + style.textContent = "${styles}"; @append(@_document.head, style); } `); @@ -84,7 +84,7 @@ export default function dom( ${$$props} => { ${uses_props && component.invalidate('$$props', x`$$props = @assign(@assign({}, $$props), $$new_props)`)} ${writable_props.map(prop => - b`if ('${prop.export_name}' in ${$$props}) ${component.invalidate(prop.name, `${prop.name} = ${$$props}.${prop.export_name}`)};` + b`if ('${prop.export_name}' in ${$$props}) ${component.invalidate(prop.name, x`${prop.name} = ${$$props}.${prop.export_name}`)};` )} ${component.slots.size > 0 && b`if ('$$scope' in ${$$props}) ${component.invalidate('$$scope', x`$$scope = ${$$props}.$$scope`)};`} @@ -160,7 +160,7 @@ export default function dom( if (expected.length) { dev_props_check = b` - const { ctx } = this.$$; + const { ctx: #ctx } = this.$$; const props = ${options.customElement ? `this.attributes` : `options.props || {}`}; ${expected.map(prop => b` if (#ctx.${prop.name} === undefined && !('${prop.export_name}' in props)) { @@ -171,7 +171,7 @@ export default function dom( capture_state = (uses_props || writable_props.length > 0) ? x` () => { - return { ${component.vars.filter(prop => prop.writable).map(prop => prop.name).join(", ")} }; + return { ${component.vars.filter(prop => prop.writable).map(prop => p`${prop.name}`)} }; } ` : x` () => { @@ -184,7 +184,7 @@ export default function dom( ${$$props} => { ${uses_props && component.invalidate('$$props', x`$$props = @assign(@assign({}, $$props), $$new_props)`)} ${writable_vars.map(prop => b` - if ('${prop.name}' in $$props) ${component.invalidate(prop.name, `${prop.name} = ${$$props}.${prop.name}`)}; + if ('${prop.name}' in $$props) ${component.invalidate(prop.name, x`${prop.name} = ${$$props}.${prop.name}`)}; `)} } ` : x` @@ -327,13 +327,14 @@ export default function dom( const dependencies = Array.from(d.dependencies); const uses_props = !!dependencies.find(n => n === '$$props'); - const condition = !uses_props && dependencies - .filter(n => { - const variable = component.var_lookup.get(n); - return variable && (variable.writable || variable.mutated); - }) + const writable = dependencies.filter(n => { + const variable = component.var_lookup.get(n); + return variable && (variable.writable || variable.mutated); + }); + + const condition = !uses_props && writable.length > 0 && (writable .map(n => x`$$dirty.${n}`) - .reduce((lhs, rhs) => x`${lhs} || ${rhs}`); + .reduce((lhs, rhs) => x`${lhs} || ${rhs}`)); let statement = d.node; if (condition) statement = b`if (${condition}) { ${statement} }`[0]; @@ -405,7 +406,7 @@ export default function dom( ${component.slots.size && b`let { $$slots = {}, $$scope } = $$props;`} - ${renderer.binding_groups.length > 0 && `const $$binding_groups = [${renderer.binding_groups.map(_ => `[]`).join(', ')}];`} + ${renderer.binding_groups.length > 0 && b`const $$binding_groups = [${renderer.binding_groups.map(_ => x`[]`)}];`} ${component.partly_hoisted} diff --git a/src/compiler/compile/render_dom/wrappers/EachBlock.ts b/src/compiler/compile/render_dom/wrappers/EachBlock.ts index 40a5ace9d4a9..75d0dd388012 100644 --- a/src/compiler/compile/render_dom/wrappers/EachBlock.ts +++ b/src/compiler/compile/render_dom/wrappers/EachBlock.ts @@ -395,7 +395,7 @@ export default class EachBlockWrapper extends Wrapper { ${this.block.has_outros && b`@group_outros();`} ${this.node.has_animation && b`for (let #i = 0; #i < ${view_length}; #i += 1) ${iterations}[#i].r();`} - ${iterations} = @update_keyed_each(${iterations}, #changed, ${get_key}, ${dynamic ? '1' : '0'}, #ctx, ${this.vars.each_block_value}, ${lookup}, ${update_mount_node}, ${destroy}, ${create_each_block}, ${update_anchor_node}, ${this.vars.get_each_context}); + ${iterations} = @update_keyed_each(${iterations}, #changed, ${get_key}, ${dynamic ? 1 : 0}, #ctx, ${this.vars.each_block_value}, ${lookup}, ${update_mount_node}, ${destroy}, ${create_each_block}, ${update_anchor_node}, ${this.vars.get_each_context}); ${this.node.has_animation && b`for (let #i = 0; #i < ${view_length}; #i += 1) ${iterations}[#i].a();`} ${this.block.has_outros && b`@check_outros();`} `); @@ -508,7 +508,7 @@ export default class EachBlockWrapper extends Wrapper { } `; - const start = this.block.has_update_method ? '0' : `#old_length`; + const start = this.block.has_update_method ? 0 : `#old_length`; let remove_old_blocks; @@ -529,7 +529,7 @@ export default class EachBlockWrapper extends Wrapper { `; } else { remove_old_blocks = b` - for (${this.block.has_update_method ? `` : x`#i = ${data_length}`}; #i < ${this.block.has_update_method ? view_length : '#old_length'}; #i += 1) { + for (${this.block.has_update_method ? null : x`#i = ${data_length}`}; #i < ${this.block.has_update_method ? view_length : '#old_length'}; #i += 1) { ${iterations}[#i].d(1); } ${!fixed_length && b`${view_length} = ${data_length};`} diff --git a/src/compiler/compile/render_dom/wrappers/Element/StyleAttribute.ts b/src/compiler/compile/render_dom/wrappers/Element/StyleAttribute.ts index 4da35952dcaf..dec62dcb4a15 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/StyleAttribute.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/StyleAttribute.ts @@ -3,7 +3,7 @@ import Attribute from '../../../nodes/Attribute'; import Block from '../../Block'; import AttributeWrapper from './Attribute'; import ElementWrapper from '../Element'; -import { stringify } from '../../../utils/stringify'; +import { string_literal } from '../../../utils/stringify'; import add_to_set from '../../../utils/add_to_set'; import Expression from '../../../nodes/shared/Expression'; import Text from '../../../nodes/Text'; @@ -32,12 +32,10 @@ export default class StyleAttributeWrapper extends AttributeWrapper { value = prop.value .map(chunk => { if (chunk.type === 'Text') { - return stringify(chunk.data); + return string_literal(chunk.data); } else { - const snippet = chunk.manipulate(block); - add_to_set(prop_dependencies, chunk.dynamic_dependencies()); - return snippet; + return chunk.manipulate(block); } }) .reduce((lhs, rhs) => x`${lhs} + ${rhs}`) @@ -61,11 +59,11 @@ export default class StyleAttributeWrapper extends AttributeWrapper { block.chunks.update.push(update); } } else { - value = stringify((prop.value[0] as Text).data); + value = string_literal((prop.value[0] as Text).data); } block.chunks.hydrate.push( - b`@set_style(${this.parent.var}, "${prop.key}", ${value}, ${prop.important ? 1 : ''});` + b`@set_style(${this.parent.var}, "${prop.key}", ${value}, ${prop.important ? 1 : null});` ); }); } diff --git a/src/compiler/compile/render_dom/wrappers/Element/index.ts b/src/compiler/compile/render_dom/wrappers/Element/index.ts index aa9ee0c04102..ec2626d5f9c6 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/index.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/index.ts @@ -480,8 +480,21 @@ export default class ElementWrapper extends Wrapper { callee = x`#ctx.${handler}`; } + const arg = contextual_dependencies.size > 0 && { + type: 'ObjectPattern', + properties: Array.from(contextual_dependencies).map(name => { + const id = { type: 'Identifier', name }; + return { + type: 'Property', + kind: 'init', + key: id, + value: id + }; + }) + }; + this.renderer.component.partly_hoisted.push(b` - function ${handler}(${contextual_dependencies.size > 0 ? `{ ${Array.from(contextual_dependencies).join(', ')} }` : ``}) { + function ${handler}(${arg}) { ${group.bindings.map(b => b.handler.mutation)} ${Array.from(dependencies).filter(dep => dep[0] !== '$').map(dep => b`${this.renderer.component.invalidate(dep)};`)} } @@ -774,10 +787,10 @@ export default class ElementWrapper extends Wrapper { block.chunks.fix.push(b` @fix_position(${this.var}); ${stop_animation}(); - ${outro && `@add_transform(${this.var}, ${rect});`} + ${outro && b`@add_transform(${this.var}, ${rect});`} `); - const params = this.node.animation.expression ? this.node.animation.expression.manipulate(block) : '{}'; + const params = this.node.animation.expression ? this.node.animation.expression.manipulate(block) : x`{}`; const name = component.qualify(this.node.animation.name); diff --git a/src/compiler/compile/render_dom/wrappers/RawMustacheTag.ts b/src/compiler/compile/render_dom/wrappers/RawMustacheTag.ts index 74724535acf7..60a6223783cc 100644 --- a/src/compiler/compile/render_dom/wrappers/RawMustacheTag.ts +++ b/src/compiler/compile/render_dom/wrappers/RawMustacheTag.ts @@ -27,7 +27,7 @@ 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 => b`${parent_node}.innerHTML = ${content};`; + const insert = content => b`${parent_node}.innerHTML = ${content};`[0]; const { init } = this.rename_this_method( block, 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 8c32e6026d51..93525f10209a 100644 --- a/src/compiler/compile/render_dom/wrappers/shared/bind_this.ts +++ b/src/compiler/compile/render_dom/wrappers/shared/bind_this.ts @@ -25,14 +25,14 @@ export default function bind_this(component: Component, block: Block, binding: B const { snippet } = block.bindings.get(name); lhs = snippet; - body = `${lhs} = $$value`; // TODO we need to invalidate... something + body = b`${lhs} = $$value`; // TODO we need to invalidate... something } else { object = flatten_reference(binding.expression.node).name; lhs = component.source.slice(binding.expression.node.start, binding.expression.node.end).trim(); body = binding.expression.node.type === 'Identifier' ? b` - ${component.invalidate(object, `${lhs} = $$value`)}; + ${component.invalidate(object, x`${lhs} = $$value`)}; ` : b` ${lhs} = $$value; diff --git a/src/compiler/utils/names.ts b/src/compiler/utils/names.ts index 8d9150bc1880..7796e5a11b49 100644 --- a/src/compiler/utils/names.ts +++ b/src/compiler/utils/names.ts @@ -104,7 +104,7 @@ export function is_void(name: string) { return void_element_names.test(name) || name.toLowerCase() === '!doctype'; } -function is_valid(str: string): boolean { +export function is_valid(str: string): boolean { let i = 0; while (i < str.length) { From 79b75cfbb085ff473771a3b22a02f8b77498b2fd Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Wed, 18 Sep 2019 20:34:26 -0400 Subject: [PATCH 32/93] various --- .../compile/render_dom/wrappers/EachBlock.ts | 2 +- .../render_dom/wrappers/Element/Binding.ts | 2 +- .../render_dom/wrappers/Element/index.ts | 10 ++++---- .../compile/render_dom/wrappers/Slot.ts | 2 +- .../compile/render_ssr/handlers/Element.ts | 10 ++++---- .../render_ssr/handlers/InlineComponent.ts | 23 +++++++++++-------- src/compiler/compile/utils/stringify_props.ts | 11 --------- 7 files changed, 26 insertions(+), 34 deletions(-) delete mode 100644 src/compiler/compile/utils/stringify_props.ts diff --git a/src/compiler/compile/render_dom/wrappers/EachBlock.ts b/src/compiler/compile/render_dom/wrappers/EachBlock.ts index 75d0dd388012..9117777c7649 100644 --- a/src/compiler/compile/render_dom/wrappers/EachBlock.ts +++ b/src/compiler/compile/render_dom/wrappers/EachBlock.ts @@ -410,7 +410,7 @@ export default class EachBlockWrapper extends Wrapper { block.chunks.destroy.push(b` for (let #i = 0; #i < ${view_length}; #i += 1) { - ${iterations}[#i].d(${parent_node ? '' : 'detaching'}); + ${iterations}[#i].d(${parent_node ? null : 'detaching'}); } `); } diff --git a/src/compiler/compile/render_dom/wrappers/Element/Binding.ts b/src/compiler/compile/render_dom/wrappers/Element/Binding.ts index ea1d18c06120..1d5bc481ee4b 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/Binding.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/Binding.ts @@ -273,7 +273,7 @@ function get_event_handler( uses_context: true, mutation: store ? mutate_store(store, value, tail) - : b`${snippet}.${tail} = ${value};`, + : b`${snippet} = ${value};`, contextual_dependencies: new Set([object.name, property.name]) }; } diff --git a/src/compiler/compile/render_dom/wrappers/Element/index.ts b/src/compiler/compile/render_dom/wrappers/Element/index.ts index ec2626d5f9c6..3c5dedf7dd6c 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/index.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/index.ts @@ -162,10 +162,10 @@ export default class ElementWrapper extends Wrapper { }); const lets = this.node.lets; - const seen = new Set(lets.map(l => l.name)); + const seen = new Set(lets.map(l => l.name.name)); (owner as unknown as InlineComponentWrapper).node.lets.forEach(l => { - if (!seen.has(l.name)) lets.push(l); + if (!seen.has(l.name.name)) lets.push(l); }); const fn = get_context_merger(lets); @@ -649,7 +649,7 @@ export default class ElementWrapper extends Wrapper { const name = block.get_unique_name(`${this.var.name}_transition`); const snippet = intro.expression ? intro.expression.manipulate(block) - : '{}'; + : x`{}`; block.add_variable(name); @@ -695,7 +695,7 @@ export default class ElementWrapper extends Wrapper { block.add_variable(intro_name); const snippet = intro.expression ? intro.expression.manipulate(block) - : '{}'; + : x`{}`; const fn = component.qualify(intro.name); @@ -737,7 +737,7 @@ export default class ElementWrapper extends Wrapper { block.add_variable(outro_name); const snippet = outro.expression ? outro.expression.manipulate(block) - : '{}'; + : x`{}`; const fn = component.qualify(outro.name); diff --git a/src/compiler/compile/render_dom/wrappers/Slot.ts b/src/compiler/compile/render_dom/wrappers/Slot.ts index f903e5cd2e88..a2e2d62fdf2b 100644 --- a/src/compiler/compile/render_dom/wrappers/Slot.ts +++ b/src/compiler/compile/render_dom/wrappers/Slot.ts @@ -131,7 +131,7 @@ export default class SlotWrapper extends Wrapper { const listeners = block.event_listeners; block.event_listeners = []; this.fragment.render(block, parent_node, parent_nodes); - block.render_listeners(`_${slot}`); + block.render_listeners(`_${slot.name}`); block.event_listeners = listeners; // block.builders.create.pop_condition(); diff --git a/src/compiler/compile/render_ssr/handlers/Element.ts b/src/compiler/compile/render_ssr/handlers/Element.ts index 1b56a509394b..e9704331b1da 100644 --- a/src/compiler/compile/render_ssr/handlers/Element.ts +++ b/src/compiler/compile/render_ssr/handlers/Element.ts @@ -65,8 +65,8 @@ export default function(node: Element, renderer: Renderer, options: RenderOption ); const slot = node.get_static_attribute_value('slot'); - const component = node.find_nearest(/InlineComponent/); - if (slot && component) { + const nearest_inline_component = node.find_nearest(/InlineComponent/); + if (slot && nearest_inline_component) { const slot = node.attributes.find((attribute) => attribute.name === 'slot'); const slot_name = (slot.chunks[0] as Text).data; const target = renderer.targets[renderer.targets.length - 1]; @@ -74,10 +74,10 @@ export default function(node: Element, renderer: Renderer, options: RenderOption target.slots[slot_name] = ''; const lets = node.lets; - const seen = new Set(lets.map(l => l.name)); + const seen = new Set(lets.map(l => l.name.name)); - component.lets.forEach(l => { - if (!seen.has(l.name)) lets.push(l); + nearest_inline_component.lets.forEach(l => { + if (!seen.has(l.name.name)) lets.push(l); }); options.slot_scopes.set(slot_name, get_slot_scope(node.lets)); diff --git a/src/compiler/compile/render_ssr/handlers/InlineComponent.ts b/src/compiler/compile/render_ssr/handlers/InlineComponent.ts index 74d990a3d86c..3bab0cfcf328 100644 --- a/src/compiler/compile/render_ssr/handlers/InlineComponent.ts +++ b/src/compiler/compile/render_ssr/handlers/InlineComponent.ts @@ -2,12 +2,12 @@ import { escape, escape_template, stringify } from '../../utils/stringify'; import { quote_name_if_necessary } from '../../../utils/names'; import { snip } from '../../utils/snip'; import Renderer, { RenderOptions } from '../Renderer'; -import { stringify_props } from '../../utils/stringify_props'; import { get_slot_scope } from './shared/get_slot_scope'; import { AppendTarget } from '../../../interfaces'; import InlineComponent from '../../nodes/InlineComponent'; import { INode } from '../../nodes/interfaces'; import Text from '../../nodes/Text'; +import { p, x } from 'code-red'; function stringify_attribute(chunk: INode) { if (chunk.type === 'Text') { @@ -43,8 +43,8 @@ export default function(node: InlineComponent, renderer: Renderer, options: Rend // TODO this probably won't work for contextual bindings const snippet = snip(binding.expression); - binding_props.push(`${binding.name}: ${snippet}`); - binding_fns.push(`${binding.name}: $$value => { ${snippet} = $$value; $$settled = false }`); + binding_props.push(p`${binding.name}: ${snippet}`); + binding_fns.push(p`${binding.name}: $$value => { ${snippet} = $$value; $$settled = false }`); }); const uses_spread = node.attributes.find(attr => attr.is_spread); @@ -65,14 +65,15 @@ export default function(node: InlineComponent, renderer: Renderer, options: Rend .join(', ') })`; } else { - props = stringify_props( - node.attributes - .map(attribute => `${quote_name_if_necessary(attribute.name)}: ${get_attribute_value(attribute)}`) - .concat(binding_props) - ); + props = x`{ + ${node.attributes.map(attribute => p`${attribute.name}: ${get_attribute_value(attribute)}`)} + ${binding_props} + }`; } - const bindings = stringify_props(binding_fns); + const bindings = x`{ + ${binding_fns} + }`; const expression = ( node.name === 'svelte:self' @@ -110,7 +111,9 @@ export default function(node: InlineComponent, renderer: Renderer, options: Rend renderer.targets.pop(); } - const slots = stringify_props(slot_fns); + const slots = x`{ + ${slot_fns} + }`; renderer.append(`\${@validate_component(${expression}, '${node.name}').$$render($$result, ${props}, ${bindings}, ${slots})}`); } diff --git a/src/compiler/compile/utils/stringify_props.ts b/src/compiler/compile/utils/stringify_props.ts deleted file mode 100644 index 206ef2766b3d..000000000000 --- a/src/compiler/compile/utils/stringify_props.ts +++ /dev/null @@ -1,11 +0,0 @@ -export function stringify_props(props: string[]) { - if (!props.length) return '{}'; - - const joined = props.join(', '); - if (joined.length > 40) { - // make larger data objects readable - return `{\n\t${props.join(',\n\t')}\n}`; - } - - return `{ ${joined} }`; -} \ No newline at end of file From 36b0bd32bedcc66123c85b544a0c3b1135065698 Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Wed, 18 Sep 2019 21:14:18 -0400 Subject: [PATCH 33/93] fix --- src/compiler/compile/utils/invalidate.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/compiler/compile/utils/invalidate.ts b/src/compiler/compile/utils/invalidate.ts index ab08e8e4446d..f386991d0438 100644 --- a/src/compiler/compile/utils/invalidate.ts +++ b/src/compiler/compile/utils/invalidate.ts @@ -30,8 +30,7 @@ export function invalidate(component: Component, scope: Scope, node: Node, names if (node.type === 'AssignmentExpression' && node.operator === '=' && nodes_match(node.left, node.right) && tail.length === 0) { return component.invalidate(head); } else { - let callee = head[0] === '$' ? `@set_store_value` : `$$invalidate`; - + const is_store_value = head[0] === '$'; const variable = component.var_lookup.get(head); const extra_args = tail.map(name => component.invalidate(name)); @@ -49,7 +48,8 @@ export function invalidate(component: Component, scope: Scope, node: Node, names }); } - let invalidate = x`${callee}("${head}", ${node}, ${extra_args})`; + const callee = is_store_value ? `@set_store_value` : `$$invalidate`; + let invalidate = x`${callee}(${is_store_value ? head.slice(1) : x`"${head}"`}, ${node}, ${extra_args})`; if (variable.subscribable && variable.reassigned) { const subscribe = `$$subscribe_${head}`; From 41becdc5fbda33e6080638da779515fd51f522a9 Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Wed, 18 Sep 2019 21:37:42 -0400 Subject: [PATCH 34/93] various --- package.json | 4 +-- .../render_dom/wrappers/Element/Attribute.ts | 4 +-- .../render_dom/wrappers/Element/index.ts | 11 ++++---- .../wrappers/InlineComponent/index.ts | 4 +-- src/compiler/parse/read/expression.ts | 26 ++++++++++++++++++- test/runtime/samples/class-helper/_config.js | 2 +- 6 files changed, 37 insertions(+), 14 deletions(-) diff --git a/package.json b/package.json index 9725d7153061..a45d1863e39f 100644 --- a/package.json +++ b/package.json @@ -30,12 +30,12 @@ "coverage": "c8 report --reporter=text-lcov > coverage.lcov && c8 report --reporter=html", "codecov": "codecov", "precodecov": "npm run coverage", - "build": "rollup -c && npm run tsd", + "build": "rollup -c", "prepare": "npm run build", "dev": "rollup -cw", "pretest": "npm run build", "posttest": "agadoo internal/index.mjs", - "prepublishOnly": "npm run lint && PUBLISH=true npm test", + "prepublishOnly": "npm run lint && npm run tsd && PUBLISH=true npm test", "tsd": "tsc -p src/compiler --emitDeclarationOnly && tsc -p src/runtime --emitDeclarationOnly", "lint": "eslint \"{src,test}/**/*.{ts,js}\"" }, diff --git a/src/compiler/compile/render_dom/wrappers/Element/Attribute.ts b/src/compiler/compile/render_dom/wrappers/Element/Attribute.ts index 3c28820a9e5b..ee85dd860b7e 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/Attribute.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/Attribute.ts @@ -123,8 +123,8 @@ export default class AttributeWrapper { : b` if (${option}.__value === ${last}) { ${option}.selected = true; - break; - }`; + ${'break'}; + }`; // TODO the 'break' is gross, but it's unsyntactic otherwise... updater = b` for (var ${i} = 0; ${i} < ${element.var}.options.length; ${i} += 1) { diff --git a/src/compiler/compile/render_dom/wrappers/Element/index.ts b/src/compiler/compile/render_dom/wrappers/Element/index.ts index 3c5dedf7dd6c..788624b820a0 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/index.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/index.ts @@ -2,12 +2,12 @@ import Renderer from '../../Renderer'; import Element from '../../../nodes/Element'; import Wrapper from '../shared/Wrapper'; import Block from '../../Block'; -import { is_void, quote_prop_if_necessary, quote_name_if_necessary, sanitize } from '../../../../utils/names'; +import { is_void, sanitize } from '../../../../utils/names'; import FragmentWrapper from '../Fragment'; import { escape_html, string_literal } from '../../../utils/stringify'; import TextWrapper from '../Text'; import fix_attribute_casing from './fix_attribute_casing'; -import { b, x } from 'code-red'; +import { b, x, p } from 'code-red'; import { namespaces } from '../../../../utils/namespaces'; import AttributeWrapper from './Attribute'; import StyleAttributeWrapper from './StyleAttribute'; @@ -381,8 +381,7 @@ export default class ElementWrapper extends Wrapper { get_claim_statement(nodes: Identifier) { const attributes = this.node.attributes .filter((attr) => attr.type === 'Attribute') - .map((attr) => `${quote_name_if_necessary(attr.name)}: true`) - .join(', '); + .map((attr) => p`${attr.name}: true`); const name = this.node.namespace ? this.node.name @@ -603,7 +602,7 @@ export default class ElementWrapper extends Wrapper { updates.push(condition ? x`${condition} && ${snippet}` : snippet); } else { - const snippet = x`{ ${quote_name_if_necessary(attr.name)}: ${attr.get_value(block)} }`; + const snippet = x`{ ${attr.name}: ${attr.get_value(block)} }`; initial_props.push(snippet); updates.push(condition ? x`${condition} && ${snippet}` : snippet); @@ -813,7 +812,7 @@ export default class ElementWrapper extends Wrapper { snippet = expression.manipulate(block); dependencies = expression.dependencies; } else { - snippet = `${quote_prop_if_necessary(name)}`; + snippet = name; dependencies = new Set([name]); } const updater = b`@toggle_class(${this.var}, "${name}", ${snippet});`; diff --git a/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts b/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts index 5031bb8cde1a..4ac181715bfd 100644 --- a/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts +++ b/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts @@ -3,7 +3,7 @@ import Renderer from '../../Renderer'; import Block from '../../Block'; import InlineComponent from '../../../nodes/InlineComponent'; import FragmentWrapper from '../Fragment'; -import { quote_name_if_necessary, sanitize } from '../../../../utils/names'; +import { sanitize } from '../../../../utils/names'; import add_to_set from '../../../utils/add_to_set'; import { b, x } from 'code-red'; import Attribute from '../../../nodes/Attribute'; @@ -254,7 +254,7 @@ export default class InlineComponentWrapper extends Wrapper { } changes.push(condition ? x`${condition} && ${value_object}` : value_object); } else { - const obj = x`{ ${quote_name_if_necessary(name)}: ${attr.get_value(block)} }`; + const obj = x`{ ${name}: ${attr.get_value(block)} }`; initial_props.push(obj); changes.push(condition ? x`${condition} && ${obj}` : x`${levels}[${i}]`); diff --git a/src/compiler/parse/read/expression.ts b/src/compiler/parse/read/expression.ts index 78a28ba72be1..1126711fe2de 100644 --- a/src/compiler/parse/read/expression.ts +++ b/src/compiler/parse/read/expression.ts @@ -1,6 +1,7 @@ import { parse_expression_at } from '../acorn'; import { Parser } from '../index'; import { Identifier, Node, SimpleLiteral } from 'estree'; +import { whitespace } from '../../utils/patterns'; const literals = new Map([['true', true], ['false', false], ['null', null]]); @@ -35,7 +36,30 @@ export default function read_expression(parser: Parser): Node { try { const node = parse_expression_at(parser.template, parser.index); - parser.index = node.end; + + let num_parens = 0; + + for (let i = parser.index; i < node.start; i += 1) { + if (parser.template[i] === '(') num_parens += 1; + } + + let index = node.end; + while (num_parens > 0) { + const char = parser.template[index]; + + if (char === ')') { + num_parens -= 1; + } else if (!whitespace.test(char)) { + parser.error({ + code: 'unexpected-token', + message: 'Expected )' + }, index); + } + + index += 1; + } + + parser.index = index; return node as Node; } catch (err) { diff --git a/test/runtime/samples/class-helper/_config.js b/test/runtime/samples/class-helper/_config.js index 2c4606fbe827..c38cc88240bd 100644 --- a/test/runtime/samples/class-helper/_config.js +++ b/test/runtime/samples/class-helper/_config.js @@ -5,7 +5,7 @@ export default { html: `
`, - test({ assert, component, target, window }) { + test({ assert, component, target }) { component.user = { active: false }; assert.htmlEqual(target.innerHTML, ` From b9b72a9f4526b75f72b042d8a28b861554ca1eed Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Wed, 18 Sep 2019 21:51:19 -0400 Subject: [PATCH 35/93] fixes --- .../compile/render_dom/wrappers/IfBlock.ts | 24 +++++++++++++------ .../compile/render_dom/wrappers/Title.ts | 6 ++--- test/runtime/samples/head-if-block/_config.js | 2 +- 3 files changed, 21 insertions(+), 11 deletions(-) diff --git a/src/compiler/compile/render_dom/wrappers/IfBlock.ts b/src/compiler/compile/render_dom/wrappers/IfBlock.ts index 85623896f1f4..34f679bce9a5 100644 --- a/src/compiler/compile/render_dom/wrappers/IfBlock.ts +++ b/src/compiler/compile/render_dom/wrappers/IfBlock.ts @@ -191,7 +191,7 @@ export default class IfBlockWrapper extends Wrapper { const vars = { name, anchor, if_exists_condition, has_else, has_transitions }; - const detaching = is_head(parent_node) ? '' : 'detaching'; + const detaching = is_head(parent_node) ? null : 'detaching'; if (this.node.else) { this.branches.forEach(branch => { @@ -322,7 +322,11 @@ export default class IfBlockWrapper extends Wrapper { block.chunks.update.push(b`${name}.p(#changed, #ctx);`); } - block.chunks.destroy.push(b`if (${if_exists_condition}) ${name}.d(${detaching});`); + block.chunks.destroy.push(b` + if (${if_exists_condition}) { + ${name}.d(${detaching}); + } + `); } // if any of the siblings have outros, we need to keep references to the blocks @@ -362,7 +366,7 @@ export default class IfBlockWrapper extends Wrapper { ${this.branches.map(({ dependencies, condition, snippet }, i) => condition ? b` ${snippet && b`if ((${condition} == null) || ${changed(dependencies)}) ${condition} = !!(${snippet})`} - if (${condition}) return ${String(i)};` + if (${condition}) return ${i};` : b`return ${i};`)} ${!has_else && b`return -1;`} } @@ -545,11 +549,17 @@ export default class IfBlockWrapper extends Wrapper { `); } } else if (dynamic) { - block.chunks.update.push( - b`if (${branch.condition}) ${name}.p(#changed, #ctx);` - ); + block.chunks.update.push(b` + if (${branch.condition}) { + ${name}.p(#changed, #ctx); + } + `); } - block.chunks.destroy.push(b`if (${if_exists_condition}) ${name}.d(${detaching});`); + block.chunks.destroy.push(b` + if (${if_exists_condition}) { + ${name}.d(${detaching}); + } + `); } } diff --git a/src/compiler/compile/render_dom/wrappers/Title.ts b/src/compiler/compile/render_dom/wrappers/Title.ts index 148d66dfdabf..2a02f1bc0843 100644 --- a/src/compiler/compile/render_dom/wrappers/Title.ts +++ b/src/compiler/compile/render_dom/wrappers/Title.ts @@ -3,7 +3,7 @@ import Wrapper from './shared/Wrapper'; import Renderer from '../Renderer'; import Block from '../Block'; import Title from '../../nodes/Title'; -import { stringify, string_literal } from '../../utils/stringify'; +import { string_literal } from '../../utils/stringify'; import add_to_set from '../../utils/add_to_set'; import Text from '../../nodes/Text'; import { Identifier } from 'estree'; @@ -93,8 +93,8 @@ export default class TitleWrapper extends Wrapper { } } else { const value = this.node.children.length > 0 - ? stringify((this.node.children[0] as Text).data) - : '""'; + ? string_literal((this.node.children[0] as Text).data) + : x`""`; block.chunks.hydrate.push(b`@_document.title = ${value};`); } diff --git a/test/runtime/samples/head-if-block/_config.js b/test/runtime/samples/head-if-block/_config.js index 439ed2cb1be6..cb8b6eccb9b7 100644 --- a/test/runtime/samples/head-if-block/_config.js +++ b/test/runtime/samples/head-if-block/_config.js @@ -3,7 +3,7 @@ export default { condition: false }, - test({ assert, component, target, window }) { + test({ assert, component, window }) { assert.equal(window.document.title, ''); component.condition = true; From d01669ebeca67cec066dcd31e44963e6b58975e6 Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Wed, 18 Sep 2019 23:31:40 -0400 Subject: [PATCH 36/93] binding stuff --- src/compiler/compile/nodes/Binding.ts | 3 + src/compiler/compile/render_dom/index.ts | 2 +- .../render_dom/wrappers/Element/Binding.ts | 122 +++++++++++------- .../compile/render_dom/wrappers/IfBlock.ts | 2 +- .../render_dom/wrappers/shared/bind_this.ts | 10 +- test/runtime/samples/_/_config.js | 21 ++- test/runtime/samples/_/main.svelte | 8 +- 7 files changed, 111 insertions(+), 57 deletions(-) diff --git a/src/compiler/compile/nodes/Binding.ts b/src/compiler/compile/nodes/Binding.ts index 29992f940ff7..8fc983254b03 100644 --- a/src/compiler/compile/nodes/Binding.ts +++ b/src/compiler/compile/nodes/Binding.ts @@ -4,6 +4,7 @@ import Expression from './shared/Expression'; import Component from '../Component'; import TemplateScope from './shared/TemplateScope'; import {dimensions} from "../../utils/patterns"; +import { Node as ESTreeNode } from 'estree'; import { x } from 'code-red'; // TODO this should live in a specific binding @@ -18,6 +19,7 @@ export default class Binding extends Node { type: 'Binding'; name: string; expression: Expression; + raw_expression: ESTreeNode; // TODO exists only for bind:this — is there a more elegant solution? is_contextual: boolean; obj: string; prop: string; @@ -35,6 +37,7 @@ export default class Binding extends Node { this.name = info.name; this.expression = new Expression(component, this, scope, info.expression); + this.raw_expression = JSON.parse(JSON.stringify(info.expression)); let obj; let prop; diff --git a/src/compiler/compile/render_dom/index.ts b/src/compiler/compile/render_dom/index.ts index eeb4d3b2b492..9a3e955cad13 100644 --- a/src/compiler/compile/render_dom/index.ts +++ b/src/compiler/compile/render_dom/index.ts @@ -416,7 +416,7 @@ export default function dom( ${inject_state && x`$$self.$inject_state = ${inject_state};`} - ${injected.length && `let ${injected.join(', ')};`} + ${injected.map(name => b`let ${name};`)} ${reactive_declarations.length > 0 && b` $$self.$$.update = ($$dirty = ${reactive_dependencies}) => { diff --git a/src/compiler/compile/render_dom/wrappers/Element/Binding.ts b/src/compiler/compile/render_dom/wrappers/Element/Binding.ts index 1d5bc481ee4b..ee30d440a7c1 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/Binding.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/Binding.ts @@ -7,7 +7,7 @@ import Renderer from '../../Renderer'; import flatten_reference from '../../../utils/flatten_reference'; import EachBlock from '../../../nodes/EachBlock'; import { changed } from '../shared/changed'; -import { Node, Identifier } from 'estree'; +import { Node, Identifier, MemberExpression } from 'estree'; export default class BindingWrapper { node: Binding; @@ -51,12 +51,8 @@ export default class BindingWrapper { this.object = get_object(this.node.expression.node).name; - // TODO unfortunate code is necessary because we need to use `ctx` - // inside the fragment, but not inside the -

{a} + {b} = {a + b}

\ No newline at end of file +{#each items as item, j} +
{item}
+{/each} \ No newline at end of file From 29f6437533fc08f3088b9a5ac6dec01fc450f2ab Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Wed, 18 Sep 2019 23:35:16 -0400 Subject: [PATCH 37/93] use raw_expression --- .../compile/render_dom/wrappers/InlineComponent/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts b/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts index 4ac181715bfd..9c1218079d49 100644 --- a/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts +++ b/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts @@ -342,7 +342,7 @@ export default class InlineComponentWrapper extends Wrapper { const contextual_dependencies = Array.from(binding.expression.contextual_dependencies); const dependencies = Array.from(binding.expression.dependencies); - let lhs = binding.expression.node; + let lhs = binding.raw_expression; if (binding.is_contextual && binding.expression.node.type === 'Identifier') { // bind:x={y} — we can't just do `y = x`, we need to From 8f233aee8b8e0d5897d6b85cbd71fadfc94cf3c3 Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Wed, 18 Sep 2019 23:57:21 -0400 Subject: [PATCH 38/93] more binding stuff --- src/compiler/compile/nodes/Attribute.ts | 7 +- .../compile/nodes/shared/Expression.ts | 11 +-- .../render_dom/wrappers/Element/Binding.ts | 81 +++---------------- 3 files changed, 23 insertions(+), 76 deletions(-) diff --git a/src/compiler/compile/nodes/Attribute.ts b/src/compiler/compile/nodes/Attribute.ts index a43bf2e8f6a0..5bedc2183860 100644 --- a/src/compiler/compile/nodes/Attribute.ts +++ b/src/compiler/compile/nodes/Attribute.ts @@ -20,7 +20,8 @@ export default class Attribute extends Node { is_spread: boolean; is_true: boolean; is_static: boolean; - is_synthetic: boolean; + // TODO apparently unnecessary? + // is_synthetic: boolean; expression?: Expression; chunks: Array; dependencies: Set; @@ -33,7 +34,7 @@ export default class Attribute extends Node { this.name = null; this.is_spread = true; this.is_true = false; - this.is_synthetic = false; + // this.is_synthetic = false; this.expression = new Expression(component, this, scope, info.expression); this.dependencies = this.expression.dependencies; @@ -46,7 +47,7 @@ export default class Attribute extends Node { this.name = info.name; this.is_true = info.value === true; this.is_static = true; - this.is_synthetic = info.synthetic; + // this.is_synthetic = info.synthetic; this.dependencies = new Set(); diff --git a/src/compiler/compile/nodes/shared/Expression.ts b/src/compiler/compile/nodes/shared/Expression.ts index f4ed48a05633..fe3d5a83f0f1 100644 --- a/src/compiler/compile/nodes/shared/Expression.ts +++ b/src/compiler/compile/nodes/shared/Expression.ts @@ -77,7 +77,9 @@ export default class Expression { scope: Scope; scope_map: WeakMap; - is_synthetic: boolean; + // TODO apparently unnecessary? + // is_synthetic: boolean; + declarations: (Node | Node[])[] = []; uses_context = false; @@ -96,7 +98,7 @@ export default class Expression { this.template_scope = template_scope; this.owner = owner; // @ts-ignore - this.is_synthetic = owner.is_synthetic; + // this.is_synthetic = owner.is_synthetic; const { dependencies, contextual_dependencies } = this; @@ -233,8 +235,7 @@ export default class Expression { declarations, scope_map: map, template_scope, - owner, - is_synthetic + owner } = this; let scope = this.scope; @@ -271,7 +272,7 @@ export default class Expression { dependencies.add(name); component.add_reference(name); // TODO is this redundant/misplaced? } - } else if (!is_synthetic && is_contextual(component, template_scope, name)) { + } else if (is_contextual(component, template_scope, name)) { this.replace(x`#ctx.${node}`); } diff --git a/src/compiler/compile/render_dom/wrappers/Element/Binding.ts b/src/compiler/compile/render_dom/wrappers/Element/Binding.ts index ee30d440a7c1..2b9aeea78e8a 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/Binding.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/Binding.ts @@ -228,12 +228,6 @@ function get_binding_group(renderer: Renderer, value: Node) { return index; } -function mutate_store(store, value, tail) { - return tail - ? b`${store}.update($$value => ($$value${tail} = ${value}, $$value));` - : b`${store}.set(${value});`; -} - function get_event_handler( binding: BindingWrapper, renderer: Renderer, @@ -259,75 +253,26 @@ function get_event_handler( contextual_dependencies.add(object.name); contextual_dependencies.add(property.name); - } else { - // (lhs as MemberExpression).object = x`${object}[${property}]`; } } + let mutation = b`${lhs} = ${value}`; + + const object = get_object(lhs); + if (object.name[0] === '$') { + const store = object.name.slice(1); + + mutation = b` + ${mutation} + ${store}.set(${object.name}); + `; + } + return { uses_context: binding.node.is_contextual || binding.node.expression.uses_context, // TODO this is messy - mutation: b`${lhs} = ${value}`, + mutation, contextual_dependencies }; - - // if (lhs.type === 'MemberExpression') { - // return { - // uses_context: binding.node.is_contextual || binding.node.expression.uses_context, // TODO this is messy - // mutation: b`${lhs} = ${value}`, - // contextual_dependencies - // }; - // } else { - - // } - - // const binding_info = block.bindings.get(name); - // console.log(binding_info); - - // let store = binding.object[0] === '$' ? binding.object.slice(1) : null; - - // let tail = null; - // if (binding.node.expression.node.type === 'MemberExpression') { - // // const { start, end } = get_tail(binding.node.expression.node); - // // tail = renderer.component.source.slice(start, end); - // tail = binding.node.expression.node.object; - // } - - // if (binding.node.is_contextual) { - // const binding = block.bindings.get(name); - // const { object, property, snippet } = binding; - - // if (binding.store) { - // store = binding.store; - // tail = x`${binding.tail}.${tail}`; - // } - - // return { - // uses_context: true, - // mutation: store - // ? mutate_store(store, value, tail) - // : b`${snippet} = ${value};`, - // contextual_dependencies: new Set([object.name, property.name]) - // }; - // } - - // const mutation = store - // ? mutate_store(store, value, tail) - // : b`${snippet} = ${value};`; - - // if (binding.node.expression.node.type === 'MemberExpression') { - // return { - // uses_context: binding.node.expression.uses_context, - // mutation, - // contextual_dependencies: binding.node.expression.contextual_dependencies, - // snippet - // }; - // } - - // return { - // uses_context: false, - // mutation, - // contextual_dependencies: new Set() - // }; } function get_value_from_dom( From f721a7d32570a8345cd9a874e2f370347081a84a Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Thu, 19 Sep 2019 00:19:07 -0400 Subject: [PATCH 39/93] more binding stuff --- .../compile/render_dom/wrappers/EachBlock.ts | 1 + .../render_dom/wrappers/Element/Binding.ts | 30 +++++++++++-------- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/src/compiler/compile/render_dom/wrappers/EachBlock.ts b/src/compiler/compile/render_dom/wrappers/EachBlock.ts index 9117777c7649..3caa78a95714 100644 --- a/src/compiler/compile/render_dom/wrappers/EachBlock.ts +++ b/src/compiler/compile/render_dom/wrappers/EachBlock.ts @@ -141,6 +141,7 @@ export default class EachBlockWrapper extends Wrapper { this.block.bindings.set(prop.key.name, { object: this.vars.each_block_value, property: this.index_name, + modifier: prop.modifier, snippet: prop.modifier(x`${this.vars.each_block_value}[${this.index_name}]` as Node), store, tail: prop.modifier(x`[${this.index_name}]` as Node) diff --git a/src/compiler/compile/render_dom/wrappers/Element/Binding.ts b/src/compiler/compile/render_dom/wrappers/Element/Binding.ts index 2b9aeea78e8a..7c7fd28d50a6 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/Binding.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/Binding.ts @@ -244,30 +244,34 @@ function get_event_handler( const contextual_dependencies = new Set(binding.node.expression.contextual_dependencies); const context = block.bindings.get(name); + let set_store; if (context) { - const { object, property } = context; + const { object, property, modifier, store } = context; if (lhs.type === 'Identifier') { - lhs = x`${object}[${property}]`; + lhs = modifier(x`${object}[${property}]`); contextual_dependencies.add(object.name); contextual_dependencies.add(property.name); } - } - - let mutation = b`${lhs} = ${value}`; - - const object = get_object(lhs); - if (object.name[0] === '$') { - const store = object.name.slice(1); - mutation = b` - ${mutation} - ${store}.set(${object.name}); - `; + if (store) { + set_store = b`${store}.set(${object.name});`; + } + } else { + const object = get_object(lhs); + if (object.name[0] === '$') { + const store = object.name.slice(1); + set_store = b`${store}.set(${object.name});`; + } } + let mutation = b` + ${lhs} = ${value}; + ${set_store} + `; + return { uses_context: binding.node.is_contextual || binding.node.expression.uses_context, // TODO this is messy mutation, From 9d9245d0960ce6ee3f89f99ca52824b9feb70283 Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Thu, 19 Sep 2019 08:43:44 -0400 Subject: [PATCH 40/93] fix dev warnings --- src/compiler/compile/Component.ts | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/compiler/compile/Component.ts b/src/compiler/compile/Component.ts index 5c4780c8c16a..c2f6ad901036 100644 --- a/src/compiler/compile/Component.ts +++ b/src/compiler/compile/Component.ts @@ -61,7 +61,7 @@ export default class Component { component_options: ComponentOptions; namespace: string; - tag: Identifier; + tag: string; accessors: boolean; vars: Var[] = []; @@ -163,12 +163,9 @@ export default class Component { message: `No custom element 'tag' option was specified. To automatically register a custom element, specify a name with a hyphen in it, e.g. . To hide this warning, use `, }); } - this.tag = { - type: 'Identifier', - name: this.component_options.tag || compile_options.tag - }; + this.tag = this.component_options.tag || compile_options.tag; } else { - this.tag = this.name; + this.tag = this.name.name; } this.walk_module_js(); From 13de893e894a8c03a725570dda16944d143c4821 Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Thu, 19 Sep 2019 09:11:43 -0400 Subject: [PATCH 41/93] remove some unreachable code --- .../wrappers/InlineComponent/index.ts | 26 ++++++++----------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts b/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts index 9c1218079d49..356e5c31bfa8 100644 --- a/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts +++ b/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts @@ -152,21 +152,17 @@ export default class InlineComponentWrapper extends Wrapper { }); } - if (uses_spread) { - attribute_object = initial_props; - } else { - attribute_object = { - type: 'ObjectExpression', - properties: this.node.attributes.map(attr => { - return { - type: 'Property', - kind: 'init', - key: { type: 'Identifier', name: attr.name }, - value: attr.get_value(block) - } - }).concat(initial_props.properties) - } as Expression; - } + attribute_object = { + type: 'ObjectExpression', + properties: this.node.attributes.map(attr => { + return { + type: 'Property', + kind: 'init', + key: { type: 'Identifier', name: attr.name }, + value: attr.get_value(block) + } + }).concat(initial_props.properties) + } as Expression; component_opts.properties.push({ type: 'Property', From 23b8f5fe19ff6ccba3686278ceb372f07dddc26f Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Fri, 20 Sep 2019 21:19:53 -0400 Subject: [PATCH 42/93] fix store bindings --- src/compiler/compile/render_dom/wrappers/Element/Binding.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/compile/render_dom/wrappers/Element/Binding.ts b/src/compiler/compile/render_dom/wrappers/Element/Binding.ts index 7c7fd28d50a6..a16e65c91bad 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/Binding.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/Binding.ts @@ -257,7 +257,7 @@ function get_event_handler( } if (store) { - set_store = b`${store}.set(${object.name});`; + set_store = b`${store}.set(${`$${store}`});`; } } else { const object = get_object(lhs); From 88106c96d2e1b73618eafb47942980392ae3689e Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Fri, 20 Sep 2019 22:53:26 -0400 Subject: [PATCH 43/93] almost all client-side runtime tests passing --- src/compiler/compile/render_dom/index.ts | 2 +- .../wrappers/InlineComponent/index.ts | 85 ++++++------------- 2 files changed, 27 insertions(+), 60 deletions(-) diff --git a/src/compiler/compile/render_dom/index.ts b/src/compiler/compile/render_dom/index.ts index 9a3e955cad13..016f7e4e6125 100644 --- a/src/compiler/compile/render_dom/index.ts +++ b/src/compiler/compile/render_dom/index.ts @@ -161,7 +161,7 @@ export default function dom( if (expected.length) { dev_props_check = b` const { ctx: #ctx } = this.$$; - const props = ${options.customElement ? `this.attributes` : `options.props || {}`}; + const props = ${options.customElement ? x`this.attributes` : x`options.props || {}`}; ${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}'"); diff --git a/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts b/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts index 356e5c31bfa8..86bb0bf15d72 100644 --- a/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts +++ b/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts @@ -5,7 +5,7 @@ import InlineComponent from '../../../nodes/InlineComponent'; import FragmentWrapper from '../Fragment'; import { sanitize } from '../../../../utils/names'; import add_to_set from '../../../utils/add_to_set'; -import { b, x } from 'code-red'; +import { b, x, p } from 'code-red'; import Attribute from '../../../nodes/Attribute'; import get_object from '../../../utils/get_object'; import create_debugging_comment from '../shared/create_debugging_comment'; @@ -15,7 +15,7 @@ import TemplateScope from '../../../nodes/shared/TemplateScope'; import is_dynamic from '../shared/is_dynamic'; import bind_this from '../shared/bind_this'; import { changed } from '../shared/changed'; -import { Node, Identifier, Expression } from 'estree'; +import { Node, Identifier, Expression, ObjectExpression, Property } from 'estree'; export default class InlineComponentWrapper extends Wrapper { var: Identifier; @@ -114,7 +114,7 @@ export default class InlineComponentWrapper extends Wrapper { const name = this.var; - const component_opts: any = x`{}`; + const component_opts = x`{}` as ObjectExpression; const statements: (Node | Node[])[] = []; const updates: (Node | Node[])[] = []; @@ -124,60 +124,32 @@ export default class InlineComponentWrapper extends Wrapper { const uses_spread = !!this.node.attributes.find(a => a.is_spread); - let attribute_object = x`{}`; + const initial_props = this.slots.size > 0 + ? [ + p`$$slots: { + ${Array.from(this.slots).map(([name, slot]) => { + return p`${name}: [${slot.block.name}, ${slot.fn || null}]`; + })} + }`, + p`$$scope: { + ctx: #ctx + }` + ] + : []; - if (this.node.attributes.length > 0 || this.node.bindings.length > 0 || this.slots.size > 0) { - if (!uses_spread && this.node.bindings.length === 0) { - const initial_props: any = x`{}`; - - if (this.slots.size > 0) { - initial_props.properties.push({ - type: 'Property', - kind: 'init', - key: { type: 'Identifier', name: '$$slots' }, - value: { - type: 'ObjectExpression', - properties: Array.from(this.slots).map(([name, slot]) => ({ - type: 'Property', - kind: 'init', - key: { type: 'Identifier', name }, - value: x`[${slot.block.name}, ${slot.fn}]` - })) - } - }, { - type: 'Property', - kind: 'init', - key: { type: 'Identifier', name: '$$scope' }, - value: x`{ ctx: #ctx }` - }); - } + const attribute_object = uses_spread + ? x`{ ${initial_props} }` + : x`{ + ${this.node.attributes.map(attr => p`${attr.name}: ${attr.get_value(block)}`)}, + ${initial_props} + }`; - attribute_object = { - type: 'ObjectExpression', - properties: this.node.attributes.map(attr => { - return { - type: 'Property', - kind: 'init', - key: { type: 'Identifier', name: attr.name }, - value: attr.get_value(block) - } - }).concat(initial_props.properties) - } as Expression; - - component_opts.properties.push({ - type: 'Property', - kind: 'init', - key: { type: 'Identifier', name: 'props' }, - value: attribute_object - }); + if (this.node.attributes.length || this.node.bindings.length || initial_props.length) { + if (!uses_spread && this.node.bindings.length === 0) { + component_opts.properties.push(p`props: ${attribute_object}`); } else { props = block.get_unique_name(`${name.name}_props`); - component_opts.properties.push({ - type: 'Property', - kind: 'init', - key: { type: 'Identifier', name: 'props' }, - value: props - }); + component_opts.properties.push(p`props: ${props}`); } } @@ -194,12 +166,7 @@ export default class InlineComponentWrapper extends Wrapper { // will complain that options.target is missing. This would // work better if components had separate public and private // APIs - component_opts.properties.push({ - type: 'Property', - kind: 'init', - key: { type: 'Identifier', name: '$$inline' }, - value: { type: 'Literal', value: true } - }); + component_opts.properties.push(p`$$inline: true`); } const fragment_dependencies = new Set(this.fragment ? ['$$scope'] : []); From 2031f5204f7b2e1933d3e018a13449428a0588f2 Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Fri, 20 Sep 2019 23:17:19 -0400 Subject: [PATCH 44/93] slot fallbacks --- .../compile/render_dom/wrappers/Slot.ts | 34 ++++++++++++------- 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/src/compiler/compile/render_dom/wrappers/Slot.ts b/src/compiler/compile/render_dom/wrappers/Slot.ts index a2e2d62fdf2b..1934ea14cd12 100644 --- a/src/compiler/compile/render_dom/wrappers/Slot.ts +++ b/src/compiler/compile/render_dom/wrappers/Slot.ts @@ -121,12 +121,15 @@ export default class SlotWrapper extends Wrapper { const ${slot} = @create_slot(${slot_definition}, #ctx, ${get_slot_context}); `); - // 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}`); + // TODO this is a dreadful hack! Should probably make this nicer + const { create, claim, hydrate, mount, update, destroy } = block.chunks; + + block.chunks.create = []; + block.chunks.claim = []; + block.chunks.hydrate = []; + block.chunks.mount = []; + block.chunks.update = []; + block.chunks.destroy = []; const listeners = block.event_listeners; block.event_listeners = []; @@ -134,12 +137,19 @@ export default class SlotWrapper extends Wrapper { block.render_listeners(`_${slot.name}`); 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(); + if (block.chunks.create) create.push(b`if (!${slot}) { ${block.chunks.create} }`); + if (block.chunks.claim) claim.push(b`if (!${slot}) { ${block.chunks.claim} }`); + if (block.chunks.hydrate) hydrate.push(b`if (!${slot}) { ${block.chunks.hydrate} }`); + if (block.chunks.mount) mount.push(b`if (!${slot}) { ${block.chunks.mount} }`); + if (block.chunks.update) update.push(b`if (!${slot}) { ${block.chunks.update} }`); + if (block.chunks.destroy) destroy.push(b`if (!${slot}) { ${block.chunks.destroy} }`); + + block.chunks.create = create; + block.chunks.claim = claim; + block.chunks.hydrate = hydrate; + block.chunks.mount = mount; + block.chunks.update = update; + block.chunks.destroy = destroy; block.chunks.create.push( b`if (${slot}) ${slot}.c();` From 2ea27530a730bb3c6cf4de1f09199ca759b808e6 Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Fri, 20 Sep 2019 23:23:22 -0400 Subject: [PATCH 45/93] fix add_css function --- src/compiler/compile/render_dom/index.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/compiler/compile/render_dom/index.ts b/src/compiler/compile/render_dom/index.ts index 016f7e4e6125..b4a38ff0c77f 100644 --- a/src/compiler/compile/render_dom/index.ts +++ b/src/compiler/compile/render_dom/index.ts @@ -31,9 +31,9 @@ export default function dom( } const css = component.stylesheet.render(options.filename, !options.customElement); - const styles = component.stylesheet.has_styles && stringify(options.dev ? - `${css.code}\n/*# sourceMappingURL=${css.map.toUrl()} */` : - css.code, { only_escape_at_symbol: true }); + const styles = component.stylesheet.has_styles && options.dev + ? `${css.code}\n/*# sourceMappingURL=${css.map.toUrl()} */` + : css.code; const add_css = component.get_unique_name('add_css'); From a5a729c04e607473db9ea0ff0294f85f876e372f Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Fri, 20 Sep 2019 23:29:18 -0400 Subject: [PATCH 46/93] doh, wrong way round --- src/compiler/compile/render_dom/wrappers/IfBlock.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/compiler/compile/render_dom/wrappers/IfBlock.ts b/src/compiler/compile/render_dom/wrappers/IfBlock.ts index 3e04d0005e14..38826f034f9a 100644 --- a/src/compiler/compile/render_dom/wrappers/IfBlock.ts +++ b/src/compiler/compile/render_dom/wrappers/IfBlock.ts @@ -250,8 +250,8 @@ export default class IfBlockWrapper extends Wrapper { const select_block_type = this.renderer.component.get_unique_name(`select_block_type`); const current_block_type = block.get_unique_name(`current_block_type`); const get_block = has_else - ? x`${current_block_type} && ${current_block_type}(#ctx)` - : x`${current_block_type}(#ctx)` + ? x`${current_block_type}(#ctx)` + : x`${current_block_type} && ${current_block_type}(#ctx)` /* eslint-disable @typescript-eslint/indent,indent */ if (this.needs_update) { From 5ece428a09353b5032b6a7298b0bcc96547a6664 Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Fri, 20 Sep 2019 23:49:33 -0400 Subject: [PATCH 47/93] fix event modifiers --- .../wrappers/shared/add_event_handlers.ts | 42 ++++++++----------- 1 file changed, 18 insertions(+), 24 deletions(-) diff --git a/src/compiler/compile/render_dom/wrappers/shared/add_event_handlers.ts b/src/compiler/compile/render_dom/wrappers/shared/add_event_handlers.ts index 588611de6021..4ef4593c0aa3 100644 --- a/src/compiler/compile/render_dom/wrappers/shared/add_event_handlers.ts +++ b/src/compiler/compile/render_dom/wrappers/shared/add_event_handlers.ts @@ -1,6 +1,9 @@ import Block from '../../Block'; import EventHandler from '../../../nodes/EventHandler'; -import { x } from 'code-red'; +import { x, p } from 'code-red'; + +const TRUE = x`true`; +const FALSE = x`false`; export default function add_event_handlers( block: Block, @@ -13,33 +16,24 @@ export default function add_event_handlers( if (handler.modifiers.has('stopPropagation')) snippet = x`@stop_propagation(${snippet})`; if (handler.modifiers.has('self')) snippet = x`@self(${snippet})`; - // let opts_string = ''; - - // if (block.renderer.options.dev) { - // if (handler.modifiers.has('stopPropagation')) { - // opts_string = ', true'; - // } - - // if (handler.modifiers.has('preventDefault')) { - // opts_string = ', true' + opts_string; - // } else if (opts_string) { - // opts_string = ', false' + opts_string; - // } - // } + const args = []; - // const opts = ['passive', 'once', 'capture'].filter(mod => handler.modifiers.has(mod)); - // if (opts.length) { - // opts_string = (opts.length === 1 && opts[0] === 'capture') - // ? ', true' - // : `, { ${opts.map(opt => `${opt}: true`).join(', ')} }`; - // } else if (opts_string) { - // opts_string = ', false' + opts_string; - // } + const opts = ['passive', 'once', 'capture'].filter(mod => handler.modifiers.has(mod)); + if (opts.length) { + args.push((opts.length === 1 && opts[0] === 'capture') + ? TRUE + : x`{ ${opts.map(opt => p`${opt}: true`)} }`); + } else if (block.renderer.options.dev) { + args.push(FALSE); + } - // TODO modifiers + if (block.renderer.options.dev) { + args.push(handler.modifiers.has('stopPropagation') ? TRUE : FALSE); + args.push(handler.modifiers.has('preventDefault') ? TRUE : FALSE); + } block.event_listeners.push( - x`@listen(${target}, "${handler.name}", ${snippet})` + x`@listen(${target}, "${handler.name}", ${snippet}, ${args})` ); }); } From eec4bd14e0da12040a1361547b29d38696e0016a Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Sat, 21 Sep 2019 00:04:14 -0400 Subject: [PATCH 48/93] so close, 4 left --- src/compiler/compile/Component.ts | 4 +++- src/compiler/compile/render_dom/wrappers/Window.ts | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/compiler/compile/Component.ts b/src/compiler/compile/Component.ts index c2f6ad901036..902a0d975627 100644 --- a/src/compiler/compile/Component.ts +++ b/src/compiler/compile/Component.ts @@ -831,7 +831,9 @@ export default class Component { }); }); - return Array.from(deps).map(n => x`$$invalidate('${n}', ${n})`); + return Array.from(deps) + .map(n => x`$$invalidate('${n}', ${n})`) + .reduce((lhs, rhs) => x`${lhs}, ${rhs}}`); } rewrite_props(get_insert: (variable: Var) => Node[]) { diff --git a/src/compiler/compile/render_dom/wrappers/Window.ts b/src/compiler/compile/render_dom/wrappers/Window.ts index 7c4c351da43c..ce63a431d42b 100644 --- a/src/compiler/compile/render_dom/wrappers/Window.ts +++ b/src/compiler/compile/render_dom/wrappers/Window.ts @@ -127,7 +127,7 @@ export default class WindowWrapper extends Wrapper { component.partly_hoisted.push(b` function ${id}() { - ${props.map(prop => x`$$invalidate('${prop.name}', ${prop.name} = @_window.${prop.value});`)} + ${props.map(prop => b`$$invalidate('${prop.name}', ${prop.name} = @_window.${prop.value});`)} } `); From 0d8bdee83c0742e893081e3224c2e511ea2d6673 Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Sat, 21 Sep 2019 09:00:27 -0400 Subject: [PATCH 49/93] deep destructuring in each block --- src/compiler/compile/nodes/EachBlock.ts | 12 ++++++------ src/compiler/compile/render_dom/index.ts | 2 +- .../samples/invalidation-in-if-condition/_config.js | 1 - .../_config.js | 1 - 4 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/compiler/compile/nodes/EachBlock.ts b/src/compiler/compile/nodes/EachBlock.ts index 876646ea9c47..6a1f21cfd9b6 100644 --- a/src/compiler/compile/nodes/EachBlock.ts +++ b/src/compiler/compile/nodes/EachBlock.ts @@ -4,7 +4,7 @@ import map_children from './shared/map_children'; import TemplateScope from './shared/TemplateScope'; import AbstractBlock from './shared/AbstractBlock'; import Element from './Element'; -import { x } from 'code-red'; +import { x, p } from 'code-red'; import { Node, Identifier } from 'estree'; interface Context { @@ -24,9 +24,9 @@ function unpack_destructuring(contexts: Context[], node: Node, modifier: (node: } else if (node.type === 'ArrayPattern') { node.elements.forEach((element, i) => { if (element && (element as any).type === 'RestIdentifier') { - unpack_destructuring(contexts, element, node => x`${node}.slice(${i})` as Node); + unpack_destructuring(contexts, element, node => x`${modifier(node)}.slice(${i})` as Node); } else { - unpack_destructuring(contexts, element, node => x`${node}[${i}]` as Node); + unpack_destructuring(contexts, element, node => x`${modifier(node)}[${i}]` as Node); } }); } else if (node.type === 'ObjectPattern') { @@ -37,12 +37,12 @@ function unpack_destructuring(contexts: Context[], node: Node, modifier: (node: unpack_destructuring( contexts, property.value, - node => x`@object_without_properties(${node}, ${JSON.stringify(used_properties)})` as Node + node => x`@object_without_properties(${modifier(node)}, [${used_properties}])` as Node ); } else { - used_properties.push((property.key as Identifier).name); + used_properties.push(x`"${(property.key as Identifier).name}"`); - unpack_destructuring(contexts, property.value, node => x`${node}.${(property.key as Identifier).name}` as Node); + unpack_destructuring(contexts, property.value, node => x`${modifier(node)}.${(property.key as Identifier).name}` as Node); } }); } diff --git a/src/compiler/compile/render_dom/index.ts b/src/compiler/compile/render_dom/index.ts index b4a38ff0c77f..3f8f2c133046 100644 --- a/src/compiler/compile/render_dom/index.ts +++ b/src/compiler/compile/render_dom/index.ts @@ -404,7 +404,7 @@ export default function dom( ${unknown_props_check} - ${component.slots.size && b`let { $$slots = {}, $$scope } = $$props;`} + ${component.slots.size ? b`let { $$slots = {}, $$scope } = $$props;` : null} ${renderer.binding_groups.length > 0 && b`const $$binding_groups = [${renderer.binding_groups.map(_ => x`[]`)}];`} diff --git a/test/runtime/samples/invalidation-in-if-condition/_config.js b/test/runtime/samples/invalidation-in-if-condition/_config.js index 60b02d993488..27209c75c92f 100644 --- a/test/runtime/samples/invalidation-in-if-condition/_config.js +++ b/test/runtime/samples/invalidation-in-if-condition/_config.js @@ -1,5 +1,4 @@ export default { - show: 1, html: ``, async test({ assert, target, window }) { diff --git a/test/runtime/samples/reactive-values-implicit-self-dependency/_config.js b/test/runtime/samples/reactive-values-implicit-self-dependency/_config.js index d7f2bbf920ac..f215de098e97 100644 --- a/test/runtime/samples/reactive-values-implicit-self-dependency/_config.js +++ b/test/runtime/samples/reactive-values-implicit-self-dependency/_config.js @@ -1,5 +1,4 @@ export default { - show: 1, html: `

1 / 1

`, From cd83265fa87a20405e224869255a89b75823679d Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Sat, 21 Sep 2019 09:18:22 -0400 Subject: [PATCH 50/93] dont overwrite const props --- src/compiler/compile/Component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/compile/Component.ts b/src/compiler/compile/Component.ts index 902a0d975627..c4d18ec4ce1b 100644 --- a/src/compiler/compile/Component.ts +++ b/src/compiler/compile/Component.ts @@ -881,7 +881,7 @@ export default class Component { const { name } = declarator.id; const variable = component.var_lookup.get(name); - if (variable.export_name) { + if (variable.export_name && variable.writable) { const insert = variable.subscribable ? get_insert(variable) : null; From 3d9943d8d402872ed975564ba1af796104c0c971 Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Sat, 21 Sep 2019 09:43:37 -0400 Subject: [PATCH 51/93] fix aliased props --- src/compiler/compile/Component.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/compiler/compile/Component.ts b/src/compiler/compile/Component.ts index c4d18ec4ce1b..dd6f100ea6e3 100644 --- a/src/compiler/compile/Component.ts +++ b/src/compiler/compile/Component.ts @@ -893,10 +893,10 @@ export default class Component { properties: [{ type: 'Property', method: false, - shorthand: true, + shorthand: false, computed: false, kind: 'init', - key: declarator.id, + key: { type: 'Identifier', name: variable.export_name }, value: declarator.init ? { type: 'AssignmentPattern', From c6dfd8c2d1e9ad2cedbfdcc04e3647ecebfc934c Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Sat, 21 Sep 2019 10:00:34 -0400 Subject: [PATCH 52/93] quality of life improvement --- test/runtime/index.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/runtime/index.js b/test/runtime/index.js index 28ef9e4d789d..7b8986576ad4 100644 --- a/test/runtime/index.js +++ b/test/runtime/index.js @@ -197,6 +197,11 @@ describe.only("runtime", () => { throw err; } }) + .catch(err => { + // print a clickable link to open the directory + err.stack += `\n\ncmd-click: ${path.relative(process.cwd(), cwd)}/main.svelte`; + throw err; + }) .then(() => { if (config.show) { showOutput(cwd, compileOptions, compile); From 734839095771c167370d1c38226edd463e0f88cc Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Sat, 21 Sep 2019 10:29:07 -0400 Subject: [PATCH 53/93] all client-side runtime tests passing! --- src/compiler/compile/Component.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/compiler/compile/Component.ts b/src/compiler/compile/Component.ts index dd6f100ea6e3..4de3da668718 100644 --- a/src/compiler/compile/Component.ts +++ b/src/compiler/compile/Component.ts @@ -859,6 +859,8 @@ export default class Component { // const next = node.declarations[i + 1]; if (declarator.id.type !== 'Identifier') { + const inserts = []; + extract_names(declarator.id).forEach(name => { const variable = component.var_lookup.get(name); @@ -871,10 +873,14 @@ export default class Component { } if (variable.subscribable) { - // TODO + inserts.push(get_insert(variable)); } }); + if (inserts.length) { + parent[key].splice(index + 1, 0, ...inserts); + } + return; } From e3c98cf2791c5b4820fcb93c117b5e70fca53121 Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Sat, 21 Sep 2019 10:57:48 -0400 Subject: [PATCH 54/93] fix hydration --- src/compiler/compile/render_dom/Renderer.ts | 2 +- src/compiler/compile/render_dom/wrappers/AwaitBlock.ts | 2 +- src/compiler/compile/render_dom/wrappers/EachBlock.ts | 4 ++-- .../compile/render_dom/wrappers/Element/index.ts | 10 +++++----- src/compiler/compile/render_dom/wrappers/Head.ts | 2 +- src/compiler/compile/render_dom/wrappers/IfBlock.ts | 2 +- .../render_dom/wrappers/InlineComponent/index.ts | 2 +- test/runtime/index.js | 2 +- 8 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/compiler/compile/render_dom/Renderer.ts b/src/compiler/compile/render_dom/Renderer.ts index 81fd4afe7840..cf148df30405 100644 --- a/src/compiler/compile/render_dom/Renderer.ts +++ b/src/compiler/compile/render_dom/Renderer.ts @@ -59,6 +59,6 @@ export default class Renderer { this.block.assign_variable_names(); - this.fragment.render(this.block, null, x`nodes` as Identifier); + this.fragment.render(this.block, null, x`#nodes` as Identifier); } } diff --git a/src/compiler/compile/render_dom/wrappers/AwaitBlock.ts b/src/compiler/compile/render_dom/wrappers/AwaitBlock.ts index 2dff7a4a1441..0a4262181eda 100644 --- a/src/compiler/compile/render_dom/wrappers/AwaitBlock.ts +++ b/src/compiler/compile/render_dom/wrappers/AwaitBlock.ts @@ -234,7 +234,7 @@ export default class AwaitBlockWrapper extends Wrapper { `); [this.pending, this.then, this.catch].forEach(branch => { - branch.fragment.render(branch.block, null, x`nodes` as Identifier); + branch.fragment.render(branch.block, null, x`#nodes` as Identifier); }); } } diff --git a/src/compiler/compile/render_dom/wrappers/EachBlock.ts b/src/compiler/compile/render_dom/wrappers/EachBlock.ts index 3caa78a95714..c5f6b0766d88 100644 --- a/src/compiler/compile/render_dom/wrappers/EachBlock.ts +++ b/src/compiler/compile/render_dom/wrappers/EachBlock.ts @@ -300,10 +300,10 @@ export default class EachBlockWrapper extends Wrapper { `); } - this.fragment.render(this.block, null, x`nodes` as Identifier); + this.fragment.render(this.block, null, x`#nodes` as Identifier); if (this.else) { - this.else.fragment.render(this.else.block, null, x`nodes` as Identifier); + this.else.fragment.render(this.else.block, null, x`#nodes` as Identifier); } } diff --git a/src/compiler/compile/render_dom/wrappers/Element/index.ts b/src/compiler/compile/render_dom/wrappers/Element/index.ts index 788624b820a0..a8e7ad40a44a 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/index.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/index.ts @@ -264,7 +264,7 @@ export default class ElementWrapper extends Wrapper { if (parent_nodes) { block.chunks.claim.push(b` ${node} = ${this.get_claim_statement(parent_nodes)}; - var ${nodes} = @children(${this.node.name === 'template' ? `${node}.content` : node}); + var ${nodes} = @children(${this.node.name === 'template' ? x`${node}.content` : node}); `); } else { block.chunks.claim.push( @@ -321,7 +321,7 @@ export default class ElementWrapper extends Wrapper { this.fragment.nodes.forEach((child: Wrapper) => { child.render( block, - this.node.name === 'template' ? `${node}.content` : node, + this.node.name === 'template' ? x`${node}.content` : node, nodes ); }); @@ -387,9 +387,9 @@ export default class ElementWrapper extends Wrapper { ? this.node.name : this.node.name.toUpperCase(); - return x`@claim_element(${nodes}, "${name}", ${attributes - ? x`{ ${attributes} }` - : x`{}`}, ${this.node.namespace === namespaces.svg ? true : false})`; + const svg = this.node.namespace === namespaces.svg ? 1 : null; + + return x`@claim_element(${nodes}, "${name}", { ${attributes} }, ${svg})`; } add_bindings(block: Block) { diff --git a/src/compiler/compile/render_dom/wrappers/Head.ts b/src/compiler/compile/render_dom/wrappers/Head.ts index 3c9d9f9ad1b6..188c26931ada 100644 --- a/src/compiler/compile/render_dom/wrappers/Head.ts +++ b/src/compiler/compile/render_dom/wrappers/Head.ts @@ -32,6 +32,6 @@ export default class HeadWrapper extends Wrapper { } render(block: Block, _parent_node: Identifier, _parent_nodes: Identifier) { - this.fragment.render(block, x`@_document.head` as unknown as Identifier, x`nodes` as unknown as Identifier); + this.fragment.render(block, x`@_document.head` as unknown as Identifier, x`#nodes` as unknown as Identifier); } } diff --git a/src/compiler/compile/render_dom/wrappers/IfBlock.ts b/src/compiler/compile/render_dom/wrappers/IfBlock.ts index 38826f034f9a..f521c9399ec8 100644 --- a/src/compiler/compile/render_dom/wrappers/IfBlock.ts +++ b/src/compiler/compile/render_dom/wrappers/IfBlock.ts @@ -235,7 +235,7 @@ export default class IfBlockWrapper extends Wrapper { } this.branches.forEach(branch => { - branch.fragment.render(branch.block, null, x`nodes` as unknown as Identifier); + branch.fragment.render(branch.block, null, x`#nodes` as unknown as Identifier); }); } diff --git a/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts b/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts index 86bb0bf15d72..3a0646491928 100644 --- a/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts +++ b/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts @@ -157,7 +157,7 @@ export default class InlineComponentWrapper extends Wrapper { const default_slot = this.slots.get('default'); this.fragment.nodes.forEach((child) => { - child.render(default_slot.block, null, x`nodes` as unknown as Identifier); + child.render(default_slot.block, null, x`#nodes` as unknown as Identifier); }); } diff --git a/test/runtime/index.js b/test/runtime/index.js index 7b8986576ad4..7bc2f18e56d5 100644 --- a/test/runtime/index.js +++ b/test/runtime/index.js @@ -216,7 +216,7 @@ describe.only("runtime", () => { fs.readdirSync("test/runtime/samples").forEach(dir => { runTest(dir, false); - // runTest(dir, true); + runTest(dir, true); }); async function create_component(src = '
') { From a2e96dbaba2c88fc72f4822324e09cb3e4a9e6f0 Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Sat, 21 Sep 2019 12:38:54 -0400 Subject: [PATCH 55/93] basic SSR working --- src/compiler/compile/Component.ts | 2 +- src/compiler/compile/render_ssr/Renderer.ts | 45 +++++++++-- .../compile/render_ssr/handlers/Element.ts | 75 ++++++++++--------- .../render_ssr/handlers/InlineComponent.ts | 31 ++++---- .../compile/render_ssr/handlers/Tag.ts | 12 +-- .../compile/render_ssr/handlers/Text.ts | 5 +- src/compiler/compile/render_ssr/index.ts | 36 ++++----- test/helpers.js | 22 +++--- test/runtime/index.js | 2 +- test/server-side-rendering/index.js | 3 +- 10 files changed, 137 insertions(+), 96 deletions(-) diff --git a/src/compiler/compile/Component.ts b/src/compiler/compile/Component.ts index 4de3da668718..b477dcafbeb5 100644 --- a/src/compiler/compile/Component.ts +++ b/src/compiler/compile/Component.ts @@ -837,7 +837,7 @@ export default class Component { } rewrite_props(get_insert: (variable: Var) => Node[]) { - // TODO + if (!this.ast.instance) return; const component = this; const { instance_scope, instance_scope_map: map } = this; diff --git a/src/compiler/compile/render_ssr/Renderer.ts b/src/compiler/compile/render_ssr/Renderer.ts index 9680866349ae..37d6f3f5b202 100644 --- a/src/compiler/compile/render_ssr/Renderer.ts +++ b/src/compiler/compile/render_ssr/Renderer.ts @@ -13,6 +13,7 @@ import Text from './handlers/Text'; import Title from './handlers/Title'; import { AppendTarget, CompileOptions } from '../../interfaces'; import { INode } from '../nodes/interfaces'; +import { Expression } from 'estree'; type Handler = (node: any, renderer: Renderer, options: CompileOptions) => void; @@ -43,17 +44,45 @@ export interface RenderOptions extends CompileOptions{ export default class Renderer { has_bindings = false; - code = ''; + + state = { + quasi: { + type: 'TemplateElement', + value: { raw: '' } + } + }; + + literal = { + type: 'TemplateLiteral', + expressions: [], + quasis: [] + }; + targets: AppendTarget[] = []; append(code: string) { - if (this.targets.length) { - const target = this.targets[this.targets.length - 1]; - const slot_name = target.slot_stack[target.slot_stack.length - 1]; - target.slots[slot_name] += code; - } else { - this.code += code; - } + throw new Error('no more append'); + // if (this.targets.length) { + // const target = this.targets[this.targets.length - 1]; + // const slot_name = target.slot_stack[target.slot_stack.length - 1]; + // target.slots[slot_name] += code; + // } else { + // this.code += code; + // } + } + + add_string(str: string) { + this.state.quasi.value.raw += str; + } + + add_expression(node: Expression) { + this.literal.quasis.push(this.state.quasi); + this.literal.expressions.push(node); + + this.state.quasi = { + type: 'TemplateElement', + value: { raw: '' } + }; } render(nodes: INode[], options: RenderOptions) { diff --git a/src/compiler/compile/render_ssr/handlers/Element.ts b/src/compiler/compile/render_ssr/handlers/Element.ts index e9704331b1da..38addbfe4a34 100644 --- a/src/compiler/compile/render_ssr/handlers/Element.ts +++ b/src/compiler/compile/render_ssr/handlers/Element.ts @@ -1,12 +1,12 @@ import { is_void, quote_prop_if_necessary, quote_name_if_necessary } from '../../../utils/names'; import Attribute from '../../nodes/Attribute'; import Class from '../../nodes/Class'; -import { snip } from '../../utils/snip'; import { stringify_attribute, stringify_class_attribute } from '../../utils/stringify_attribute'; import { get_slot_scope } from './shared/get_slot_scope'; import Renderer, { RenderOptions } from '../Renderer'; import Element from '../../nodes/Element'; import Text from '../../nodes/Text'; +import { x } from 'code-red'; // source: https://gist.github.com/ArjanSchouten/0b8574a6ad7f5065a5e7 const boolean_attributes = new Set([ @@ -52,7 +52,7 @@ const boolean_attributes = new Set([ export default function(node: Element, renderer: Renderer, options: RenderOptions & { slot_scopes: Map; }) { - let opening_tag = `<${node.name}`; + renderer.add_string(`<${node.name}`); // awkward special case let node_contents; @@ -96,29 +96,29 @@ export default function(node: Element, renderer: Renderer, options: RenderOption const args = []; node.attributes.forEach(attribute => { if (attribute.is_spread) { - args.push(snip(attribute.expression)); + args.push(attribute.expression.node); } else { if (attribute.name === 'value' && node.name === 'textarea') { node_contents = stringify_attribute(attribute, true); } else if (attribute.is_true) { - args.push(`{ ${quote_name_if_necessary(attribute.name)}: true }`); + args.push(x`{ ${attribute.name}: true }`); } else if ( boolean_attributes.has(attribute.name) && attribute.chunks.length === 1 && attribute.chunks[0].type !== 'Text' ) { // a boolean attribute with one non-Text chunk - args.push(`{ ${quote_name_if_necessary(attribute.name)}: ${snip(attribute.chunks[0])} }`); + args.push(x`{ ${attribute.name}: ${attribute.chunks[0].node} }`); } else if (attribute.name === 'class' && class_expression) { // Add class expression - args.push(`{ ${quote_name_if_necessary(attribute.name)}: [\`${stringify_class_attribute(attribute)}\`, \`\${${class_expression}}\`].join(' ').trim() }`); + args.push(x`{ ${attribute.name}: [${stringify_class_attribute(attribute)}, ${class_expression}}].join(' ').trim() }`); } else { - args.push(`{ ${quote_name_if_necessary(attribute.name)}: \`${attribute.name === 'class' ? stringify_class_attribute(attribute) : stringify_attribute(attribute, true)}\` }`); + args.push(x`{ ${attribute.name}: ${attribute.name === 'class' ? stringify_class_attribute(attribute) : stringify_attribute(attribute, true)} }`); } } }); - opening_tag += "${@spread([" + args.join(', ') + "])}"; + renderer.add_expression(x`@spread([${args}])`); } else { node.attributes.forEach((attribute: Attribute) => { if (attribute.type !== 'Attribute') return; @@ -126,23 +126,32 @@ export default function(node: Element, renderer: Renderer, options: RenderOption if (attribute.name === 'value' && node.name === 'textarea') { node_contents = stringify_attribute(attribute, true); } else if (attribute.is_true) { - opening_tag += ` ${attribute.name}`; + renderer.add_string(` ${attribute.name}`); } else if ( boolean_attributes.has(attribute.name) && attribute.chunks.length === 1 && attribute.chunks[0].type !== 'Text' ) { // a boolean attribute with one non-Text chunk - opening_tag += '${' + snip(attribute.chunks[0]) + ' ? " ' + attribute.name + '" : "" }'; + throw new Error('here'); + renderer.add_expression(x`${attribute.chunks[0]} ? "${attribute.name}" : ""`); } else if (attribute.name === 'class' && class_expression) { add_class_attribute = false; - opening_tag += ` class="\${[\`${stringify_class_attribute(attribute)}\`, ${class_expression}].join(' ').trim() }"`; + renderer.add_string(` class="`); + renderer.add_expression(x`[${stringify_class_attribute(attribute)}, ${class_expression}].join(' ').trim()`); + renderer.add_string(`"`); } else if (attribute.chunks.length === 1 && attribute.chunks[0].type !== 'Text') { const { name } = attribute; - const snippet = snip(attribute.chunks[0]); - opening_tag += '${@add_attribute("' + name + '", ' + snippet + ', ' + (boolean_attributes.has(name) ? 1 : 0) + ')}'; + const snippet = attribute.chunks[0].node; + console.log(snippet); + renderer.add_expression(x`@add_attribute("${name}", ${snippet}, ${boolean_attributes.has(name) ? 1 : 0})`); } else { - opening_tag += ` ${attribute.name}="${attribute.name === 'class' ? stringify_class_attribute(attribute) : stringify_attribute(attribute, true)}"`; + renderer.add_string(` ${attribute.name}="`); + attribute.chunks.forEach(chunk => { + if (chunk.type === 'Text') renderer.add_string(chunk.data); + else renderer.add_expression(x`@escape(${chunk.node})`); + }); + renderer.add_string(`"`); } }); } @@ -157,38 +166,36 @@ export default function(node: Element, renderer: Renderer, options: RenderOption if (name === 'group') { // TODO server-render group bindings } else if (contenteditable && (name === 'textContent' || name === 'innerHTML')) { - node_contents = snip(expression); - value = name === 'textContent' ? '@escape($$value)' : '$$value'; + node_contents = expression.node; + value = name === 'textContent' ? x`@escape($$value)` : x`$$value`; } else if (binding.name === 'value' && node.name === 'textarea') { - const snippet = snip(expression); - node_contents = '${(' + snippet + ') || ""}'; + const snippet = expression.node; + node_contents = x`${snippet} || ""`; } else { - const snippet = snip(expression); - opening_tag += '${@add_attribute("' + name + '", ' + snippet + ', 1)}'; + const snippet = expression.node; + renderer.add_expression(x`@add_attribute("${name}", ${snippet}, 1)`); } }); - if (add_class_attribute) { - opening_tag += `\${@add_classes([${class_expression}].join(' ').trim())}`; - } - - opening_tag += '>'; + // if (add_class_attribute) { + // opening_tag += `\${@add_classes([${class_expression}].join(' ').trim())}`; + // } - renderer.append(opening_tag); + renderer.add_string('>'); if (node_contents !== undefined) { - if (contenteditable) { - renderer.append('${($$value => $$value === void 0 ? `'); - renderer.render(node.children, options); - renderer.append('` : ' + value + ')(' + node_contents + ')}'); - } else { - renderer.append(node_contents); - } + // if (contenteditable) { + // renderer.append('${($$value => $$value === void 0 ? `'); + // renderer.render(node.children, options); + // renderer.append('` : ' + value + ')(' + node_contents + ')}'); + // } else { + // renderer.append(node_contents); + // } } else { renderer.render(node.children, options); } if (!is_void(node.name)) { - renderer.append(``); + renderer.add_string(``); } } diff --git a/src/compiler/compile/render_ssr/handlers/InlineComponent.ts b/src/compiler/compile/render_ssr/handlers/InlineComponent.ts index 3bab0cfcf328..34a8055e98a5 100644 --- a/src/compiler/compile/render_ssr/handlers/InlineComponent.ts +++ b/src/compiler/compile/render_ssr/handlers/InlineComponent.ts @@ -1,6 +1,5 @@ -import { escape, escape_template, stringify } from '../../utils/stringify'; +import { escape, escape_template, stringify, string_literal } from '../../utils/stringify'; import { quote_name_if_necessary } from '../../../utils/names'; -import { snip } from '../../utils/snip'; import Renderer, { RenderOptions } from '../Renderer'; import { get_slot_scope } from './shared/get_slot_scope'; import { AppendTarget } from '../../../interfaces'; @@ -18,19 +17,15 @@ function stringify_attribute(chunk: INode) { } function get_attribute_value(attribute) { - if (attribute.is_true) return `true`; - if (attribute.chunks.length === 0) return `''`; - - if (attribute.chunks.length === 1) { - const chunk = attribute.chunks[0]; - if (chunk.type === 'Text') { - return stringify(chunk.data); - } - - return snip(chunk); - } - - return '`' + attribute.chunks.map(stringify_attribute).join('') + '`'; + if (attribute.is_true) return x`true`; + if (attribute.chunks.length === 0) return x`''`; + + return attribute.chunks + .map(chunk => { + if (chunk.type === 'Text') return string_literal(chunk.data); + return chunk.node; + }) + .reduce((lhs, rhs) => x`${lhs} + ${rhs}`); } export default function(node: InlineComponent, renderer: Renderer, options: RenderOptions) { @@ -41,7 +36,7 @@ export default function(node: InlineComponent, renderer: Renderer, options: Rend renderer.has_bindings = true; // TODO this probably won't work for contextual bindings - const snippet = snip(binding.expression); + const snippet = binding.expression.node; binding_props.push(p`${binding.name}: ${snippet}`); binding_fns.push(p`${binding.name}: $$value => { ${snippet} = $$value; $$settled = false }`); @@ -66,7 +61,7 @@ export default function(node: InlineComponent, renderer: Renderer, options: Rend })`; } else { props = x`{ - ${node.attributes.map(attribute => p`${attribute.name}: ${get_attribute_value(attribute)}`)} + ${node.attributes.map(attribute => p`${attribute.name}: ${get_attribute_value(attribute)}`)}, ${binding_props} }`; } @@ -115,5 +110,5 @@ export default function(node: InlineComponent, renderer: Renderer, options: Rend ${slot_fns} }`; - renderer.append(`\${@validate_component(${expression}, '${node.name}').$$render($$result, ${props}, ${bindings}, ${slots})}`); + renderer.add_expression(x`@validate_component(${expression}, "${node.name}").$$render($$result, ${props}, ${bindings}, ${slots})`); } diff --git a/src/compiler/compile/render_ssr/handlers/Tag.ts b/src/compiler/compile/render_ssr/handlers/Tag.ts index 353939049d25..45c0c1908936 100644 --- a/src/compiler/compile/render_ssr/handlers/Tag.ts +++ b/src/compiler/compile/render_ssr/handlers/Tag.ts @@ -1,13 +1,15 @@ -import { snip } from '../../utils/snip'; + import Renderer, { RenderOptions } from '../Renderer'; +import { x } from 'code-red'; + export default function(node, renderer: Renderer, _options: RenderOptions) { - const snippet = snip(node.expression); + const snippet = node.expression.node; - renderer.append( + renderer.add_expression( node.parent && node.parent.type === 'Element' && node.parent.name === 'style' - ? '${' + snippet + '}' - : '${@escape(' + snippet + ')}' + ? snippet + : x`@escape(${snippet})` ); } diff --git a/src/compiler/compile/render_ssr/handlers/Text.ts b/src/compiler/compile/render_ssr/handlers/Text.ts index 5e56952f1329..b86b79bdb9c8 100644 --- a/src/compiler/compile/render_ssr/handlers/Text.ts +++ b/src/compiler/compile/render_ssr/handlers/Text.ts @@ -1,4 +1,4 @@ -import { escape_html, escape_template, escape } from '../../utils/stringify'; +import { escape_html } from '../../utils/stringify'; import Renderer, { RenderOptions } from '../Renderer'; import Text from '../../nodes/Text'; import Element from '../../nodes/Element'; @@ -13,5 +13,6 @@ export default function(node: Text, renderer: Renderer, _options: RenderOptions) // unless this Text node is inside a -{#each items as item, j} -
{item}
-{/each} \ No newline at end of file +

Current state: {state}

+ +
    + {#each states as state} +
  • {state}
  • + {/each} +
\ No newline at end of file From 16b4897abfe79c22bf7091f0a34fbfde04afa57a Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Sat, 21 Sep 2019 21:37:08 -0400 Subject: [PATCH 62/93] various --- src/compiler/compile/render_ssr/Renderer.ts | 2 +- .../compile/render_ssr/handlers/Element.ts | 18 ++++++++++-------- src/compiler/compile/render_ssr/index.ts | 10 +++++----- src/compiler/compile/utils/get_slot_data.ts | 14 +------------- 4 files changed, 17 insertions(+), 27 deletions(-) diff --git a/src/compiler/compile/render_ssr/Renderer.ts b/src/compiler/compile/render_ssr/Renderer.ts index b0c122656487..096257d22ecb 100644 --- a/src/compiler/compile/render_ssr/Renderer.ts +++ b/src/compiler/compile/render_ssr/Renderer.ts @@ -46,7 +46,7 @@ export default class Renderer { has_bindings = false; stack: { current: { value: string }, literal: TemplateLiteral }[] = []; - current: { value: string }; + current: { value: string }; // TODO can it just be `current: string`? literal: TemplateLiteral; targets: AppendTarget[] = []; diff --git a/src/compiler/compile/render_ssr/handlers/Element.ts b/src/compiler/compile/render_ssr/handlers/Element.ts index f8f281de0ade..2716e924b16d 100644 --- a/src/compiler/compile/render_ssr/handlers/Element.ts +++ b/src/compiler/compile/render_ssr/handlers/Element.ts @@ -81,11 +81,13 @@ export default function(node: Element, renderer: Renderer, options: RenderOption // options.slot_scopes.set(slot_name, get_slot_scope(node.lets)); // } - const class_expression = node.classes.map((class_directive: Class) => { - const { expression, name } = class_directive; - const snippet = expression ? snip(expression) : `#ctx${quote_prop_if_necessary(name)}`; - return `${snippet} ? "${name}" : ""`; - }).join(', '); + const class_expression = node.classes.length > 0 && node.classes + .map((class_directive: Class) => { + const { expression, name } = class_directive; + const snippet = expression ? expression.node : x`#ctx.${name}`; + return x`${snippet} ? "${name}" : ""`; + }) + .reduce((lhs, rhs) => x`${lhs} + ${rhs}`); let add_class_attribute = class_expression ? true : false; @@ -171,9 +173,9 @@ export default function(node: Element, renderer: Renderer, options: RenderOption } }); - // if (add_class_attribute) { - // opening_tag += `\${@add_classes([${class_expression}].join(' ').trim())}`; - // } + if (add_class_attribute) { + renderer.add_expression(x`@add_classes([${class_expression}].join(' ').trim())`); + } renderer.add_string('>'); diff --git a/src/compiler/compile/render_ssr/index.ts b/src/compiler/compile/render_ssr/index.ts index f979df1b7b76..a22e7fee0d61 100644 --- a/src/compiler/compile/render_ssr/index.ts +++ b/src/compiler/compile/render_ssr/index.ts @@ -70,7 +70,7 @@ export default function ssr( : []; const reactive_declarations = component.reactive_declarations.map(d => { - let snippet = b`${d.node}`; + let statement = b`${d.node.body}`; if (d.declaration) { const declared = extract_names(d.declaration); @@ -88,16 +88,16 @@ export default function ssr( declared.length > injected.length ); - snippet = separate + statement = separate ? b` ${injected.map(name => b`let ${name};`)} - ${snippet}` + ${statement}` : b` - let ${snippet}`; + let ${d.node.body.expression.left} = ${d.node.body.expression.right}`; } } - return snippet; + return statement; }); const main = renderer.has_bindings diff --git a/src/compiler/compile/utils/get_slot_data.ts b/src/compiler/compile/utils/get_slot_data.ts index cb42cece7e94..18df4e311816 100644 --- a/src/compiler/compile/utils/get_slot_data.ts +++ b/src/compiler/compile/utils/get_slot_data.ts @@ -8,25 +8,13 @@ export default function get_slot_data(values: Map, is_ssr: bo properties: Array.from(values.values()) .filter(attribute => attribute.name !== 'name') .map(attribute => { - if (is_ssr) { - throw new Error(`TODO SSR`); - } - const value = get_value(attribute); - - // const value = attribute.is_true - // ? x`true` - // : attribute.chunks.length === 0 - // ? x`""` - // : attribute.chunks.length === 1 && attribute.chunks[0].type !== 'Text' - // ? snip(attribute.chunks[0]) - // : '`' + stringify_attribute(attribute, is_ssr) + '`'; - return p`${attribute.name}: ${value}`; }) } } +// TODO fairly sure this is duplicated at least once function get_value(attribute: Attribute) { if (attribute.is_true) return x`true`; if (attribute.chunks.length === 0) return x`""`; From 91459bd755f815707db4a7f5037882211c2667d3 Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Sat, 21 Sep 2019 21:42:47 -0400 Subject: [PATCH 63/93] fixes --- src/compiler/compile/render_ssr/handlers/Element.ts | 2 +- src/compiler/compile/render_ssr/handlers/InlineComponent.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/compiler/compile/render_ssr/handlers/Element.ts b/src/compiler/compile/render_ssr/handlers/Element.ts index 2716e924b16d..87bcc5e39067 100644 --- a/src/compiler/compile/render_ssr/handlers/Element.ts +++ b/src/compiler/compile/render_ssr/handlers/Element.ts @@ -87,7 +87,7 @@ export default function(node: Element, renderer: Renderer, options: RenderOption const snippet = expression ? expression.node : x`#ctx.${name}`; return x`${snippet} ? "${name}" : ""`; }) - .reduce((lhs, rhs) => x`${lhs} + ${rhs}`); + .reduce((lhs, rhs) => x`${lhs} + ' ' + ${rhs}`); let add_class_attribute = class_expression ? true : false; diff --git a/src/compiler/compile/render_ssr/handlers/InlineComponent.ts b/src/compiler/compile/render_ssr/handlers/InlineComponent.ts index 78ffe13f971e..6484edcb7619 100644 --- a/src/compiler/compile/render_ssr/handlers/InlineComponent.ts +++ b/src/compiler/compile/render_ssr/handlers/InlineComponent.ts @@ -45,7 +45,7 @@ export default function(node: InlineComponent, renderer: Renderer, options: Rend return x`{ ${attribute.name}: ${get_prop_value(attribute)} }`; } }) - .concat(binding_props.map(p => `{ ${p} }`)) + .concat(binding_props.map(p => x`{ ${p} }`)) })`; } else { props = x`{ From 7a000c290564bd8d1fd833209fa5927be5f8455a Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Sat, 21 Sep 2019 22:01:26 -0400 Subject: [PATCH 64/93] fix slots --- src/compiler/compile/render_ssr/handlers/Element.ts | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/compiler/compile/render_ssr/handlers/Element.ts b/src/compiler/compile/render_ssr/handlers/Element.ts index 87bcc5e39067..dee8add21010 100644 --- a/src/compiler/compile/render_ssr/handlers/Element.ts +++ b/src/compiler/compile/render_ssr/handlers/Element.ts @@ -52,8 +52,6 @@ const boolean_attributes = new Set([ export default function(node: Element, renderer: Renderer, options: RenderOptions & { slot_scopes: Map; }) { - renderer.add_string(`<${node.name}`); - // awkward special case let node_contents; let value; @@ -67,6 +65,12 @@ export default function(node: Element, renderer: Renderer, options: RenderOption const slot = node.get_static_attribute_value('slot'); const nearest_inline_component = node.find_nearest(/InlineComponent/); + if (slot && nearest_inline_component) { + renderer.push(); + } + + renderer.add_string(`<${node.name}`); + // if (slot && nearest_inline_component) { // const slot = node.attributes.find((attribute) => attribute.name === 'slot'); // const slot_name = (slot.chunks[0] as Text).data; @@ -185,12 +189,11 @@ export default function(node: Element, renderer: Renderer, options: RenderOption renderer.render(node.children, options); const result = renderer.pop(); - renderer.add_expression(x`($$value => $$value === void 0 ? ${result} : ${node_contents})`); + renderer.add_expression(x`($$value => $$value === void 0 ? ${result} : $$value)(${node_contents})`); } else { renderer.add_expression(node_contents); } } else if (slot && nearest_inline_component) { - renderer.push(); renderer.render(node.children, options); const lets = node.lets; From 9ba199a716d2e015b944035db34e61fe817d2959 Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Sat, 21 Sep 2019 22:04:45 -0400 Subject: [PATCH 65/93] almost all SSR tests passing --- .../compile/render_ssr/handlers/Element.ts | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/compiler/compile/render_ssr/handlers/Element.ts b/src/compiler/compile/render_ssr/handlers/Element.ts index dee8add21010..8de08c51f37b 100644 --- a/src/compiler/compile/render_ssr/handlers/Element.ts +++ b/src/compiler/compile/render_ssr/handlers/Element.ts @@ -115,7 +115,7 @@ export default function(node: Element, renderer: Renderer, options: RenderOption args.push(x`{ ${attribute.name}: ${attribute.chunks[0].node} }`); } else if (attribute.name === 'class' && class_expression) { // Add class expression - args.push(x`{ ${attribute.name}: [${get_class_attribute_value(attribute)}, ${class_expression}}].join(' ').trim() }`); + args.push(x`{ ${attribute.name}: [${get_class_attribute_value(attribute)}, ${class_expression}].join(' ').trim() }`); } else { args.push(x`{ ${attribute.name}: ${attribute.name === 'class' ? get_class_attribute_value(attribute) : get_attribute_value(attribute, true)} }`); } @@ -193,9 +193,17 @@ export default function(node: Element, renderer: Renderer, options: RenderOption } else { renderer.add_expression(node_contents); } + + if (!is_void(node.name)) { + renderer.add_string(``); + } } else if (slot && nearest_inline_component) { renderer.render(node.children, options); + if (!is_void(node.name)) { + renderer.add_string(``); + } + const lets = node.lets; const seen = new Set(lets.map(l => l.name.name)); @@ -209,9 +217,9 @@ export default function(node: Element, renderer: Renderer, options: RenderOption }); } else { renderer.render(node.children, options); - } - if (!is_void(node.name)) { - renderer.add_string(``); + if (!is_void(node.name)) { + renderer.add_string(``); + } } } From c4a43a36a169138b2943e4c762712cc9b7446043 Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Sat, 21 Sep 2019 22:28:30 -0400 Subject: [PATCH 66/93] ... --- src/compiler/compile/nodes/EachBlock.ts | 11 +++++++++-- src/compiler/compile/nodes/Let.ts | 8 +++++--- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/compiler/compile/nodes/EachBlock.ts b/src/compiler/compile/nodes/EachBlock.ts index 6a1f21cfd9b6..70b3340ce57e 100644 --- a/src/compiler/compile/nodes/EachBlock.ts +++ b/src/compiler/compile/nodes/EachBlock.ts @@ -5,7 +5,7 @@ import TemplateScope from './shared/TemplateScope'; import AbstractBlock from './shared/AbstractBlock'; import Element from './Element'; import { x, p } from 'code-red'; -import { Node, Identifier } from 'estree'; +import { Node, Identifier, RestElement } from 'estree'; interface Context { key: Identifier; @@ -32,8 +32,15 @@ function unpack_destructuring(contexts: Context[], node: Node, modifier: (node: } else if (node.type === 'ObjectPattern') { const used_properties = []; - node.properties.forEach((property) => { + node.properties.forEach((property, i) => { if ((property as any).kind === 'rest') { // TODO is this right? + const replacement: RestElement = { + type: 'RestElement', + argument: property.key as Identifier + } + + node.properties[i] = replacement; + unpack_destructuring( contexts, property.value, diff --git a/src/compiler/compile/nodes/Let.ts b/src/compiler/compile/nodes/Let.ts index de8f73cdd24c..7b92c5ce7085 100644 --- a/src/compiler/compile/nodes/Let.ts +++ b/src/compiler/compile/nodes/Let.ts @@ -16,11 +16,13 @@ export default class Let extends Node { this.name = { type: 'Identifier', name: info.name }; + const { names } = this; + if (info.expression) { this.value = info.expression; walk(info.expression, { - enter: node => { + enter(node) { if (!applicable.has(node.type)) { component.error(node as any, { code: 'invalid-let', @@ -29,7 +31,7 @@ export default class Let extends Node { } if (node.type === 'Identifier') { - this.names.push(node.name); + names.push(node.name); } // slightly unfortunate hack @@ -43,7 +45,7 @@ export default class Let extends Node { } }); } else { - this.names.push(this.name.name); + names.push(this.name.name); } } } \ No newline at end of file From 59035c89d53dfc608b8d19ce1aa57cf25f7ac0bb Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Sat, 21 Sep 2019 22:38:26 -0400 Subject: [PATCH 67/93] all runtime tests passing --- src/compiler/compile/render_ssr/Renderer.ts | 3 ++- test/helpers.js | 2 +- test/server-side-rendering/index.js | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/compiler/compile/render_ssr/Renderer.ts b/src/compiler/compile/render_ssr/Renderer.ts index 096257d22ecb..1f8991995574 100644 --- a/src/compiler/compile/render_ssr/Renderer.ts +++ b/src/compiler/compile/render_ssr/Renderer.ts @@ -14,6 +14,7 @@ import Title from './handlers/Title'; import { AppendTarget, CompileOptions } from '../../interfaces'; import { INode } from '../nodes/interfaces'; import { Expression, TemplateLiteral } from 'estree'; +import { escape_template } from '../utils/stringify'; type Handler = (node: any, renderer: Renderer, options: CompileOptions) => void; @@ -67,7 +68,7 @@ export default class Renderer { } add_string(str: string) { - this.current.value += str; + this.current.value += escape_template(str); } add_expression(node: Expression) { diff --git a/test/helpers.js b/test/helpers.js index 2a40851cd6c5..480b28948b40 100644 --- a/test/helpers.js +++ b/test/helpers.js @@ -47,7 +47,7 @@ export function tryToReadFile(file) { const virtualConsole = new jsdom.VirtualConsole(); virtualConsole.sendTo(console); -global.window = new jsdom.JSDOM('
', {virtualConsole}).window; +const window = new jsdom.JSDOM('
', {virtualConsole}).window; global.document = window.document; global.navigator = window.navigator; global.getComputedStyle = window.getComputedStyle; diff --git a/test/server-side-rendering/index.js b/test/server-side-rendering/index.js index 3e2c812b6cc1..eb2303a794b2 100644 --- a/test/server-side-rendering/index.js +++ b/test/server-side-rendering/index.js @@ -20,7 +20,7 @@ function tryToReadFile(file) { const sveltePath = process.cwd().split('\\').join('/'); -describe.only("ssr", () => { +describe("ssr", () => { before(() => { require("../../register")({ extensions: ['.svelte', '.html'], From 2f7e67e01999b5b25e0740927da4c8064fb443f9 Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Sun, 22 Sep 2019 10:33:20 -0400 Subject: [PATCH 68/93] fix some CSS stuff --- src/compiler/compile/render_dom/index.ts | 16 +++++++--------- src/compiler/compile/render_ssr/index.ts | 4 ++-- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/compiler/compile/render_dom/index.ts b/src/compiler/compile/render_dom/index.ts index 3f8f2c133046..e01b43dc095d 100644 --- a/src/compiler/compile/render_dom/index.ts +++ b/src/compiler/compile/render_dom/index.ts @@ -37,7 +37,13 @@ export default function dom( const add_css = component.get_unique_name('add_css'); - if (styles && component.compile_options.css !== false && !options.customElement) { + const should_add_css = ( + !options.customElement && + styles.length > 0 && + options.css !== false + ); + + if (should_add_css) { body.push(b` function ${add_css}() { var style = @element("style"); @@ -65,14 +71,6 @@ export default function dom( ); } - // TODO injecting CSS this way is kinda dirty. Maybe it should be an - // explicit opt-in, or something? - const should_add_css = ( - !options.customElement && - component.stylesheet.has_styles && - options.css !== false - ); - const uses_props = component.var_lookup.has('$$props'); const $$props = uses_props ? `$$new_props` : `$$props`; const props = component.vars.filter(variable => !variable.module && variable.export_name); diff --git a/src/compiler/compile/render_ssr/index.ts b/src/compiler/compile/render_ssr/index.ts index a22e7fee0d61..72cc26d5cf61 100644 --- a/src/compiler/compile/render_ssr/index.ts +++ b/src/compiler/compile/render_ssr/index.ts @@ -142,11 +142,11 @@ export default function ssr( ].filter(Boolean); return b` - ${css.code && b` + ${css.code ? b` const #css = { code: "${css.code}", map: ${css.map ? string_literal(css.map.toString()) : 'null'} - };`} + };` : null} ${component.extract_javascript(component.ast.module)} From b02028db325dbb8b1b9cbcb151838133acc8267f Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Sun, 22 Sep 2019 10:34:35 -0400 Subject: [PATCH 69/93] fix element_is --- src/compiler/compile/render_dom/wrappers/Element/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/compile/render_dom/wrappers/Element/index.ts b/src/compiler/compile/render_dom/wrappers/Element/index.ts index a8e7ad40a44a..d91f9caa2227 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/index.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/index.ts @@ -372,7 +372,7 @@ export default class ElementWrapper extends Wrapper { const is = this.attributes.find(attr => attr.node.name === 'is'); if (is) { - return x`@element_is("${name}", ${is.render_chunks().join(' + ')});`; + return x`@element_is("${name}", ${is.render_chunks().reduce((lhs, rhs) => x`${lhs} + ${rhs}`)});`; } return x`@element("${name}")`; From 09c0cefe6ae1bd4258486e960c7b749f6948e6cb Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Sun, 22 Sep 2019 11:25:01 -0400 Subject: [PATCH 70/93] fix a bunch more tests --- src/compiler/compile/Component.ts | 16 +++++++++++++--- src/compiler/compile/nodes/Element.ts | 1 + src/compiler/compile/nodes/EventHandler.ts | 2 +- src/compiler/compile/render_dom/index.ts | 2 +- .../attribute-with-whitespace/output.json | 2 +- .../parser/samples/binding-shorthand/output.json | 1 + test/parser/samples/binding/output.json | 1 + test/parser/samples/css/output.json | 1 + test/parser/samples/dynamic-import/output.json | 1 + test/parser/samples/refs/output.json | 1 + .../samples/script-comment-only/output.json | 1 + .../output.json | 1 + .../samples/script-comment-trailing/output.json | 1 + test/parser/samples/script/output.json | 1 + test/validator/index.js | 2 +- 15 files changed, 27 insertions(+), 7 deletions(-) diff --git a/src/compiler/compile/Component.ts b/src/compiler/compile/Component.ts index b477dcafbeb5..0facb30c1d09 100644 --- a/src/compiler/compile/Component.ts +++ b/src/compiler/compile/Component.ts @@ -51,6 +51,7 @@ export default class Component { ignore_stack: Array> = []; ast: Ast; + original_ast: Ast; source: string; name: Identifier; compile_options: CompileOptions; @@ -124,6 +125,15 @@ export default class Component { this.source = source; this.compile_options = compile_options; + // the instance JS gets mutated, so we park + // a copy here for later. TODO this feels gross + this.original_ast = { + html: ast.html, + css: ast.css, + instance: ast.instance && JSON.parse(JSON.stringify(ast.instance)), + module: ast.module + }; + this.file = compile_options.filename && (typeof process !== 'undefined' @@ -364,7 +374,7 @@ export default class Component { return { js, css, - ast: this.ast, + ast: this.original_ast, warnings: this.warnings, vars: this.vars .filter(v => !v.global && !v.internal) @@ -710,9 +720,9 @@ export default class Component { const script = this.ast.instance; if (!script) return; + this.warn_on_undefined_store_value_references(); this.hoist_instance_declarations(); this.extract_reactive_declarations(); - this.extract_reactive_store_references(); } // TODO merge this with other walks that are independent @@ -751,7 +761,7 @@ export default class Component { }); } - extract_reactive_store_references() { + warn_on_undefined_store_value_references() { // TODO this pattern happens a lot... can we abstract it // (or better still, do fewer AST walks)? const component = this; diff --git a/src/compiler/compile/nodes/Element.ts b/src/compiler/compile/nodes/Element.ts index 2981741fa06c..7e6aa2804b47 100644 --- a/src/compiler/compile/nodes/Element.ts +++ b/src/compiler/compile/nodes/Element.ts @@ -676,6 +676,7 @@ export default class Element extends Node { if (modifier === 'passive') { if (passive_events.has(handler.name)) { + console.log('here', handler.name, handler.can_make_passive); if (handler.can_make_passive) { component.warn(handler, { code: 'redundant-event-modifier', diff --git a/src/compiler/compile/nodes/EventHandler.ts b/src/compiler/compile/nodes/EventHandler.ts index 11c030a55e08..7faf5d15dd9a 100644 --- a/src/compiler/compile/nodes/EventHandler.ts +++ b/src/compiler/compile/nodes/EventHandler.ts @@ -39,7 +39,7 @@ export default class EventHandler extends Node { node = declarator && declarator.init; } - if (node && (node.type === 'FunctionExpression' || node.type === 'ArrowFunctionExpression') && node.params.length === 0) { + if (node && (node.type === 'FunctionExpression' || node.type === 'FunctionDeclaration' || node.type === 'ArrowFunctionExpression') && node.params.length === 0) { this.can_make_passive = true; } } diff --git a/src/compiler/compile/render_dom/index.ts b/src/compiler/compile/render_dom/index.ts index e01b43dc095d..062b85090afa 100644 --- a/src/compiler/compile/render_dom/index.ts +++ b/src/compiler/compile/render_dom/index.ts @@ -39,7 +39,7 @@ export default function dom( const should_add_css = ( !options.customElement && - styles.length > 0 && + !!styles && options.css !== false ); diff --git a/test/parser/samples/attribute-with-whitespace/output.json b/test/parser/samples/attribute-with-whitespace/output.json index eab6054f2a64..11d5aa5e069a 100644 --- a/test/parser/samples/attribute-with-whitespace/output.json +++ b/test/parser/samples/attribute-with-whitespace/output.json @@ -36,4 +36,4 @@ } ] } -} +} \ No newline at end of file diff --git a/test/parser/samples/binding-shorthand/output.json b/test/parser/samples/binding-shorthand/output.json index 7fe7acb5b375..0f10aeb40d93 100644 --- a/test/parser/samples/binding-shorthand/output.json +++ b/test/parser/samples/binding-shorthand/output.json @@ -36,6 +36,7 @@ ] }, "instance": { + "type": "Script", "start": 0, "end": 28, "context": "default", diff --git a/test/parser/samples/binding/output.json b/test/parser/samples/binding/output.json index 72ad60202c98..e5ebc3fbc736 100644 --- a/test/parser/samples/binding/output.json +++ b/test/parser/samples/binding/output.json @@ -36,6 +36,7 @@ ] }, "instance": { + "type": "Script", "start": 0, "end": 29, "context": "default", diff --git a/test/parser/samples/css/output.json b/test/parser/samples/css/output.json index 12d74ae7f87a..676b11f6a96d 100644 --- a/test/parser/samples/css/output.json +++ b/test/parser/samples/css/output.json @@ -30,6 +30,7 @@ ] }, "css": { + "type": "Style", "start": 16, "end": 56, "attributes": [], diff --git a/test/parser/samples/dynamic-import/output.json b/test/parser/samples/dynamic-import/output.json index f66cdaaa0b24..ce6c7880bcf8 100644 --- a/test/parser/samples/dynamic-import/output.json +++ b/test/parser/samples/dynamic-import/output.json @@ -6,6 +6,7 @@ "children": [] }, "instance": { + "type": "Script", "start": 0, "end": 146, "context": "default", diff --git a/test/parser/samples/refs/output.json b/test/parser/samples/refs/output.json index e09383f9b682..707da8977439 100644 --- a/test/parser/samples/refs/output.json +++ b/test/parser/samples/refs/output.json @@ -36,6 +36,7 @@ ] }, "instance": { + "type": "Script", "start": 0, "end": 28, "context": "default", diff --git a/test/parser/samples/script-comment-only/output.json b/test/parser/samples/script-comment-only/output.json index ba2843431826..bc541abcc3da 100644 --- a/test/parser/samples/script-comment-only/output.json +++ b/test/parser/samples/script-comment-only/output.json @@ -22,6 +22,7 @@ ] }, "instance": { + "type": "Script", "start": 0, "end": 43, "context": "default", diff --git a/test/parser/samples/script-comment-trailing-multiline/output.json b/test/parser/samples/script-comment-trailing-multiline/output.json index 7d01599efa21..ec4f8fe69389 100644 --- a/test/parser/samples/script-comment-trailing-multiline/output.json +++ b/test/parser/samples/script-comment-trailing-multiline/output.json @@ -48,6 +48,7 @@ ] }, "instance": { + "type": "Script", "start": 0, "end": 77, "context": "default", diff --git a/test/parser/samples/script-comment-trailing/output.json b/test/parser/samples/script-comment-trailing/output.json index bc8f3e4e6740..166b1a134be4 100644 --- a/test/parser/samples/script-comment-trailing/output.json +++ b/test/parser/samples/script-comment-trailing/output.json @@ -48,6 +48,7 @@ ] }, "instance": { + "type": "Script", "start": 0, "end": 66, "context": "default", diff --git a/test/parser/samples/script/output.json b/test/parser/samples/script/output.json index 75aa0a7d2c57..4dee65735463 100644 --- a/test/parser/samples/script/output.json +++ b/test/parser/samples/script/output.json @@ -48,6 +48,7 @@ ] }, "instance": { + "type": "Script", "start": 0, "end": 39, "context": "default", diff --git a/test/validator/index.js b/test/validator/index.js index 1e54cc20dbac..9be8d6b6b826 100644 --- a/test/validator/index.js +++ b/test/validator/index.js @@ -2,7 +2,7 @@ import * as fs from "fs"; import * as assert from "assert"; import { svelte, loadConfig, tryToLoadJson } from "../helpers.js"; -describe("validate", () => { +describe.only("validate", () => { fs.readdirSync("test/validator/samples").forEach(dir => { if (dir[0] === ".") return; From ff3501fe8fa2743a603513ec89cbcdaa4776e47e Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Sun, 22 Sep 2019 11:57:04 -0400 Subject: [PATCH 71/93] almost all tests passing... --- src/compiler/compile/render_ssr/Renderer.ts | 7 +++++-- .../compile/render_ssr/handlers/InlineComponent.ts | 2 +- src/compiler/compile/render_ssr/index.ts | 6 ++++-- src/compiler/parse/state/tag.ts | 2 -- test/js/index.js | 2 +- test/server-side-rendering/index.js | 7 ++++--- test/validator/index.js | 2 +- 7 files changed, 16 insertions(+), 12 deletions(-) diff --git a/src/compiler/compile/render_ssr/Renderer.ts b/src/compiler/compile/render_ssr/Renderer.ts index 1f8991995574..c8b2d14ff6fa 100644 --- a/src/compiler/compile/render_ssr/Renderer.ts +++ b/src/compiler/compile/render_ssr/Renderer.ts @@ -13,7 +13,7 @@ import Text from './handlers/Text'; import Title from './handlers/Title'; import { AppendTarget, CompileOptions } from '../../interfaces'; import { INode } from '../nodes/interfaces'; -import { Expression, TemplateLiteral } from 'estree'; +import { Expression, TemplateLiteral, Identifier } from 'estree'; import { escape_template } from '../utils/stringify'; type Handler = (node: any, renderer: Renderer, options: CompileOptions) => void; @@ -46,13 +46,16 @@ export interface RenderOptions extends CompileOptions{ export default class Renderer { has_bindings = false; + name: Identifier; + stack: { current: { value: string }, literal: TemplateLiteral }[] = []; current: { value: string }; // TODO can it just be `current: string`? literal: TemplateLiteral; targets: AppendTarget[] = []; - constructor() { + constructor({ name }) { + this.name = name; this.push(); } diff --git a/src/compiler/compile/render_ssr/handlers/InlineComponent.ts b/src/compiler/compile/render_ssr/handlers/InlineComponent.ts index 6484edcb7619..9ef293de7706 100644 --- a/src/compiler/compile/render_ssr/handlers/InlineComponent.ts +++ b/src/compiler/compile/render_ssr/handlers/InlineComponent.ts @@ -60,7 +60,7 @@ export default function(node: InlineComponent, renderer: Renderer, options: Rend const expression = ( node.name === 'svelte:self' - ? options.name + ? renderer.name : node.name === 'svelte:component' ? x`(${node.expression.node}) || @missing_component` : node.name diff --git a/src/compiler/compile/render_ssr/index.ts b/src/compiler/compile/render_ssr/index.ts index 72cc26d5cf61..7a7796ed29e2 100644 --- a/src/compiler/compile/render_ssr/index.ts +++ b/src/compiler/compile/render_ssr/index.ts @@ -1,7 +1,7 @@ import { b } from 'code-red'; import Component from '../Component'; import { CompileOptions } from '../../interfaces'; -import { stringify, string_literal } from '../utils/stringify'; +import { string_literal } from '../utils/stringify'; import Renderer from './Renderer'; import { INode as TemplateNode } from '../nodes/interfaces'; // TODO import Text from '../nodes/Text'; @@ -11,7 +11,9 @@ export default function ssr( component: Component, options: CompileOptions ) { - const renderer = new Renderer(); + const renderer = new Renderer({ + name: component.name + }); const { name } = component; diff --git a/src/compiler/parse/state/tag.ts b/src/compiler/parse/state/tag.ts index 6b187d141b7b..dca23012035d 100644 --- a/src/compiler/parse/state/tag.ts +++ b/src/compiler/parse/state/tag.ts @@ -37,9 +37,7 @@ const specials = new Map([ ], ]); -// eslint-disable-next-line no-useless-escape const SELF = /^svelte:self(?=[\s\/>])/; -// eslint-disable-next-line no-useless-escape const COMPONENT = /^svelte:component(?=[\s\/>])/; function parent_is_head(stack) { diff --git a/test/js/index.js b/test/js/index.js index 14d73d6c6572..1026ea2fdc17 100644 --- a/test/js/index.js +++ b/test/js/index.js @@ -3,7 +3,7 @@ import * as fs from "fs"; import * as path from "path"; import { loadConfig, svelte } from "../helpers.js"; -describe("js", () => { +describe.skip("js", () => { fs.readdirSync("test/js/samples").forEach(dir => { if (dir[0] === ".") return; diff --git a/test/server-side-rendering/index.js b/test/server-side-rendering/index.js index eb2303a794b2..10974861246b 100644 --- a/test/server-side-rendering/index.js +++ b/test/server-side-rendering/index.js @@ -72,9 +72,9 @@ describe("ssr", () => { ); } - if (show) showOutput(dir, { generate: 'ssr' }); + if (show) showOutput(dir, { generate: 'ssr', format: 'cjs' }); } catch (err) { - showOutput(dir, { generate: 'ssr' }); + showOutput(dir, { generate: 'ssr', format: 'cjs' }); err.stack += `\n\ncmd-click: ${path.relative(process.cwd(), dir)}/main.svelte`; throw err; } @@ -105,7 +105,8 @@ describe("ssr", () => { delete global.window; const compileOptions = Object.assign({ sveltePath }, config.compileOptions, { - generate: 'ssr' + generate: 'ssr', + format: 'cjs' }); require("../../register")(compileOptions); diff --git a/test/validator/index.js b/test/validator/index.js index 9be8d6b6b826..1e54cc20dbac 100644 --- a/test/validator/index.js +++ b/test/validator/index.js @@ -2,7 +2,7 @@ import * as fs from "fs"; import * as assert from "assert"; import { svelte, loadConfig, tryToLoadJson } from "../helpers.js"; -describe.only("validate", () => { +describe("validate", () => { fs.readdirSync("test/validator/samples").forEach(dir => { if (dir[0] === ".") return; From f3064f13f254300b97a20cec5db109bf5334a287 Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Sun, 22 Sep 2019 13:15:53 -0400 Subject: [PATCH 72/93] most sourcemap tests working --- package-lock.json | 56 +++++++++++++++++++-------- package.json | 4 +- src/compiler/compile/Component.ts | 32 ++++++++++++++- src/compiler/parse/acorn.ts | 6 ++- test/sourcemaps/index.js | 8 ++-- test/sourcemaps/samples/basic/test.js | 2 +- 6 files changed, 81 insertions(+), 27 deletions(-) diff --git a/package-lock.json b/package-lock.json index e1b1d459928d..d5abb0d992ca 100644 --- a/package-lock.json +++ b/package-lock.json @@ -331,7 +331,7 @@ "dev": true }, "astring": { - "version": "github:Rich-Harris/astring#00fa527b66cc1b57efb2a4b9052dd4e190ae3590", + "version": "github:Rich-Harris/astring#9f675d470d1c758de5ec42724aa5dd2e1dabf919", "from": "github:Rich-Harris/astring#generic-handler", "dev": true }, @@ -507,24 +507,16 @@ "dev": true }, "code-red": { - "version": "0.0.12", - "resolved": "https://registry.npmjs.org/code-red/-/code-red-0.0.12.tgz", - "integrity": "sha512-5R8zbm2z5CmHp2iSmV/kSDhXcdISJwBr898jIPeASEdsGrjFpT4Jhky0J659jLsZL9gzDBGn32rvR0YWDXzAvw==", + "version": "0.0.13", + "resolved": "https://registry.npmjs.org/code-red/-/code-red-0.0.13.tgz", + "integrity": "sha512-cBYTCCcEuxdkIvK7LnDlZslan3NoYCV4YAH0xVkePuCD7/TOKg/vWXug7TNjKePLJEnc9isgeK76RzsBy1pShA==", "dev": true, "requires": { "acorn": "^7.0.0", - "astring": "github:Rich-Harris/astring#00fa527b66cc1b57efb2a4b9052dd4e190ae3590", + "astring": "github:Rich-Harris/astring#9f675d470d1c758de5ec42724aa5dd2e1dabf919", "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": { @@ -830,6 +822,13 @@ "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=", "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "optional": true } } }, @@ -1522,6 +1521,14 @@ "optimist": "^0.6.1", "source-map": "^0.6.1", "uglify-js": "^3.1.4" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } } }, "har-schema": { @@ -3271,9 +3278,9 @@ } }, "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", "dev": true }, "source-map-support": { @@ -3284,6 +3291,14 @@ "requires": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } } }, "sourcemap-codec": { @@ -3591,6 +3606,15 @@ "requires": { "commander": "~2.20.0", "source-map": "~0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "optional": true + } } }, "uri-js": { diff --git a/package.json b/package.json index a45d1863e39f..a357954da6c6 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,7 @@ "acorn": "^7.0.0", "agadoo": "^1.0.1", "c8": "^5.0.1", - "code-red": "0.0.12", + "code-red": "0.0.13", "codecov": "^3.5.0", "css-tree": "1.0.0-alpha22", "eslint": "^6.3.0", @@ -85,7 +85,7 @@ "rollup-plugin-sucrase": "^2.1.0", "rollup-plugin-typescript": "^1.0.1", "rollup-plugin-virtual": "^1.0.1", - "source-map": "^0.6.1", + "source-map": "^0.7.3", "source-map-support": "^0.5.13", "tiny-glob": "^0.2.6", "tslib": "^1.10.0", diff --git a/src/compiler/compile/Component.ts b/src/compiler/compile/Component.ts index 0facb30c1d09..77e01f8e795a 100644 --- a/src/compiler/compile/Component.ts +++ b/src/compiler/compile/Component.ts @@ -1,4 +1,3 @@ -// @ts-ignore import { walk, childKeys } from 'estree-walker'; import { getLocator } from 'locate-character'; import Stats from '../Stats'; @@ -368,7 +367,17 @@ export default class Component { ? { code: null, map: null } : this.stylesheet.render(compile_options.cssOutputFilename, true); - js = print(program); + js = print(program, { + sourceMapSource: compile_options.filename + }); + + js.map.sources = [ + compile_options.filename ? get_relative_path(compile_options.outputFilename || '', compile_options.filename) : null + ]; + + js.map.sourcesContent = [ + this.source + ]; } return { @@ -1404,3 +1413,22 @@ function process_component_options(component: Component, nodes) { return component_options; } + +function get_relative_path(from: string, to: string) { + const from_parts = from.split(/[/\\]/); + const to_parts = to.split(/[/\\]/); + + from_parts.pop(); // get dirname + + while (from_parts[0] === to_parts[0]) { + from_parts.shift(); + to_parts.shift(); + } + + if (from_parts.length) { + let i = from_parts.length; + while (i--) from_parts[i] = '..'; + } + + return from_parts.concat(to_parts).join('/'); +} \ No newline at end of file diff --git a/src/compiler/parse/acorn.ts b/src/compiler/parse/acorn.ts index 308a99a42273..a7d270395603 100644 --- a/src/compiler/parse/acorn.ts +++ b/src/compiler/parse/acorn.ts @@ -5,10 +5,12 @@ const Parser = acorn.Parser; export const parse = (source: string) => Parser.parse(source, { sourceType: 'module', // @ts-ignore TODO pending release of fixed types - ecmaVersion: 11 + ecmaVersion: 11, + locations: true }); export const parse_expression_at = (source: string, index: number) => Parser.parseExpressionAt(source, index, { // @ts-ignore TODO pending release of fixed types - ecmaVersion: 11 + ecmaVersion: 11, + locations: true }); \ No newline at end of file diff --git a/test/sourcemaps/index.js b/test/sourcemaps/index.js index ee169ebe1b6c..fb5814e8d814 100644 --- a/test/sourcemaps/index.js +++ b/test/sourcemaps/index.js @@ -5,7 +5,7 @@ import { svelte } from "../helpers.js"; import { SourceMapConsumer } from "source-map"; import { getLocator } from "locate-character"; -describe("sourcemaps", () => { +describe.only("sourcemaps", () => { fs.readdirSync("test/sourcemaps/samples").forEach(dir => { if (dir[0] === ".") return; @@ -17,7 +17,7 @@ describe("sourcemaps", () => { throw new Error("Forgot to remove `solo: true` from test"); } - (solo ? it.only : skip ? it.skip : it)(dir, () => { + (solo ? it.only : skip ? it.skip : it)(dir, async () => { const filename = path.resolve( `test/sourcemaps/samples/${dir}/input.svelte` ); @@ -61,10 +61,10 @@ describe("sourcemaps", () => { const locateInSource = getLocator(input); - const smc = new SourceMapConsumer(js.map); + const smc = await new SourceMapConsumer(js.map); const locateInGenerated = getLocator(_code); - const smcCss = css.map && new SourceMapConsumer(css.map); + const smcCss = css.map && await new SourceMapConsumer(css.map); const locateInGeneratedCss = getLocator(css.code || ''); test({ assert, code: _code, map: js.map, smc, smcCss, locateInSource, locateInGenerated, locateInGeneratedCss }); diff --git a/test/sourcemaps/samples/basic/test.js b/test/sourcemaps/samples/basic/test.js index f13ff5d0e137..f2ce4198fdb3 100644 --- a/test/sourcemaps/samples/basic/test.js +++ b/test/sourcemaps/samples/basic/test.js @@ -4,7 +4,7 @@ export function test({ assert, smc, locateInSource, locateInGenerated }) { let start; let actual; - start = locateInGenerated( 'foo.bar.baz' ); + start = locateInGenerated('foo.bar.baz'); actual = smc.originalPositionFor({ line: start.line + 1, From 37bac603133eb0c0e17c6d06b5bbbfbf387f4f7b Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Sun, 22 Sep 2019 14:06:25 -0400 Subject: [PATCH 73/93] fix each block sourcemap hack --- src/compiler/compile/render_dom/wrappers/EachBlock.ts | 8 ++++---- test/sourcemaps/samples/each-block/test.js | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/compiler/compile/render_dom/wrappers/EachBlock.ts b/src/compiler/compile/render_dom/wrappers/EachBlock.ts index c5f6b0766d88..33968c762a63 100644 --- a/src/compiler/compile/render_dom/wrappers/EachBlock.ts +++ b/src/compiler/compile/render_dom/wrappers/EachBlock.ts @@ -107,14 +107,14 @@ export default class EachBlockWrapper extends Wrapper { // is easy to find let c = this.node.start + 2; while (renderer.component.source[c] !== 'e') c += 1; + const start = renderer.component.locate(c); + start.line += 1; + const end = { line: start.line, column: start.column + 4 }; const length = { type: 'Identifier', name: 'length', - // TODO this format may be incorrect - start: c, - end: c + 4 + loc: { start, end } }; - // renderer.component.code.overwrite(c, c + 4, 'length'); const each_block_value = renderer.component.get_unique_name(`${this.var.name}_value`); const iterations = block.get_unique_name(`${this.var.name}_blocks`); diff --git a/test/sourcemaps/samples/each-block/test.js b/test/sourcemaps/samples/each-block/test.js index 6e9d2d70b00d..35479986a546 100644 --- a/test/sourcemaps/samples/each-block/test.js +++ b/test/sourcemaps/samples/each-block/test.js @@ -1,15 +1,15 @@ -export function test({ assert, code, smc, locateInSource, locateInGenerated }) { +export function test({ assert, code, smc, map, locateInSource, locateInGenerated }) { const startIndex = code.indexOf('create_main_fragment'); const expected = locateInSource('each'); - const start = locateInGenerated('length', startIndex ); + const start = locateInGenerated('length', startIndex); const actual = smc.originalPositionFor({ line: start.line + 1, column: start.column }); - assert.deepEqual( actual, { + assert.deepEqual(actual, { source: 'input.svelte', name: null, line: expected.line + 1, From 12d5126e32c10128c131c4c92c83cf28b123f74d Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Sun, 22 Sep 2019 14:10:19 -0400 Subject: [PATCH 74/93] update tests. one still failing --- .../samples/action-with-call/output.json | 30 ++ .../samples/action-with-literal/output.json | 10 + test/parser/samples/animation/output.json | 20 ++ .../samples/await-then-catch/output.json | 50 ++++ .../samples/binding-shorthand/output.json | 40 +++ test/parser/samples/binding/output.json | 40 +++ .../samples/component-dynamic/output.json | 40 +++ .../parser/samples/dynamic-import/output.json | 280 ++++++++++++++++++ .../each-block-destructured/output.json | 10 + .../samples/each-block-else/output.json | 10 + .../samples/each-block-indexed/output.json | 10 + .../samples/each-block-keyed/output.json | 40 +++ test/parser/samples/each-block/output.json | 10 + test/parser/samples/event-handler/output.json | 50 ++++ .../samples/if-block-elseif/output.json | 60 ++++ test/parser/samples/raw-mustaches/output.json | 20 ++ test/parser/samples/refs/output.json | 40 +++ .../samples/script-comment-only/output.json | 10 + .../output.json | 50 ++++ .../script-comment-trailing/output.json | 50 ++++ test/parser/samples/script/output.json | 50 ++++ .../parser/samples/self-reference/output.json | 60 ++++ .../samples/transition-intro/output.json | 40 +++ .../samples/unusual-identifier/output.json | 20 ++ test/sourcemaps/index.js | 2 +- 25 files changed, 1041 insertions(+), 1 deletion(-) diff --git a/test/parser/samples/action-with-call/output.json b/test/parser/samples/action-with-call/output.json index e910f0b49f25..ccb4011c678b 100644 --- a/test/parser/samples/action-with-call/output.json +++ b/test/parser/samples/action-with-call/output.json @@ -20,10 +20,30 @@ "type": "CallExpression", "start": 21, "end": 37, + "loc": { + "start": { + "line": 1, + "column": 21 + }, + "end": { + "line": 1, + "column": 37 + } + }, "callee": { "type": "Identifier", "start": 21, "end": 22, + "loc": { + "start": { + "line": 1, + "column": 21 + }, + "end": { + "line": 1, + "column": 22 + } + }, "name": "t" }, "arguments": [ @@ -31,6 +51,16 @@ "type": "Literal", "start": 23, "end": 36, + "loc": { + "start": { + "line": 1, + "column": 23 + }, + "end": { + "line": 1, + "column": 36 + } + }, "value": "tooltip msg", "raw": "'tooltip msg'" } diff --git a/test/parser/samples/action-with-literal/output.json b/test/parser/samples/action-with-literal/output.json index 01a6b675498f..bb0b13ee4270 100644 --- a/test/parser/samples/action-with-literal/output.json +++ b/test/parser/samples/action-with-literal/output.json @@ -20,6 +20,16 @@ "type": "Literal", "start": 21, "end": 34, + "loc": { + "start": { + "line": 1, + "column": 21 + }, + "end": { + "line": 1, + "column": 34 + } + }, "value": "tooltip msg", "raw": "'tooltip msg'" } diff --git a/test/parser/samples/animation/output.json b/test/parser/samples/animation/output.json index f4d183eb5cd7..1958ba2817bd 100644 --- a/test/parser/samples/animation/output.json +++ b/test/parser/samples/animation/output.json @@ -12,6 +12,16 @@ "type": "Identifier", "start": 7, "end": 13, + "loc": { + "start": { + "line": 1, + "column": 7 + }, + "end": { + "line": 1, + "column": 13 + } + }, "name": "things" }, "children": [ @@ -51,6 +61,16 @@ "type": "Identifier", "start": 24, "end": 29, + "loc": { + "start": { + "line": 1, + "column": 24 + }, + "end": { + "line": 1, + "column": 29 + } + }, "name": "thing" } } diff --git a/test/parser/samples/await-then-catch/output.json b/test/parser/samples/await-then-catch/output.json index ac598a403a06..d9defb69329d 100644 --- a/test/parser/samples/await-then-catch/output.json +++ b/test/parser/samples/await-then-catch/output.json @@ -12,6 +12,16 @@ "type": "Identifier", "start": 8, "end": 18, + "loc": { + "start": { + "line": 1, + "column": 8 + }, + "end": { + "line": 1, + "column": 18 + } + }, "name": "thePromise" }, "value": "theValue", @@ -88,6 +98,16 @@ "type": "Identifier", "start": 74, "end": 82, + "loc": { + "start": { + "line": 4, + "column": 18 + }, + "end": { + "line": 4, + "column": 26 + } + }, "name": "theValue" } } @@ -137,16 +157,46 @@ "type": "MemberExpression", "start": 118, "end": 134, + "loc": { + "start": { + "line": 6, + "column": 12 + }, + "end": { + "line": 6, + "column": 28 + } + }, "object": { "type": "Identifier", "start": 118, "end": 126, + "loc": { + "start": { + "line": 6, + "column": 12 + }, + "end": { + "line": 6, + "column": 20 + } + }, "name": "theError" }, "property": { "type": "Identifier", "start": 127, "end": 134, + "loc": { + "start": { + "line": 6, + "column": 21 + }, + "end": { + "line": 6, + "column": 28 + } + }, "name": "message" }, "computed": false diff --git a/test/parser/samples/binding-shorthand/output.json b/test/parser/samples/binding-shorthand/output.json index 0f10aeb40d93..17012db31ac3 100644 --- a/test/parser/samples/binding-shorthand/output.json +++ b/test/parser/samples/binding-shorthand/output.json @@ -44,20 +44,60 @@ "type": "Program", "start": 8, "end": 19, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 3, + "column": 0 + } + }, "body": [ { "type": "VariableDeclaration", "start": 10, "end": 18, + "loc": { + "start": { + "line": 2, + "column": 1 + }, + "end": { + "line": 2, + "column": 9 + } + }, "declarations": [ { "type": "VariableDeclarator", "start": 14, "end": 17, + "loc": { + "start": { + "line": 2, + "column": 5 + }, + "end": { + "line": 2, + "column": 8 + } + }, "id": { "type": "Identifier", "start": 14, "end": 17, + "loc": { + "start": { + "line": 2, + "column": 5 + }, + "end": { + "line": 2, + "column": 8 + } + }, "name": "foo" }, "init": null diff --git a/test/parser/samples/binding/output.json b/test/parser/samples/binding/output.json index e5ebc3fbc736..558215f41aa5 100644 --- a/test/parser/samples/binding/output.json +++ b/test/parser/samples/binding/output.json @@ -44,20 +44,60 @@ "type": "Program", "start": 8, "end": 20, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 3, + "column": 0 + } + }, "body": [ { "type": "VariableDeclaration", "start": 10, "end": 19, + "loc": { + "start": { + "line": 2, + "column": 1 + }, + "end": { + "line": 2, + "column": 10 + } + }, "declarations": [ { "type": "VariableDeclarator", "start": 14, "end": 18, + "loc": { + "start": { + "line": 2, + "column": 5 + }, + "end": { + "line": 2, + "column": 9 + } + }, "id": { "type": "Identifier", "start": 14, "end": 18, + "loc": { + "start": { + "line": 2, + "column": 5 + }, + "end": { + "line": 2, + "column": 9 + } + }, "name": "name" }, "init": null diff --git a/test/parser/samples/component-dynamic/output.json b/test/parser/samples/component-dynamic/output.json index 77837d1ca9d4..32cde85f1a27 100644 --- a/test/parser/samples/component-dynamic/output.json +++ b/test/parser/samples/component-dynamic/output.json @@ -15,22 +15,62 @@ "type": "ConditionalExpression", "start": 25, "end": 40, + "loc": { + "start": { + "line": 1, + "column": 25 + }, + "end": { + "line": 1, + "column": 40 + } + }, "test": { "type": "Identifier", "start": 25, "end": 28, + "loc": { + "start": { + "line": 1, + "column": 25 + }, + "end": { + "line": 1, + "column": 28 + } + }, "name": "foo" }, "consequent": { "type": "Identifier", "start": 31, "end": 34, + "loc": { + "start": { + "line": 1, + "column": 31 + }, + "end": { + "line": 1, + "column": 34 + } + }, "name": "Foo" }, "alternate": { "type": "Identifier", "start": 37, "end": 40, + "loc": { + "start": { + "line": 1, + "column": 37 + }, + "end": { + "line": 1, + "column": 40 + } + }, "name": "Bar" } } diff --git a/test/parser/samples/dynamic-import/output.json b/test/parser/samples/dynamic-import/output.json index ce6c7880bcf8..1e41252afab1 100644 --- a/test/parser/samples/dynamic-import/output.json +++ b/test/parser/samples/dynamic-import/output.json @@ -14,26 +14,76 @@ "type": "Program", "start": 8, "end": 137, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 9, + "column": 0 + } + }, "body": [ { "type": "ImportDeclaration", "start": 10, "end": 43, + "loc": { + "start": { + "line": 2, + "column": 1 + }, + "end": { + "line": 2, + "column": 34 + } + }, "specifiers": [ { "type": "ImportSpecifier", "start": 19, "end": 26, + "loc": { + "start": { + "line": 2, + "column": 10 + }, + "end": { + "line": 2, + "column": 17 + } + }, "imported": { "type": "Identifier", "start": 19, "end": 26, + "loc": { + "start": { + "line": 2, + "column": 10 + }, + "end": { + "line": 2, + "column": 17 + } + }, "name": "onMount" }, "local": { "type": "Identifier", "start": 19, "end": 26, + "loc": { + "start": { + "line": 2, + "column": 10 + }, + "end": { + "line": 2, + "column": 17 + } + }, "name": "onMount" } } @@ -42,6 +92,16 @@ "type": "Literal", "start": 34, "end": 42, + "loc": { + "start": { + "line": 2, + "column": 25 + }, + "end": { + "line": 2, + "column": 33 + } + }, "value": "svelte", "raw": "'svelte'" } @@ -50,14 +110,44 @@ "type": "ExpressionStatement", "start": 46, "end": 136, + "loc": { + "start": { + "line": 4, + "column": 1 + }, + "end": { + "line": 8, + "column": 4 + } + }, "expression": { "type": "CallExpression", "start": 46, "end": 135, + "loc": { + "start": { + "line": 4, + "column": 1 + }, + "end": { + "line": 8, + "column": 3 + } + }, "callee": { "type": "Identifier", "start": 46, "end": 53, + "loc": { + "start": { + "line": 4, + "column": 1 + }, + "end": { + "line": 4, + "column": 8 + } + }, "name": "onMount" }, "arguments": [ @@ -65,6 +155,16 @@ "type": "ArrowFunctionExpression", "start": 54, "end": 134, + "loc": { + "start": { + "line": 4, + "column": 9 + }, + "end": { + "line": 8, + "column": 2 + } + }, "id": null, "expression": false, "generator": false, @@ -74,27 +174,87 @@ "type": "BlockStatement", "start": 60, "end": 134, + "loc": { + "start": { + "line": 4, + "column": 15 + }, + "end": { + "line": 8, + "column": 2 + } + }, "body": [ { "type": "ExpressionStatement", "start": 64, "end": 131, + "loc": { + "start": { + "line": 5, + "column": 2 + }, + "end": { + "line": 7, + "column": 5 + } + }, "expression": { "type": "CallExpression", "start": 64, "end": 130, + "loc": { + "start": { + "line": 5, + "column": 2 + }, + "end": { + "line": 7, + "column": 4 + } + }, "callee": { "type": "MemberExpression", "start": 64, "end": 87, + "loc": { + "start": { + "line": 5, + "column": 2 + }, + "end": { + "line": 5, + "column": 25 + } + }, "object": { "type": "ImportExpression", "start": 64, "end": 82, + "loc": { + "start": { + "line": 5, + "column": 2 + }, + "end": { + "line": 5, + "column": 20 + } + }, "source": { "type": "Literal", "start": 71, "end": 81, + "loc": { + "start": { + "line": 5, + "column": 9 + }, + "end": { + "line": 5, + "column": 19 + } + }, "value": "./foo.js", "raw": "'./foo.js'" } @@ -103,6 +263,16 @@ "type": "Identifier", "start": 83, "end": 87, + "loc": { + "start": { + "line": 5, + "column": 21 + }, + "end": { + "line": 5, + "column": 25 + } + }, "name": "then" }, "computed": false @@ -112,6 +282,16 @@ "type": "ArrowFunctionExpression", "start": 88, "end": 129, + "loc": { + "start": { + "line": 5, + "column": 26 + }, + "end": { + "line": 7, + "column": 3 + } + }, "id": null, "expression": false, "generator": false, @@ -121,6 +301,16 @@ "type": "Identifier", "start": 88, "end": 91, + "loc": { + "start": { + "line": 5, + "column": 26 + }, + "end": { + "line": 5, + "column": 29 + } + }, "name": "foo" } ], @@ -128,29 +318,89 @@ "type": "BlockStatement", "start": 95, "end": 129, + "loc": { + "start": { + "line": 5, + "column": 33 + }, + "end": { + "line": 7, + "column": 3 + } + }, "body": [ { "type": "ExpressionStatement", "start": 100, "end": 125, + "loc": { + "start": { + "line": 6, + "column": 3 + }, + "end": { + "line": 6, + "column": 28 + } + }, "expression": { "type": "CallExpression", "start": 100, "end": 124, + "loc": { + "start": { + "line": 6, + "column": 3 + }, + "end": { + "line": 6, + "column": 27 + } + }, "callee": { "type": "MemberExpression", "start": 100, "end": 111, + "loc": { + "start": { + "line": 6, + "column": 3 + }, + "end": { + "line": 6, + "column": 14 + } + }, "object": { "type": "Identifier", "start": 100, "end": 107, + "loc": { + "start": { + "line": 6, + "column": 3 + }, + "end": { + "line": 6, + "column": 10 + } + }, "name": "console" }, "property": { "type": "Identifier", "start": 108, "end": 111, + "loc": { + "start": { + "line": 6, + "column": 11 + }, + "end": { + "line": 6, + "column": 14 + } + }, "name": "log" }, "computed": false @@ -160,16 +410,46 @@ "type": "MemberExpression", "start": 112, "end": 123, + "loc": { + "start": { + "line": 6, + "column": 15 + }, + "end": { + "line": 6, + "column": 26 + } + }, "object": { "type": "Identifier", "start": 112, "end": 115, + "loc": { + "start": { + "line": 6, + "column": 15 + }, + "end": { + "line": 6, + "column": 18 + } + }, "name": "foo" }, "property": { "type": "Identifier", "start": 116, "end": 123, + "loc": { + "start": { + "line": 6, + "column": 19 + }, + "end": { + "line": 6, + "column": 26 + } + }, "name": "default" }, "computed": false diff --git a/test/parser/samples/each-block-destructured/output.json b/test/parser/samples/each-block-destructured/output.json index 6368b445d61e..bafde1324db4 100644 --- a/test/parser/samples/each-block-destructured/output.json +++ b/test/parser/samples/each-block-destructured/output.json @@ -12,6 +12,16 @@ "type": "Identifier", "start": 7, "end": 14, + "loc": { + "start": { + "line": 1, + "column": 7 + }, + "end": { + "line": 1, + "column": 14 + } + }, "name": "animals" }, "children": [ diff --git a/test/parser/samples/each-block-else/output.json b/test/parser/samples/each-block-else/output.json index 1e8ac455e6fd..19b5af19b4fa 100644 --- a/test/parser/samples/each-block-else/output.json +++ b/test/parser/samples/each-block-else/output.json @@ -12,6 +12,16 @@ "type": "Identifier", "start": 7, "end": 14, + "loc": { + "start": { + "line": 1, + "column": 7 + }, + "end": { + "line": 1, + "column": 14 + } + }, "name": "animals" }, "children": [ diff --git a/test/parser/samples/each-block-indexed/output.json b/test/parser/samples/each-block-indexed/output.json index 77417ba67aed..68a12ea31c16 100644 --- a/test/parser/samples/each-block-indexed/output.json +++ b/test/parser/samples/each-block-indexed/output.json @@ -12,6 +12,16 @@ "type": "Identifier", "start": 7, "end": 14, + "loc": { + "start": { + "line": 1, + "column": 7 + }, + "end": { + "line": 1, + "column": 14 + } + }, "name": "animals" }, "children": [ diff --git a/test/parser/samples/each-block-keyed/output.json b/test/parser/samples/each-block-keyed/output.json index 11cdd45ff15a..61b5442c0d93 100644 --- a/test/parser/samples/each-block-keyed/output.json +++ b/test/parser/samples/each-block-keyed/output.json @@ -12,6 +12,16 @@ "type": "Identifier", "start": 7, "end": 12, + "loc": { + "start": { + "line": 1, + "column": 7 + }, + "end": { + "line": 1, + "column": 12 + } + }, "name": "todos" }, "children": [ @@ -46,16 +56,46 @@ "type": "MemberExpression", "start": 22, "end": 29, + "loc": { + "start": { + "line": 1, + "column": 22 + }, + "end": { + "line": 1, + "column": 29 + } + }, "object": { "type": "Identifier", "start": 22, "end": 26, + "loc": { + "start": { + "line": 1, + "column": 22 + }, + "end": { + "line": 1, + "column": 26 + } + }, "name": "todo" }, "property": { "type": "Identifier", "start": 27, "end": 29, + "loc": { + "start": { + "line": 1, + "column": 27 + }, + "end": { + "line": 1, + "column": 29 + } + }, "name": "id" }, "computed": false diff --git a/test/parser/samples/each-block/output.json b/test/parser/samples/each-block/output.json index 6a60823952ea..38bc7e1d042f 100644 --- a/test/parser/samples/each-block/output.json +++ b/test/parser/samples/each-block/output.json @@ -12,6 +12,16 @@ "type": "Identifier", "start": 7, "end": 14, + "loc": { + "start": { + "line": 1, + "column": 7 + }, + "end": { + "line": 1, + "column": 14 + } + }, "name": "animals" }, "children": [ diff --git a/test/parser/samples/event-handler/output.json b/test/parser/samples/event-handler/output.json index f792ffadcc1a..44bb83de7dfa 100644 --- a/test/parser/samples/event-handler/output.json +++ b/test/parser/samples/event-handler/output.json @@ -20,6 +20,16 @@ "type": "ArrowFunctionExpression", "start": 19, "end": 43, + "loc": { + "start": { + "line": 1, + "column": 19 + }, + "end": { + "line": 1, + "column": 43 + } + }, "id": null, "expression": true, "generator": false, @@ -29,23 +39,63 @@ "type": "AssignmentExpression", "start": 25, "end": 43, + "loc": { + "start": { + "line": 1, + "column": 25 + }, + "end": { + "line": 1, + "column": 43 + } + }, "operator": "=", "left": { "type": "Identifier", "start": 25, "end": 32, + "loc": { + "start": { + "line": 1, + "column": 25 + }, + "end": { + "line": 1, + "column": 32 + } + }, "name": "visible" }, "right": { "type": "UnaryExpression", "start": 35, "end": 43, + "loc": { + "start": { + "line": 1, + "column": 35 + }, + "end": { + "line": 1, + "column": 43 + } + }, "operator": "!", "prefix": true, "argument": { "type": "Identifier", "start": 36, "end": 43, + "loc": { + "start": { + "line": 1, + "column": 36 + }, + "end": { + "line": 1, + "column": 43 + } + }, "name": "visible" } } diff --git a/test/parser/samples/if-block-elseif/output.json b/test/parser/samples/if-block-elseif/output.json index 54fb53dacb5f..0d8fcd987e31 100644 --- a/test/parser/samples/if-block-elseif/output.json +++ b/test/parser/samples/if-block-elseif/output.json @@ -12,10 +12,30 @@ "type": "BinaryExpression", "start": 5, "end": 11, + "loc": { + "start": { + "line": 1, + "column": 5 + }, + "end": { + "line": 1, + "column": 11 + } + }, "left": { "type": "Identifier", "start": 5, "end": 6, + "loc": { + "start": { + "line": 1, + "column": 5 + }, + "end": { + "line": 1, + "column": 6 + } + }, "name": "x" }, "operator": ">", @@ -23,6 +43,16 @@ "type": "Literal", "start": 9, "end": 11, + "loc": { + "start": { + "line": 1, + "column": 9 + }, + "end": { + "line": 1, + "column": 11 + } + }, "value": 10, "raw": "10" } @@ -59,10 +89,30 @@ "type": "BinaryExpression", "start": 52, "end": 57, + "loc": { + "start": { + "line": 3, + "column": 10 + }, + "end": { + "line": 3, + "column": 15 + } + }, "left": { "type": "Identifier", "start": 52, "end": 53, + "loc": { + "start": { + "line": 3, + "column": 10 + }, + "end": { + "line": 3, + "column": 11 + } + }, "name": "x" }, "operator": "<", @@ -70,6 +120,16 @@ "type": "Literal", "start": 56, "end": 57, + "loc": { + "start": { + "line": 3, + "column": 14 + }, + "end": { + "line": 3, + "column": 15 + } + }, "value": 5, "raw": "5" } diff --git a/test/parser/samples/raw-mustaches/output.json b/test/parser/samples/raw-mustaches/output.json index 1b3d9b7a9c7b..764b6df07d45 100644 --- a/test/parser/samples/raw-mustaches/output.json +++ b/test/parser/samples/raw-mustaches/output.json @@ -26,6 +26,16 @@ "type": "Identifier", "start": 11, "end": 15, + "loc": { + "start": { + "line": 1, + "column": 11 + }, + "end": { + "line": 1, + "column": 15 + } + }, "name": "raw1" } }, @@ -44,6 +54,16 @@ "type": "Identifier", "start": 24, "end": 28, + "loc": { + "start": { + "line": 1, + "column": 24 + }, + "end": { + "line": 1, + "column": 28 + } + }, "name": "raw2" } }, diff --git a/test/parser/samples/refs/output.json b/test/parser/samples/refs/output.json index 707da8977439..72a3d7689c4a 100644 --- a/test/parser/samples/refs/output.json +++ b/test/parser/samples/refs/output.json @@ -44,20 +44,60 @@ "type": "Program", "start": 8, "end": 19, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 3, + "column": 0 + } + }, "body": [ { "type": "VariableDeclaration", "start": 10, "end": 18, + "loc": { + "start": { + "line": 2, + "column": 1 + }, + "end": { + "line": 2, + "column": 9 + } + }, "declarations": [ { "type": "VariableDeclarator", "start": 14, "end": 17, + "loc": { + "start": { + "line": 2, + "column": 5 + }, + "end": { + "line": 2, + "column": 8 + } + }, "id": { "type": "Identifier", "start": 14, "end": 17, + "loc": { + "start": { + "line": 2, + "column": 5 + }, + "end": { + "line": 2, + "column": 8 + } + }, "name": "foo" }, "init": null diff --git a/test/parser/samples/script-comment-only/output.json b/test/parser/samples/script-comment-only/output.json index bc541abcc3da..3441d8a7bb12 100644 --- a/test/parser/samples/script-comment-only/output.json +++ b/test/parser/samples/script-comment-only/output.json @@ -30,6 +30,16 @@ "type": "Program", "start": 8, "end": 34, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 3, + "column": 0 + } + }, "body": [], "sourceType": "module" } diff --git a/test/parser/samples/script-comment-trailing-multiline/output.json b/test/parser/samples/script-comment-trailing-multiline/output.json index ec4f8fe69389..3c02b1fbde2d 100644 --- a/test/parser/samples/script-comment-trailing-multiline/output.json +++ b/test/parser/samples/script-comment-trailing-multiline/output.json @@ -56,26 +56,76 @@ "type": "Program", "start": 8, "end": 68, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 7, + "column": 0 + } + }, "body": [ { "type": "VariableDeclaration", "start": 10, "end": 29, + "loc": { + "start": { + "line": 2, + "column": 1 + }, + "end": { + "line": 2, + "column": 20 + } + }, "declarations": [ { "type": "VariableDeclarator", "start": 14, "end": 28, + "loc": { + "start": { + "line": 2, + "column": 5 + }, + "end": { + "line": 2, + "column": 19 + } + }, "id": { "type": "Identifier", "start": 14, "end": 18, + "loc": { + "start": { + "line": 2, + "column": 5 + }, + "end": { + "line": 2, + "column": 9 + } + }, "name": "name" }, "init": { "type": "Literal", "start": 21, "end": 28, + "loc": { + "start": { + "line": 2, + "column": 12 + }, + "end": { + "line": 2, + "column": 19 + } + }, "value": "world", "raw": "'world'" } diff --git a/test/parser/samples/script-comment-trailing/output.json b/test/parser/samples/script-comment-trailing/output.json index 166b1a134be4..beca0010426a 100644 --- a/test/parser/samples/script-comment-trailing/output.json +++ b/test/parser/samples/script-comment-trailing/output.json @@ -56,26 +56,76 @@ "type": "Program", "start": 8, "end": 57, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 5, + "column": 0 + } + }, "body": [ { "type": "VariableDeclaration", "start": 10, "end": 29, + "loc": { + "start": { + "line": 2, + "column": 1 + }, + "end": { + "line": 2, + "column": 20 + } + }, "declarations": [ { "type": "VariableDeclarator", "start": 14, "end": 28, + "loc": { + "start": { + "line": 2, + "column": 5 + }, + "end": { + "line": 2, + "column": 19 + } + }, "id": { "type": "Identifier", "start": 14, "end": 18, + "loc": { + "start": { + "line": 2, + "column": 5 + }, + "end": { + "line": 2, + "column": 9 + } + }, "name": "name" }, "init": { "type": "Literal", "start": 21, "end": 28, + "loc": { + "start": { + "line": 2, + "column": 12 + }, + "end": { + "line": 2, + "column": 19 + } + }, "value": "world", "raw": "'world'" } diff --git a/test/parser/samples/script/output.json b/test/parser/samples/script/output.json index 4dee65735463..00b7073a1940 100644 --- a/test/parser/samples/script/output.json +++ b/test/parser/samples/script/output.json @@ -56,26 +56,76 @@ "type": "Program", "start": 8, "end": 30, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 3, + "column": 0 + } + }, "body": [ { "type": "VariableDeclaration", "start": 10, "end": 29, + "loc": { + "start": { + "line": 2, + "column": 1 + }, + "end": { + "line": 2, + "column": 20 + } + }, "declarations": [ { "type": "VariableDeclarator", "start": 14, "end": 28, + "loc": { + "start": { + "line": 2, + "column": 5 + }, + "end": { + "line": 2, + "column": 19 + } + }, "id": { "type": "Identifier", "start": 14, "end": 18, + "loc": { + "start": { + "line": 2, + "column": 5 + }, + "end": { + "line": 2, + "column": 9 + } + }, "name": "name" }, "init": { "type": "Literal", "start": 21, "end": 28, + "loc": { + "start": { + "line": 2, + "column": 12 + }, + "end": { + "line": 2, + "column": 19 + } + }, "value": "world", "raw": "'world'" } diff --git a/test/parser/samples/self-reference/output.json b/test/parser/samples/self-reference/output.json index 92dfdfe4d0e5..ea9eecc69102 100644 --- a/test/parser/samples/self-reference/output.json +++ b/test/parser/samples/self-reference/output.json @@ -12,10 +12,30 @@ "type": "BinaryExpression", "start": 5, "end": 14, + "loc": { + "start": { + "line": 1, + "column": 5 + }, + "end": { + "line": 1, + "column": 14 + } + }, "left": { "type": "Identifier", "start": 5, "end": 10, + "loc": { + "start": { + "line": 1, + "column": 5 + }, + "end": { + "line": 1, + "column": 10 + } + }, "name": "depth" }, "operator": ">", @@ -23,6 +43,16 @@ "type": "Literal", "start": 13, "end": 14, + "loc": { + "start": { + "line": 1, + "column": 13 + }, + "end": { + "line": 1, + "column": 14 + } + }, "value": 1, "raw": "1" } @@ -48,10 +78,30 @@ "type": "BinaryExpression", "start": 38, "end": 47, + "loc": { + "start": { + "line": 2, + "column": 22 + }, + "end": { + "line": 2, + "column": 31 + } + }, "left": { "type": "Identifier", "start": 38, "end": 43, + "loc": { + "start": { + "line": 2, + "column": 22 + }, + "end": { + "line": 2, + "column": 27 + } + }, "name": "depth" }, "operator": "-", @@ -59,6 +109,16 @@ "type": "Literal", "start": 46, "end": 47, + "loc": { + "start": { + "line": 2, + "column": 30 + }, + "end": { + "line": 2, + "column": 31 + } + }, "value": 1, "raw": "1" } diff --git a/test/parser/samples/transition-intro/output.json b/test/parser/samples/transition-intro/output.json index 418bb97e169c..1e10f40c42fe 100644 --- a/test/parser/samples/transition-intro/output.json +++ b/test/parser/samples/transition-intro/output.json @@ -20,11 +20,31 @@ "type": "ObjectExpression", "start": 16, "end": 28, + "loc": { + "start": { + "line": 1, + "column": 16 + }, + "end": { + "line": 1, + "column": 28 + } + }, "properties": [ { "type": "Property", "start": 17, "end": 27, + "loc": { + "start": { + "line": 1, + "column": 17 + }, + "end": { + "line": 1, + "column": 27 + } + }, "method": false, "shorthand": false, "computed": false, @@ -32,12 +52,32 @@ "type": "Identifier", "start": 17, "end": 24, + "loc": { + "start": { + "line": 1, + "column": 17 + }, + "end": { + "line": 1, + "column": 24 + } + }, "name": "opacity" }, "value": { "type": "Literal", "start": 26, "end": 27, + "loc": { + "start": { + "line": 1, + "column": 26 + }, + "end": { + "line": 1, + "column": 27 + } + }, "value": 0, "raw": "0" }, diff --git a/test/parser/samples/unusual-identifier/output.json b/test/parser/samples/unusual-identifier/output.json index e4a2a186191b..76cc82cfd6de 100644 --- a/test/parser/samples/unusual-identifier/output.json +++ b/test/parser/samples/unusual-identifier/output.json @@ -12,6 +12,16 @@ "type": "Identifier", "start": 7, "end": 13, + "loc": { + "start": { + "line": 1, + "column": 7 + }, + "end": { + "line": 1, + "column": 13 + } + }, "name": "things" }, "children": [ @@ -30,6 +40,16 @@ "type": "Identifier", "start": 26, "end": 28, + "loc": { + "start": { + "line": 2, + "column": 5 + }, + "end": { + "line": 2, + "column": 7 + } + }, "name": "𐊧" } } diff --git a/test/sourcemaps/index.js b/test/sourcemaps/index.js index fb5814e8d814..e5915780c69c 100644 --- a/test/sourcemaps/index.js +++ b/test/sourcemaps/index.js @@ -5,7 +5,7 @@ import { svelte } from "../helpers.js"; import { SourceMapConsumer } from "source-map"; import { getLocator } from "locate-character"; -describe.only("sourcemaps", () => { +describe("sourcemaps", () => { fs.readdirSync("test/sourcemaps/samples").forEach(dir => { if (dir[0] === ".") return; From 24be60744fcab2b287a3769030fd030334fe33f8 Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Sun, 22 Sep 2019 15:23:21 -0400 Subject: [PATCH 75/93] all tests passing --- src/compiler/compile/render_dom/index.ts | 4 +-- test/custom-elements/assert.js | 26 +++++++++++++++++++ test/custom-elements/index.js | 5 ++++ .../samples/no-missing-prop-warnings/test.js | 5 ++-- 4 files changed, 36 insertions(+), 4 deletions(-) diff --git a/src/compiler/compile/render_dom/index.ts b/src/compiler/compile/render_dom/index.ts index 062b85090afa..e542e3ab832a 100644 --- a/src/compiler/compile/render_dom/index.ts +++ b/src/compiler/compile/render_dom/index.ts @@ -1,5 +1,5 @@ import { b, x, p } from 'code-red'; -import { stringify, escape } from '../utils/stringify'; +import { escape } from '../utils/stringify'; import Component from '../Component'; import Renderer from './Renderer'; import { CompileOptions } from '../../interfaces'; @@ -26,7 +26,7 @@ export default function dom( const body = []; - if (component.compile_options.dev && component.file) { + if (renderer.file_var) { body.push(b`const ${renderer.file_var} = "${component.file}";`); } diff --git a/test/custom-elements/assert.js b/test/custom-elements/assert.js index 79aba6c73688..0edbd3112492 100644 --- a/test/custom-elements/assert.js +++ b/test/custom-elements/assert.js @@ -1,3 +1,29 @@ +export function deepEqual(a, b, message) { + if (!is_equal(a, b)) { + throw new Error(message || `Expected ${JSON.stringify(a)} to equal ${JSON.stringify(b)}`); + } +} + +function is_equal(a, b) { + if (a && typeof a === 'object') { + const is_array = Array.isArray(a); + if (Array.isArray(b) !== is_array) return false; + + if (is_array) { + if (a.length !== b.length) return false; + return a.every((value, i) => is_equal(value, b[i])); + } + + const a_keys = Object.keys(a).sort(); + const b_keys = Object.keys(b).sort(); + if (a_keys.join(',') !== b_keys.join(',')) return false; + + return a_keys.every(key => is_equal(a[key], b[key])); + } + + return a === b; +} + export function equal(a, b, message) { if (a != b) throw new Error(message || `Expected ${a} to equal ${b}`); } diff --git a/test/custom-elements/index.js b/test/custom-elements/index.js index 9255d33c0ef4..7fe47f2ecd9e 100644 --- a/test/custom-elements/index.js +++ b/test/custom-elements/index.js @@ -109,6 +109,11 @@ describe('custom-elements', function() { console[type](...args); }); + page.on('error', error => { + console.log('>>> an error happened'); + console.error(error); + }); + try { await page.goto('http://localhost:6789'); diff --git a/test/custom-elements/samples/no-missing-prop-warnings/test.js b/test/custom-elements/samples/no-missing-prop-warnings/test.js index e7ced25e1933..1909e7aef9d7 100644 --- a/test/custom-elements/samples/no-missing-prop-warnings/test.js +++ b/test/custom-elements/samples/no-missing-prop-warnings/test.js @@ -11,8 +11,9 @@ export default function (target) { target.innerHTML = ''; - assert.equal(warnings.length, 1); - assert.equal(warnings[0], ` was created without expected prop 'bar'`); + assert.deepEqual(warnings, [ + ` was created without expected prop 'bar'` + ]); console.warn = warn; } \ No newline at end of file From ab2c228ee06d56cdee5f8809ef5fd4d563e8b549 Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Sun, 22 Sep 2019 20:57:30 -0400 Subject: [PATCH 76/93] fix DebugTag etc --- package-lock.json | 6 +- package.json | 2 +- src/compiler/compile/render_dom/index.ts | 2 +- .../compile/render_dom/wrappers/DebugTag.ts | 95 ++++++++++--------- 4 files changed, 55 insertions(+), 50 deletions(-) diff --git a/package-lock.json b/package-lock.json index d5abb0d992ca..161b5409715a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -507,9 +507,9 @@ "dev": true }, "code-red": { - "version": "0.0.13", - "resolved": "https://registry.npmjs.org/code-red/-/code-red-0.0.13.tgz", - "integrity": "sha512-cBYTCCcEuxdkIvK7LnDlZslan3NoYCV4YAH0xVkePuCD7/TOKg/vWXug7TNjKePLJEnc9isgeK76RzsBy1pShA==", + "version": "0.0.15", + "resolved": "https://registry.npmjs.org/code-red/-/code-red-0.0.15.tgz", + "integrity": "sha512-r3c5r7IFsgKw3IE+F1wkTOezvwZ1N6xXKAJ0Dfyrs+JxHVEWbPU+goKwbo6XCCc8ykO5IU5Pofq1BvuxiXMQHQ==", "dev": true, "requires": { "acorn": "^7.0.0", diff --git a/package.json b/package.json index a357954da6c6..90b926dd52ff 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,7 @@ "acorn": "^7.0.0", "agadoo": "^1.0.1", "c8": "^5.0.1", - "code-red": "0.0.13", + "code-red": "0.0.15", "codecov": "^3.5.0", "css-tree": "1.0.0-alpha22", "eslint": "^6.3.0", diff --git a/src/compiler/compile/render_dom/index.ts b/src/compiler/compile/render_dom/index.ts index e542e3ab832a..78b2ae75c8a5 100644 --- a/src/compiler/compile/render_dom/index.ts +++ b/src/compiler/compile/render_dom/index.ts @@ -497,7 +497,7 @@ export default function dom( super(${options.dev && `options`}); ${should_add_css && b`if (!@_document.getElementById("${component.stylesheet.id}-style")) ${add_css}();`} @init(this, options, ${definition}, create_fragment, ${not_equal}, ${prop_names}); - ${options.dev && b`@dispatch_dev("SvelteRegisterComponent", { component: this, tagName: "${name}", options, id: create_fragment.name });`} + ${options.dev && b`@dispatch_dev("SvelteRegisterComponent", { component: this, tagName: "${name.name}", options, id: create_fragment.name });`} ${dev_props_check} } diff --git a/src/compiler/compile/render_dom/wrappers/DebugTag.ts b/src/compiler/compile/render_dom/wrappers/DebugTag.ts index af8948698a8c..628d05b368c3 100644 --- a/src/compiler/compile/render_dom/wrappers/DebugTag.ts +++ b/src/compiler/compile/render_dom/wrappers/DebugTag.ts @@ -2,9 +2,10 @@ import Renderer from '../Renderer'; import Wrapper from './shared/Wrapper'; import Block from '../Block'; import DebugTag from '../../nodes/DebugTag'; -// import add_to_set from '../../utils/add_to_set'; -import { b } from 'code-red'; -import { Identifier } from 'estree'; +import add_to_set from '../../utils/add_to_set'; +import { b, p } from 'code-red'; +import { Identifier, DebuggerStatement } from 'estree'; +import { changed } from './shared/changed'; export default class DebugTagWrapper extends Wrapper { node: DebugTag; @@ -22,61 +23,65 @@ export default class DebugTagWrapper extends Wrapper { render(block: Block, _parent_node: Identifier, _parent_nodes: Identifier) { const { renderer } = this; - // const { component } = renderer; + const { component } = renderer; if (!renderer.options.dev) return; - // const { var_lookup } = component; + const { var_lookup } = component; + + const start = component.locate(this.node.start + 1); + start.line += 1; + const end = { line: start.line, column: start.column + 6 }; + + const loc = { start, end }; + + const debug: DebuggerStatement = { + type: 'DebuggerStatement', + loc + }; 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}✂];`; - - block.chunks.create.push(b`debugger`); - block.chunks.update.push(b`debugger`); + block.chunks.create.push(debug); + block.chunks.update.push(debug); } else { - // TODO + const log: Identifier = { + type: 'Identifier', + name: 'log', + loc + }; - // const { code } = component; - // code.overwrite(this.node.start + 1, this.node.start + 7, 'log', { - // storeName: true - // }); - // const log = `[✂${this.node.start + 1}-${this.node.start + 7}✂]`; + const dependencies: Set = new Set(); + this.node.expressions.forEach(expression => { + add_to_set(dependencies, expression.dependencies); + }); - // const dependencies = new Set(); - // this.node.expressions.forEach(expression => { - // add_to_set(dependencies, expression.dependencies); - // }); + const condition = changed(Array.from(dependencies)); - // const condition = Array.from(dependencies).map(d => `changed.${d}`).join(' || '); + const contextual_identifiers = this.node.expressions + .filter(e => { + const variable = var_lookup.get(e.node.name); + return !(variable && variable.hoistable); + }) + .map(e => p`${e.node.name}`); - // const ctx_identifiers = this.node.expressions - // .filter(e => { - // const looked_up_var = var_lookup.get(e.node.name); - // return !(looked_up_var && looked_up_var.hoistable); - // }) - // .map(e => e.node.name) - // .join(', '); - // const logged_identifiers = this.node.expressions.map(e => e.node.name).join(', '); + const logged_identifiers = this.node.expressions.map(e => p`${e.node.name}`); - // block.chunks.update.push(b` - // if (${condition}) { - // const { ${ctx_identifiers} } = #ctx; - // @_console.${log}({ ${logged_identifiers} }); - // debugger; - // } - // `); + block.chunks.update.push(b` + if (${condition}) { + const { ${contextual_identifiers} } = #ctx; + @_console.${log}({ ${logged_identifiers} }); + ${debug}; + } + `); - // block.chunks.create.push(b` - // { - // const { ${ctx_identifiers} } = #ctx; - // @_console.${log}({ ${logged_identifiers} }); - // debugger; - // } - // `); + block.chunks.create.push(b` + { + const { ${contextual_identifiers} } = #ctx; + @_console.${log}({ ${logged_identifiers} }); + ${debug}; + } + `); } } } From 68b6d9e09f4a5c4f5c5add55f5efb56bbd7e6adc Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Sun, 22 Sep 2019 21:00:39 -0400 Subject: [PATCH 77/93] SSR debug tag --- .../compile/render_ssr/handlers/DebugTag.ts | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/compiler/compile/render_ssr/handlers/DebugTag.ts b/src/compiler/compile/render_ssr/handlers/DebugTag.ts index 3fd7584d5745..7c45d386402c 100644 --- a/src/compiler/compile/render_ssr/handlers/DebugTag.ts +++ b/src/compiler/compile/render_ssr/handlers/DebugTag.ts @@ -1,19 +1,16 @@ -import { stringify } from '../../utils/stringify'; import DebugTag from '../../nodes/DebugTag'; import Renderer, { RenderOptions } from '../Renderer'; +import { x } from 'code-red'; + export default function(node: DebugTag, renderer: Renderer, options: RenderOptions) { if (!options.dev) return; const filename = options.filename || null; const { line, column } = options.locate(node.start + 1); - const obj = node.expressions.length === 0 - ? `{}` - : `{ ${node.expressions - .map(e => e.node.name) - .join(', ')} }`; - - const str = '${@debug(' + `${filename && stringify(filename)}, ${line}, ${column}, ${obj})}`; + const obj = x`{ + ${node.expressions.map(e => e.node.name)} + }`; - renderer.append(str); + renderer.add_expression(x`@debug(${filename ? x`"${filename}"` : x`null`}, ${line}, ${column}, ${obj})`); } From d7e6ffcdd3f5f3ab5d1e15daaf922be7f245ae45 Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Sun, 22 Sep 2019 21:05:34 -0400 Subject: [PATCH 78/93] remove some unused code --- .../compile/nodes/shared/Expression.ts | 54 +------------------ src/compiler/compile/utils/stringify.ts | 4 -- 2 files changed, 1 insertion(+), 57 deletions(-) diff --git a/src/compiler/compile/nodes/shared/Expression.ts b/src/compiler/compile/nodes/shared/Expression.ts index fe3d5a83f0f1..24753ee40b89 100644 --- a/src/compiler/compile/nodes/shared/Expression.ts +++ b/src/compiler/compile/nodes/shared/Expression.ts @@ -11,57 +11,9 @@ import Block from '../../render_dom/Block'; import is_dynamic from '../../render_dom/wrappers/shared/is_dynamic'; import { x, b } from 'code-red'; import { invalidate } from '../../utils/invalidate'; -import { Node, BinaryExpression, LogicalExpression, FunctionExpression } from 'estree'; +import { Node, FunctionExpression } from 'estree'; import { TemplateNode } from '../../../interfaces'; -const binary_operators: Record = { - '**': 15, - '*': 14, - '/': 14, - '%': 14, - '+': 13, - '-': 13, - '<<': 12, - '>>': 12, - '>>>': 12, - '<': 11, - '<=': 11, - '>': 11, - '>=': 11, - in: 11, - instanceof: 11, - '==': 10, - '!=': 10, - '===': 10, - '!==': 10, - '&': 9, - '^': 8, - '|': 7 -}; - -const logical_operators: Record = { - '&&': 6, - '||': 5 -}; - -const precedence: Record number> = { - Literal: () => 21, - Identifier: () => 21, - ParenthesizedExpression: () => 20, - MemberExpression: () => 19, - NewExpression: () => 19, // can be 18 (if no args) but makes no practical difference - CallExpression: () => 19, - UpdateExpression: () => 17, - UnaryExpression: () => 16, - BinaryExpression: (node: BinaryExpression) => binary_operators[node.operator], - LogicalExpression: (node: LogicalExpression) => logical_operators[node.operator], - ConditionalExpression: () => 4, - AssignmentExpression: () => 3, - YieldExpression: () => 2, - SpreadElement: () => 1, - SequenceExpression: () => 0 -}; - type Owner = Wrapper | TemplateNode; export default class Expression { @@ -220,10 +172,6 @@ export default class Expression { }); } - get_precedence() { - return this.node.type in precedence ? precedence[this.node.type](this.node) : 0; - } - // TODO move this into a render-dom wrapper? manipulate(block?: Block) { // TODO ideally we wouldn't end up calling this method diff --git a/src/compiler/compile/utils/stringify.ts b/src/compiler/compile/utils/stringify.ts index 650a49051a4e..d042cd43ca34 100644 --- a/src/compiler/compile/utils/stringify.ts +++ b/src/compiler/compile/utils/stringify.ts @@ -1,7 +1,3 @@ -export function stringify(data: string, options = {}) { - return JSON.stringify(escape(data, options)); -} - export function string_literal(data: string) { return { type: 'Literal', From f2f71293966a65bdf12e6fbe686823ff5df2ad4d Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Sun, 22 Sep 2019 21:06:43 -0400 Subject: [PATCH 79/93] remove class_matches --- src/compiler/compile/css/Selector.ts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/compiler/compile/css/Selector.ts b/src/compiler/compile/css/Selector.ts index 2f539baf4baa..95eeaaf8cd38 100644 --- a/src/compiler/compile/css/Selector.ts +++ b/src/compiler/compile/css/Selector.ts @@ -250,12 +250,6 @@ function attribute_matches(node: CssNode, name: string, expected_value: string, return false; } -function class_matches(node, name: string) { - return node.classes.some((class_directive) => { - return new RegExp(`\\b${name}\\b`).test(class_directive.name); - }); -} - function unquote(value: CssNode) { if (value.type === 'Identifier') return value.name; const str = value.value; From 2ce451f29d3535e6d91294ec6d9b071fdcab9d59 Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Tue, 8 Oct 2019 22:02:07 -0400 Subject: [PATCH 80/93] various --- src/compiler/compile/Component.ts | 18 ++++++++++++------ src/compiler/compile/render_dom/index.ts | 2 +- .../compile/render_dom/wrappers/IfBlock.ts | 2 +- .../render_ssr/handlers/InlineComponent.ts | 2 +- test/css/index.js | 18 ++++++++++++++++-- 5 files changed, 31 insertions(+), 11 deletions(-) diff --git a/src/compiler/compile/Component.ts b/src/compiler/compile/Component.ts index 77e01f8e795a..292657095d7f 100644 --- a/src/compiler/compile/Component.ts +++ b/src/compiler/compile/Component.ts @@ -294,7 +294,7 @@ export default class Component { enter: (node, parent, key) => { if (node.type === 'Identifier' && !('name' in node)) { console.log(node); - throw new Error('wtf'); + throw new Error('this should never happen'); // TODO remove once satisfied } if (node.type === 'Identifier') { @@ -328,6 +328,7 @@ export default class Component { else { console.log(node); + throw new Error('this should never happen'); // TODO remove once satisfied } } } @@ -1246,15 +1247,20 @@ export default class Component { qualify(name) { if (name === `$$props`) return x`#ctx.$$props`; - const variable = this.var_lookup.get(name); + let [head, ...tail] = name.split('.'); - if (!variable) return name; + const variable = this.var_lookup.get(head); - this.add_reference(name); // TODO we can probably remove most other occurrences of this + if (variable) { + this.add_reference(name); // TODO we can probably remove most other occurrences of this - if (variable.hoistable) return name; + if (!variable.hoistable) { + tail.unshift(head); + head = '#ctx'; + } + } - return x`#ctx.${name}`; + return [head, ...tail].reduce((lhs, rhs) => x`${lhs}.${rhs}`); } warn_if_undefined(name: string, node, template_scope: TemplateScope) { diff --git a/src/compiler/compile/render_dom/index.ts b/src/compiler/compile/render_dom/index.ts index 78b2ae75c8a5..4269a929b961 100644 --- a/src/compiler/compile/render_dom/index.ts +++ b/src/compiler/compile/render_dom/index.ts @@ -442,7 +442,7 @@ export default function dom( constructor(options) { super(); - ${css.code && `this.shadowRoot.innerHTML = \`\`;`} + ${css.code && b`this.shadowRoot.innerHTML = \`\`;`} @init(this, { target: this.shadowRoot }, ${definition}, create_fragment, ${not_equal}, ${prop_names}); diff --git a/src/compiler/compile/render_dom/wrappers/IfBlock.ts b/src/compiler/compile/render_dom/wrappers/IfBlock.ts index f521c9399ec8..e1d93d1a5d75 100644 --- a/src/compiler/compile/render_dom/wrappers/IfBlock.ts +++ b/src/compiler/compile/render_dom/wrappers/IfBlock.ts @@ -374,7 +374,7 @@ export default class IfBlockWrapper extends Wrapper { : b` function ${select_block_type}(#changed, #ctx) { ${this.branches.map(({ condition, snippet }, i) => condition - ? b`if (${snippet || condition}) return ${String(i)};` + ? b`if (${snippet || condition}) return ${i};` : b`return ${i};`)} ${!has_else && b`return -1;`} } diff --git a/src/compiler/compile/render_ssr/handlers/InlineComponent.ts b/src/compiler/compile/render_ssr/handlers/InlineComponent.ts index 9ef293de7706..e9ebb189cbfe 100644 --- a/src/compiler/compile/render_ssr/handlers/InlineComponent.ts +++ b/src/compiler/compile/render_ssr/handlers/InlineComponent.ts @@ -63,7 +63,7 @@ export default function(node: InlineComponent, renderer: Renderer, options: Rend ? renderer.name : node.name === 'svelte:component' ? x`(${node.expression.node}) || @missing_component` - : node.name + : node.name.split('.').reduce(((lhs, rhs) => x`${lhs}.${rhs}`) as any) ); const slot_fns = []; diff --git a/test/css/index.js b/test/css/index.js index be2a10bef18c..61e8a0c6cb14 100644 --- a/test/css/index.js +++ b/test/css/index.js @@ -82,10 +82,24 @@ describe('css', () => { assert.equal(dom.css.code.replace(/svelte(-ref)?-[a-z0-9]+/g, (m, $1) => $1 ? m : 'svelte-xyz'), expected.css); + let ClientComponent; + let ServerComponent; + // we do this here, rather than in the expected.html !== null // block, to verify that valid code was generated - const ClientComponent = create(dom.js.code); - const ServerComponent = create(ssr.js.code); + try { + ClientComponent = create(dom.js.code); + } catch (err) { + console.log(dom.js.code); + throw err; + } + + try { + ServerComponent = create(ssr.js.code); + } catch (err) { + console.log(dom.js.code); + throw err; + } // verify that the right elements have scoping selectors if (expected.html !== null) { From 42e1c8f191294c78a75ab5406225913f2aa30a53 Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Wed, 9 Oct 2019 08:36:28 -0400 Subject: [PATCH 81/93] various --- src/compiler/compile/Component.ts | 32 +------------------ src/compiler/compile/create_module.ts | 5 +++ src/compiler/compile/render_dom/Block.ts | 8 +++++ .../compile/render_dom/wrappers/Window.ts | 2 +- test/js/index.js | 2 +- test/js/samples/bind-online/expected.js | 7 ++-- 6 files changed, 18 insertions(+), 38 deletions(-) diff --git a/src/compiler/compile/Component.ts b/src/compiler/compile/Component.ts index 292657095d7f..885bf1895fae 100644 --- a/src/compiler/compile/Component.ts +++ b/src/compiler/compile/Component.ts @@ -253,41 +253,11 @@ export default class Component { const { compile_options, name } = this; const { format = 'esm' } = compile_options; + // TODO reinstate banner (along with fragment marker comments) const banner = `/* ${ 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; - // } - // ); - const program: any = { type: 'Program', body: result }; walk(program, { diff --git a/src/compiler/compile/create_module.ts b/src/compiler/compile/create_module.ts index 87d7da0dc799..5f2f0cebfd22 100644 --- a/src/compiler/compile/create_module.ts +++ b/src/compiler/compile/create_module.ts @@ -23,6 +23,11 @@ export default function create_module( ) { const internal_path = `${sveltePath}/internal`; + helpers.sort((a, b) => { + if (a.name < b.name) return -1; + return 1; + }); + if (format === 'esm') { return esm(program, name, banner, sveltePath, internal_path, helpers, globals, imports, module_exports); } diff --git a/src/compiler/compile/render_dom/Block.ts b/src/compiler/compile/render_dom/Block.ts index c149ca642d84..fba1b55165bc 100644 --- a/src/compiler/compile/render_dom/Block.ts +++ b/src/compiler/compile/render_dom/Block.ts @@ -352,6 +352,14 @@ export default class Block { }`; } + if (!this.renderer.component.compile_options.dev) { + // allow shorthand names + for (const name in properties) { + const property = properties[name]; + if (property) property.id = null; + } + } + const return_value: any = x`{ key: ${properties.key}, first: ${properties.first}, diff --git a/src/compiler/compile/render_dom/wrappers/Window.ts b/src/compiler/compile/render_dom/wrappers/Window.ts index ce63a431d42b..90846f8a7cc0 100644 --- a/src/compiler/compile/render_dom/wrappers/Window.ts +++ b/src/compiler/compile/render_dom/wrappers/Window.ts @@ -167,7 +167,7 @@ export default class WindowWrapper extends Wrapper { component.partly_hoisted.push(b` function ${id}() { - ${name} = @_navigator.onLine; $$invalidate('${name}', ${name}); + $$invalidate('${name}', ${name} = @_navigator.onLine); } `); diff --git a/test/js/index.js b/test/js/index.js index 1026ea2fdc17..e0fdaa1175a1 100644 --- a/test/js/index.js +++ b/test/js/index.js @@ -3,7 +3,7 @@ import * as fs from "fs"; import * as path from "path"; import { loadConfig, svelte } from "../helpers.js"; -describe.skip("js", () => { +describe.only("js", () => { fs.readdirSync("test/js/samples").forEach(dir => { if (dir[0] === ".") return; diff --git a/test/js/samples/bind-online/expected.js b/test/js/samples/bind-online/expected.js index 0c9faa3ef6f8..d42f804325b0 100644 --- a/test/js/samples/bind-online/expected.js +++ b/test/js/samples/bind-online/expected.js @@ -10,8 +10,7 @@ import { } from "svelte/internal"; function create_fragment(ctx) { - var dispose; - + let dispose; add_render_callback(ctx.onlinestatuschanged); return { @@ -21,12 +20,10 @@ function create_fragment(ctx) { listen(window, "offline", ctx.onlinestatuschanged) ]; }, - m: noop, p: noop, i: noop, o: noop, - d(detaching) { run_all(dispose); } @@ -37,7 +34,7 @@ function instance($$self, $$props, $$invalidate) { let online; function onlinestatuschanged() { - online = navigator.onLine; $$invalidate('online', online); + $$invalidate("online", online = navigator.onLine); } return { online, onlinestatuschanged }; From da4d90004ecfb2450d1f76347a6793b3e0b65e7b Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Wed, 9 Oct 2019 22:20:54 -0400 Subject: [PATCH 82/93] update code-red, update some tests etc --- package-lock.json | 35 ++++++++++-------- package.json | 2 +- src/compiler/compile/render_dom/index.ts | 2 +- .../render_dom/wrappers/shared/add_actions.ts | 4 +- .../action-custom-event-handler/expected.js | 33 ++++++----------- test/js/samples/action/expected.js | 37 ++++++++----------- test/js/samples/bind-online/expected.js | 1 - 7 files changed, 52 insertions(+), 62 deletions(-) diff --git a/package-lock.json b/package-lock.json index 88c3353c22c5..26b2b8b62714 100644 --- a/package-lock.json +++ b/package-lock.json @@ -318,11 +318,6 @@ "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", "dev": true }, - "astring": { - "version": "github:Rich-Harris/astring#9f675d470d1c758de5ec42724aa5dd2e1dabf919", - "from": "github:Rich-Harris/astring#generic-handler", - "dev": true - }, "async-limiter": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", @@ -495,16 +490,15 @@ "dev": true }, "code-red": { - "version": "0.0.15", - "resolved": "https://registry.npmjs.org/code-red/-/code-red-0.0.15.tgz", - "integrity": "sha512-r3c5r7IFsgKw3IE+F1wkTOezvwZ1N6xXKAJ0Dfyrs+JxHVEWbPU+goKwbo6XCCc8ykO5IU5Pofq1BvuxiXMQHQ==", + "version": "0.0.16", + "resolved": "https://registry.npmjs.org/code-red/-/code-red-0.0.16.tgz", + "integrity": "sha512-40SV6oWnBVVfUP+i8NYeTo9EQWtTnlZ17LIv91dKhLa6R/iZKqxOAV/5HEkj86EhLmNiRB7O6hEnga2jy0hoBA==", "dev": true, "requires": { "acorn": "^7.0.0", - "astring": "github:Rich-Harris/astring#9f675d470d1c758de5ec42724aa5dd2e1dabf919", "is-reference": "^1.1.3", - "periscopic": "^1.0.0", - "source-map": "^0.7.3" + "periscopic": "^1.0.1", + "sourcemap-codec": "^1.4.6" } }, "codecov": { @@ -2727,12 +2721,23 @@ "dev": true }, "periscopic": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/periscopic/-/periscopic-1.0.0.tgz", - "integrity": "sha512-ftydZZH2Ca4FdWJXDwQ1Uuz4VEBhh4jXuT1bprR4qg/zM2+FhulluBUxnQXI0olDqADmsQRE1eHLs42iIhNjtA==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/periscopic/-/periscopic-1.0.1.tgz", + "integrity": "sha512-JcSQ6sufVNGT04lPr2f2qGuJ2FCkZcbWBw0gQ8mzSVf9+6bEX9ea6l48+PdAekjJIHlEwSrqJND1TR2cC1FbtQ==", "dev": true, "requires": { - "is-reference": "^1.1.3" + "is-reference": "^1.1.4" + }, + "dependencies": { + "is-reference": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.1.4.tgz", + "integrity": "sha512-uJA/CDPO3Tao3GTrxYn6AwkM4nUPJiGGYu5+cB8qbC7WGFlrKZbiRo7SFKxUAEpFUfiHofWCXBUNhvYJMh+6zw==", + "dev": true, + "requires": { + "@types/estree": "0.0.39" + } + } } }, "pify": { diff --git a/package.json b/package.json index c103604e4a86..44c4cda6d168 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,7 @@ "acorn": "^7.0.0", "agadoo": "^1.1.0", "c8": "^5.0.1", - "code-red": "0.0.15", + "code-red": "0.0.16", "codecov": "^3.5.0", "css-tree": "1.0.0-alpha22", "eslint": "^6.3.0", diff --git a/src/compiler/compile/render_dom/index.ts b/src/compiler/compile/render_dom/index.ts index 4269a929b961..ea2ccb422e07 100644 --- a/src/compiler/compile/render_dom/index.ts +++ b/src/compiler/compile/render_dom/index.ts @@ -283,7 +283,7 @@ export default function dom( const instance_javascript = component.extract_javascript(component.ast.instance); const has_definition = ( - instance_javascript || + instance_javascript.length > 0 || filtered_props.length > 0 || uses_props || component.partly_hoisted.length > 0 || 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 6eb25fcc3610..331a71708efc 100644 --- a/src/compiler/compile/render_dom/wrappers/shared/add_actions.ts +++ b/src/compiler/compile/render_dom/wrappers/shared/add_actions.ts @@ -33,7 +33,7 @@ export default function add_actions( ); if (dependencies && dependencies.length > 0) { - let condition = x`typeof ${id}.update === 'function'`; + let condition = x`@is_function(${id}.update)`; // TODO can this case be handled more elegantly? if (dependencies.length > 0) { @@ -51,7 +51,7 @@ export default function add_actions( } block.chunks.destroy.push( - b`if (${id} && typeof ${id}.destroy === 'function') ${id}.destroy();` + b`if (${id} && @is_function(${id}.destroy)) ${id}.destroy();` ); }); } diff --git a/test/js/samples/action-custom-event-handler/expected.js b/test/js/samples/action-custom-event-handler/expected.js index 34d5ca10aa38..ec65b83cd22b 100644 --- a/test/js/samples/action-custom-event-handler/expected.js +++ b/test/js/samples/action-custom-event-handler/expected.js @@ -1,62 +1,53 @@ -/* generated by Svelte vX.Y.Z */ import { SvelteComponent, detach, element, init, insert, + is_function, noop, safe_not_equal } from "svelte/internal"; function create_fragment(ctx) { - var button, foo_action; + let button; + let foo_action; return { c() { button = element("button"); button.textContent = "foo"; }, - m(target, anchor) { insert(target, button, anchor); - foo_action = foo.call(null, button, ctx.foo_function) || {}; + foo_action = foo.call(null, button, ctx.foo_function) || ({}); }, - p(changed, ctx) { - if (typeof foo_action.update === 'function' && changed.bar) { - foo_action.update.call(null, ctx.foo_function); - } + if (is_function(foo_action.update) && changed.bar) foo_action.update.call(null, ctx.foo_function); }, - i: noop, o: noop, - d(detaching) { - if (detaching) { - detach(button); - } - - if (foo_action && typeof foo_action.destroy === 'function') foo_action.destroy(); + if (detaching) detach(button); + if (foo_action && is_function(foo_action.destroy)) foo_action.destroy(); } }; } -function handleFoo(bar) { - console.log(bar); +function foo(node, callback) { + } -function foo(node, callback) { - // code goes here +function handleFoo(bar) { + console.log(bar); } function instance($$self, $$props, $$invalidate) { let { bar } = $$props; - const foo_function = () => handleFoo(bar); $$self.$set = $$props => { - if ('bar' in $$props) $$invalidate('bar', bar = $$props.bar); + if ("bar" in $$props) $$invalidate("bar", bar = $$props.bar); }; return { bar, foo_function }; diff --git a/test/js/samples/action/expected.js b/test/js/samples/action/expected.js index ed0a0a74304b..04882f88f579 100644 --- a/test/js/samples/action/expected.js +++ b/test/js/samples/action/expected.js @@ -1,4 +1,3 @@ -/* generated by Svelte vX.Y.Z */ import { SvelteComponent, attr, @@ -6,12 +5,14 @@ import { element, init, insert, + is_function, noop, safe_not_equal } from "svelte/internal"; function create_fragment(ctx) { - var a, link_action; + let a; + let link_action; return { c() { @@ -19,39 +20,33 @@ function create_fragment(ctx) { a.textContent = "Test"; attr(a, "href", "#"); }, - m(target, anchor) { insert(target, a, anchor); - link_action = link.call(null, a) || {}; + link_action = link.call(null, a) || ({}); }, - p: noop, i: noop, o: noop, - d(detaching) { - if (detaching) { - detach(a); - } - - if (link_action && typeof link_action.destroy === 'function') link_action.destroy(); + if (detaching) detach(a); + if (link_action && is_function(link_action.destroy)) link_action.destroy(); } }; } function link(node) { - function onClick(event) { - event.preventDefault(); - history.pushState(null, null, event.target.href); - } + function onClick(event) { + event.preventDefault(); + history.pushState(null, null, event.target.href); + } - node.addEventListener('click', onClick); + node.addEventListener("click", onClick); - return { - destroy() { - node.removeEventListener('click', onClick); - } - } + return { + destroy() { + node.removeEventListener("click", onClick); + } + }; } class Component extends SvelteComponent { diff --git a/test/js/samples/bind-online/expected.js b/test/js/samples/bind-online/expected.js index d42f804325b0..30087ca6153e 100644 --- a/test/js/samples/bind-online/expected.js +++ b/test/js/samples/bind-online/expected.js @@ -1,4 +1,3 @@ -/* generated by Svelte vX.Y.Z */ import { SvelteComponent, add_render_callback, From 8f2c657d2ca2993b6a320c5a3f0e18d080da52f3 Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Sat, 12 Oct 2019 20:44:54 -0400 Subject: [PATCH 83/93] get various js tests passing. not all the way there yet --- src/compiler/compile/Component.ts | 21 ++-- src/compiler/compile/render_dom/Block.ts | 21 ++-- src/compiler/compile/render_dom/index.ts | 5 +- .../render_dom/wrappers/Element/Binding.ts | 4 +- .../compile/render_dom/wrappers/IfBlock.ts | 8 +- .../compile/render_dom/wrappers/shared/Tag.ts | 6 +- test/js/samples/bind-open/expected.js | 26 ++-- test/js/samples/bind-width-height/expected.js | 23 ++-- .../capture-inject-dev-only/expected.js | 31 ++--- .../expected.js | 20 +-- .../component-static-array/expected.js | 13 +- .../component-static-immutable/expected.js | 13 +- .../component-static-immutable2/expected.js | 13 +- .../samples/component-static-var/expected.js | 46 +++---- test/js/samples/component-static/expected.js | 13 +- .../samples/computed-collapsed-if/expected.js | 10 +- test/js/samples/css-media-query/expected.js | 12 +- .../css-shadow-dom-keyframes/expected.js | 13 +- test/js/samples/data-attribute/expected.js | 19 ++- test/js/samples/debug-empty/expected.js | 54 ++++---- .../debug-foo-bar-baz-things/expected.js | 114 +++++++++-------- test/js/samples/debug-foo/expected.js | 98 ++++++++------- test/js/samples/debug-hoisted/expected.js | 27 ++-- .../expected.js | 19 ++- .../samples/select-dynamic-value/expected.js | 20 ++- test/js/samples/setup-method/expected.js | 8 +- .../samples/ssr-no-oncreate-etc/expected.js | 13 +- test/js/samples/svg-title/expected.js | 12 +- test/js/samples/title/expected.js | 17 +-- test/js/samples/transition-local/expected.js | 56 +++------ .../transition-repeated-outro/expected.js | 43 +++---- .../expected.js | 43 +++---- .../use-elements-as-anchors/expected.js | 118 +++++++----------- .../samples/window-binding-scroll/expected.js | 30 ++--- 34 files changed, 431 insertions(+), 558 deletions(-) diff --git a/src/compiler/compile/Component.ts b/src/compiler/compile/Component.ts index 885bf1895fae..bab3466c0b69 100644 --- a/src/compiler/compile/Component.ts +++ b/src/compiler/compile/Component.ts @@ -254,9 +254,7 @@ export default class Component { const { format = 'esm' } = compile_options; // TODO reinstate banner (along with fragment marker comments) - const banner = `/* ${ - this.file ? `${this.file} ` : `` - }generated by Svelte v${'__VERSION__'} */`; + const banner = `/* ${this.file ? `${this.file} ` : ``}generated by Svelte v${'__VERSION__'} */`; const program: any = { type: 'Program', body: result }; @@ -278,7 +276,17 @@ export default class Component { const alias = this.global(node.name.slice(2)); node.name = alias.name; } else { - const alias = this.helper(node.name.slice(1)); + let name = node.name.slice(1); + + if (compile_options.dev) { + if (internal_exports.has(`${name}_dev`)) { + name += '_dev'; + } else if (internal_exports.has(`${name}Dev`)) { + name += 'Dev'; + } + } + + const alias = this.helper(name); node.name = alias.name; } } @@ -473,12 +481,11 @@ export default class Component { } extract_imports(content) { - let i = content.body.length; - while (i--) { + for (let i = 0; i < content.body.length; i += 1) { const node = content.body[i]; if (node.type === 'ImportDeclaration') { - content.body.splice(i, 1); + content.body.splice(i--, 1); this.imports.push(node); } } diff --git a/src/compiler/compile/render_dom/Block.ts b/src/compiler/compile/render_dom/Block.ts index fba1b55165bc..8f96520780f1 100644 --- a/src/compiler/compile/render_dom/Block.ts +++ b/src/compiler/compile/render_dom/Block.ts @@ -119,9 +119,8 @@ export default class Block { } assign_variable_names() { - // TODO reimplement for #3539 - const seen = new Set(); - const dupes = new Set(); + const seen: Set = new Set(); + const dupes: Set = new Set(); let i = this.wrappers.length; @@ -131,11 +130,11 @@ export default class Block { if (!wrapper.var) continue; if (wrapper.parent && wrapper.parent.can_use_innerhtml) continue; - if (seen.has(wrapper.var)) { - dupes.add(wrapper.var); + if (seen.has(wrapper.var.name)) { + dupes.add(wrapper.var.name); } - seen.add(wrapper.var); + seen.add(wrapper.var.name); } const counts = new Map(); @@ -146,12 +145,10 @@ export default class Block { if (!wrapper.var) continue; - if (dupes.has(wrapper.var)) { - const i = counts.get(wrapper.var) || 0; - counts.set(wrapper.var, i + 1); - wrapper.var = this.get_unique_name(wrapper.var + i); - } else { - wrapper.var = this.get_unique_name(wrapper.var.name); + if (dupes.has(wrapper.var.name)) { + const i = counts.get(wrapper.var.name) || 0; + counts.set(wrapper.var.name, i + 1); + wrapper.var.name = this.get_unique_name(wrapper.var.name + i).name; } } } diff --git a/src/compiler/compile/render_dom/index.ts b/src/compiler/compile/render_dom/index.ts index ea2ccb422e07..f793e41ac32e 100644 --- a/src/compiler/compile/render_dom/index.ts +++ b/src/compiler/compile/render_dom/index.ts @@ -27,7 +27,8 @@ export default function dom( const body = []; if (renderer.file_var) { - body.push(b`const ${renderer.file_var} = "${component.file}";`); + const file = component.file ? x`"${component.file}"` : x`undefined`; + body.push(b`const ${renderer.file_var} = ${file};`); } const css = component.stylesheet.render(options.filename, !options.customElement); @@ -283,7 +284,7 @@ export default function dom( const instance_javascript = component.extract_javascript(component.ast.instance); const has_definition = ( - instance_javascript.length > 0 || + (instance_javascript && instance_javascript.length > 0) || filtered_props.length > 0 || uses_props || component.partly_hoisted.length > 0 || diff --git a/src/compiler/compile/render_dom/wrappers/Element/Binding.ts b/src/compiler/compile/render_dom/wrappers/Element/Binding.ts index a16e65c91bad..e9fc9a87ef27 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/Binding.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/Binding.ts @@ -89,7 +89,7 @@ export default class BindingWrapper { const dependency_array = [...this.node.expression.dependencies]; - if (dependency_array.length > 1) { + if (dependency_array.length > 0) { update_conditions.push(changed(dependency_array)); } @@ -153,7 +153,7 @@ export default class BindingWrapper { if (update_dom) { if (update_conditions.length > 0) { - const condition = update_conditions.reduce((lhs, rhs) => x`${lhs} || ${rhs}`); + const condition = update_conditions.reduce((lhs, rhs) => x`${lhs} && ${rhs}`); block.chunks.update.push(b` if (${condition}) { diff --git a/src/compiler/compile/render_dom/wrappers/IfBlock.ts b/src/compiler/compile/render_dom/wrappers/IfBlock.ts index e1d93d1a5d75..7273845fbe0e 100644 --- a/src/compiler/compile/render_dom/wrappers/IfBlock.ts +++ b/src/compiler/compile/render_dom/wrappers/IfBlock.ts @@ -550,16 +550,12 @@ export default class IfBlockWrapper extends Wrapper { } } else if (dynamic) { block.chunks.update.push(b` - if (${branch.condition}) { - ${name}.p(#changed, #ctx); - } + if (${branch.condition}) ${name}.p(#changed, #ctx); `); } block.chunks.destroy.push(b` - if (${if_exists_condition}) { - ${name}.d(${detaching}); - } + if (${if_exists_condition}) ${name}.d(${detaching}); `); } } diff --git a/src/compiler/compile/render_dom/wrappers/shared/Tag.ts b/src/compiler/compile/render_dom/wrappers/shared/Tag.ts index 5b0481af27b2..6738dd8c9901 100644 --- a/src/compiler/compile/render_dom/wrappers/shared/Tag.ts +++ b/src/compiler/compile/render_dom/wrappers/shared/Tag.ts @@ -21,11 +21,13 @@ export default class Tag extends Wrapper { update: ((value: Node) => (Node | Node[])) ) { const dependencies = this.node.expression.dynamic_dependencies(); - const snippet = this.node.expression.manipulate(block); + let snippet = this.node.expression.manipulate(block); const value = this.node.should_cache && block.get_unique_name(`${this.var.name}_value`); const content = this.node.should_cache ? value : snippet; + snippet = x`${snippet} + ""`; + if (this.node.should_cache) block.add_variable(value, snippet); // TODO may need to coerce snippet to string if (dependencies.length > 0) { @@ -38,7 +40,7 @@ export default class Tag extends Wrapper { condition = x`!#current || ${condition}`; } - const update_cached_value = x`${value} !== (${value} = ${snippet} + "")`; + const update_cached_value = x`${value} !== (${value} = ${snippet})`; if (this.node.should_cache) { condition = x`${condition} && ${update_cached_value}`; diff --git a/test/js/samples/bind-open/expected.js b/test/js/samples/bind-open/expected.js index 7f739aec8b72..3ccd5604590f 100644 --- a/test/js/samples/bind-open/expected.js +++ b/test/js/samples/bind-open/expected.js @@ -1,4 +1,3 @@ -/* generated by Svelte vX.Y.Z */ import { SvelteComponent, detach, @@ -11,34 +10,31 @@ import { } from "svelte/internal"; function create_fragment(ctx) { - var details, dispose; + let details; + let dispose; return { c() { details = element("details"); + details.innerHTML = `summarycontent - `; +`; + dispose = listen(details, "toggle", ctx.details_toggle_handler); }, - m(target, anchor) { insert(target, details, anchor); - details.open = ctx.open; }, - p(changed, ctx) { - if (changed.open) details.open = ctx.open; + if (changed.open) { + details.open = ctx.open; + } }, - i: noop, o: noop, - d(detaching) { - if (detaching) { - detach(details); - } - + if (detaching) detach(details); dispose(); } }; @@ -49,11 +45,11 @@ function instance($$self, $$props, $$invalidate) { function details_toggle_handler() { open = this.open; - $$invalidate('open', open); + $$invalidate("open", open); } $$self.$set = $$props => { - if ('open' in $$props) $$invalidate('open', open = $$props.open); + if ("open" in $$props) $$invalidate("open", open = $$props.open); }; return { open, details_toggle_handler }; diff --git a/test/js/samples/bind-width-height/expected.js b/test/js/samples/bind-width-height/expected.js index 2ef190588f3e..b10074ce2b2c 100644 --- a/test/js/samples/bind-width-height/expected.js +++ b/test/js/samples/bind-width-height/expected.js @@ -1,4 +1,3 @@ -/* generated by Svelte vX.Y.Z */ import { SvelteComponent, add_render_callback, @@ -12,7 +11,8 @@ import { } from "svelte/internal"; function create_fragment(ctx) { - var div, div_resize_listener; + let div; + let div_resize_listener; return { c() { @@ -20,39 +20,34 @@ function create_fragment(ctx) { div.textContent = "some content"; add_render_callback(() => ctx.div_resize_handler.call(div)); }, - m(target, anchor) { insert(target, div, anchor); div_resize_listener = add_resize_listener(div, ctx.div_resize_handler.bind(div)); }, - p: noop, i: noop, o: noop, - d(detaching) { - if (detaching) { - detach(div); - } - + if (detaching) detach(div); div_resize_listener.cancel(); } }; } function instance($$self, $$props, $$invalidate) { - let { w, h } = $$props; + let { w } = $$props; + let { h } = $$props; function div_resize_handler() { w = this.offsetWidth; h = this.offsetHeight; - $$invalidate('w', w); - $$invalidate('h', h); + $$invalidate("w", w); + $$invalidate("h", h); } $$self.$set = $$props => { - if ('w' in $$props) $$invalidate('w', w = $$props.w); - if ('h' in $$props) $$invalidate('h', h = $$props.h); + if ("w" in $$props) $$invalidate("w", w = $$props.w); + if ("h" in $$props) $$invalidate("h", h = $$props.h); }; return { w, h, div_resize_handler }; diff --git a/test/js/samples/capture-inject-dev-only/expected.js b/test/js/samples/capture-inject-dev-only/expected.js index 8ed14d6cd5a5..7091990056a2 100644 --- a/test/js/samples/capture-inject-dev-only/expected.js +++ b/test/js/samples/capture-inject-dev-only/expected.js @@ -1,4 +1,3 @@ -/* generated by Svelte vX.Y.Z */ import { SvelteComponent, append, @@ -16,7 +15,11 @@ import { } from "svelte/internal"; function create_fragment(ctx) { - var p, t0, t1, input, dispose; + let p; + let t0; + let t1; + let input; + let dispose; return { c() { @@ -26,34 +29,26 @@ function create_fragment(ctx) { input = element("input"); dispose = listen(input, "input", ctx.input_input_handler); }, - m(target, anchor) { insert(target, p, anchor); append(p, t0); insert(target, t1, anchor); insert(target, input, anchor); - set_input_value(input, ctx.foo); }, - p(changed, ctx) { - if (changed.foo) { - set_data(t0, ctx.foo); - } + if (changed.foo) set_data(t0, ctx.foo); - if (changed.foo && (input.value !== ctx.foo)) set_input_value(input, ctx.foo); + if (changed.foo && input.value !== ctx.foo) { + set_input_value(input, ctx.foo); + } }, - i: noop, o: noop, - d(detaching) { - if (detaching) { - detach(p); - detach(t1); - detach(input); - } - + if (detaching) detach(p); + if (detaching) detach(t1); + if (detaching) detach(input); dispose(); } }; @@ -64,7 +59,7 @@ function instance($$self, $$props, $$invalidate) { function input_input_handler() { foo = this.value; - $$invalidate('foo', foo); + $$invalidate("foo", foo); } return { foo, input_input_handler }; diff --git a/test/js/samples/collapses-text-around-comments/expected.js b/test/js/samples/collapses-text-around-comments/expected.js index 09b40a1e9827..9a34f69b0771 100644 --- a/test/js/samples/collapses-text-around-comments/expected.js +++ b/test/js/samples/collapses-text-around-comments/expected.js @@ -1,4 +1,3 @@ -/* generated by Svelte vX.Y.Z */ import { SvelteComponent, append, @@ -15,13 +14,14 @@ import { function add_css() { var style = element("style"); - style.id = 'svelte-1a7i8ec-style'; + style.id = "svelte-1a7i8ec-style"; style.textContent = "p.svelte-1a7i8ec{color:red}"; append(document.head, style); } function create_fragment(ctx) { - var p, t; + let p; + let t; return { c() { @@ -29,25 +29,17 @@ function create_fragment(ctx) { t = text(ctx.foo); attr(p, "class", "svelte-1a7i8ec"); }, - m(target, anchor) { insert(target, p, anchor); append(p, t); }, - p(changed, ctx) { - if (changed.foo) { - set_data(t, ctx.foo); - } + if (changed.foo) set_data(t, ctx.foo); }, - i: noop, o: noop, - d(detaching) { - if (detaching) { - detach(p); - } + if (detaching) detach(p); } }; } @@ -56,7 +48,7 @@ function instance($$self, $$props, $$invalidate) { let { foo = 42 } = $$props; $$self.$set = $$props => { - if ('foo' in $$props) $$invalidate('foo', foo = $$props.foo); + if ("foo" in $$props) $$invalidate("foo", foo = $$props.foo); }; return { foo }; diff --git a/test/js/samples/component-static-array/expected.js b/test/js/samples/component-static-array/expected.js index 6997f431ddf6..3905fcce5681 100644 --- a/test/js/samples/component-static-array/expected.js +++ b/test/js/samples/component-static-array/expected.js @@ -1,4 +1,3 @@ -/* generated by Svelte vX.Y.Z */ import { SvelteComponent, destroy_component, @@ -11,34 +10,27 @@ import { } from "svelte/internal"; function create_fragment(ctx) { - var current; - - var nested = new ctx.Nested({ props: { foo: [1, 2, 3] } }); + let current; + const nested = new ctx.Nested({ props: { foo: [1, 2, 3] } }); return { c() { nested.$$.fragment.c(); }, - m(target, anchor) { mount_component(nested, target, anchor); current = true; }, - p: noop, - i(local) { if (current) return; transition_in(nested.$$.fragment, local); - current = true; }, - o(local) { transition_out(nested.$$.fragment, local); current = false; }, - d(detaching) { destroy_component(nested, detaching); } @@ -47,7 +39,6 @@ function create_fragment(ctx) { function instance($$self) { const Nested = window.Nested; - return { Nested }; } diff --git a/test/js/samples/component-static-immutable/expected.js b/test/js/samples/component-static-immutable/expected.js index 4b33d537ca8a..0e8bf81d09a7 100644 --- a/test/js/samples/component-static-immutable/expected.js +++ b/test/js/samples/component-static-immutable/expected.js @@ -1,4 +1,3 @@ -/* generated by Svelte vX.Y.Z */ import { SvelteComponent, destroy_component, @@ -11,34 +10,27 @@ import { } from "svelte/internal"; function create_fragment(ctx) { - var current; - - var nested = new ctx.Nested({ props: { foo: "bar" } }); + let current; + const nested = new ctx.Nested({ props: { foo: "bar" } }); return { c() { nested.$$.fragment.c(); }, - m(target, anchor) { mount_component(nested, target, anchor); current = true; }, - p: noop, - i(local) { if (current) return; transition_in(nested.$$.fragment, local); - current = true; }, - o(local) { transition_out(nested.$$.fragment, local); current = false; }, - d(detaching) { destroy_component(nested, detaching); } @@ -47,7 +39,6 @@ function create_fragment(ctx) { function instance($$self) { const Nested = window.Nested; - return { Nested }; } diff --git a/test/js/samples/component-static-immutable2/expected.js b/test/js/samples/component-static-immutable2/expected.js index 4b33d537ca8a..0e8bf81d09a7 100644 --- a/test/js/samples/component-static-immutable2/expected.js +++ b/test/js/samples/component-static-immutable2/expected.js @@ -1,4 +1,3 @@ -/* generated by Svelte vX.Y.Z */ import { SvelteComponent, destroy_component, @@ -11,34 +10,27 @@ import { } from "svelte/internal"; function create_fragment(ctx) { - var current; - - var nested = new ctx.Nested({ props: { foo: "bar" } }); + let current; + const nested = new ctx.Nested({ props: { foo: "bar" } }); return { c() { nested.$$.fragment.c(); }, - m(target, anchor) { mount_component(nested, target, anchor); current = true; }, - p: noop, - i(local) { if (current) return; transition_in(nested.$$.fragment, local); - current = true; }, - o(local) { transition_out(nested.$$.fragment, local); current = false; }, - d(detaching) { destroy_component(nested, detaching); } @@ -47,7 +39,6 @@ function create_fragment(ctx) { function instance($$self) { const Nested = window.Nested; - return { Nested }; } diff --git a/test/js/samples/component-static-var/expected.js b/test/js/samples/component-static-var/expected.js index 2f6521f87efa..aa3ec5a5031c 100644 --- a/test/js/samples/component-static-var/expected.js +++ b/test/js/samples/component-static-var/expected.js @@ -1,4 +1,3 @@ -/* generated by Svelte vX.Y.Z */ import { SvelteComponent, destroy_component, @@ -14,15 +13,18 @@ import { transition_in, transition_out } from "svelte/internal"; + import Foo from "./Foo.svelte"; import Bar from "./Bar.svelte"; function create_fragment(ctx) { - var t0, t1, input, current, dispose; - - var foo = new Foo({ props: { x: y } }); - - var bar = new Bar({ props: { x: ctx.z } }); + let t0; + let t1; + let input; + let current; + let dispose; + const foo = new Foo({ props: { x: y } }); + const bar = new Bar({ props: { x: ctx.z } }); return { c() { @@ -33,56 +35,41 @@ function create_fragment(ctx) { input = element("input"); dispose = listen(input, "input", ctx.input_input_handler); }, - m(target, anchor) { mount_component(foo, target, anchor); insert(target, t0, anchor); mount_component(bar, target, anchor); insert(target, t1, anchor); insert(target, input, anchor); - set_input_value(input, ctx.z); - current = true; }, - p(changed, ctx) { - var bar_changes = {}; + const bar_changes = {}; if (changed.z) bar_changes.x = ctx.z; bar.$set(bar_changes); - if (changed.z && (input.value !== ctx.z)) set_input_value(input, ctx.z); + if (changed.z && input.value !== ctx.z) { + set_input_value(input, ctx.z); + } }, - i(local) { if (current) return; transition_in(foo.$$.fragment, local); - transition_in(bar.$$.fragment, local); - current = true; }, - o(local) { transition_out(foo.$$.fragment, local); transition_out(bar.$$.fragment, local); current = false; }, - d(detaching) { destroy_component(foo, detaching); - - if (detaching) { - detach(t0); - } - + if (detaching) detach(t0); destroy_component(bar, detaching); - - if (detaching) { - detach(t1); - detach(input); - } - + if (detaching) detach(t1); + if (detaching) detach(input); dispose(); } }; @@ -91,12 +78,11 @@ function create_fragment(ctx) { let y = 1; function instance($$self, $$props, $$invalidate) { - let z = 2; function input_input_handler() { z = this.value; - $$invalidate('z', z); + $$invalidate("z", z); } return { z, input_input_handler }; diff --git a/test/js/samples/component-static/expected.js b/test/js/samples/component-static/expected.js index 5a031a32a42a..f82d5d026eea 100644 --- a/test/js/samples/component-static/expected.js +++ b/test/js/samples/component-static/expected.js @@ -1,4 +1,3 @@ -/* generated by Svelte vX.Y.Z */ import { SvelteComponent, destroy_component, @@ -11,34 +10,27 @@ import { } from "svelte/internal"; function create_fragment(ctx) { - var current; - - var nested = new ctx.Nested({ props: { foo: "bar" } }); + let current; + const nested = new ctx.Nested({ props: { foo: "bar" } }); return { c() { nested.$$.fragment.c(); }, - m(target, anchor) { mount_component(nested, target, anchor); current = true; }, - p: noop, - i(local) { if (current) return; transition_in(nested.$$.fragment, local); - current = true; }, - o(local) { transition_out(nested.$$.fragment, local); current = false; }, - d(detaching) { destroy_component(nested, detaching); } @@ -47,7 +39,6 @@ function create_fragment(ctx) { function instance($$self) { const Nested = window.Nested; - return { Nested }; } diff --git a/test/js/samples/computed-collapsed-if/expected.js b/test/js/samples/computed-collapsed-if/expected.js index bc7c383319b0..2aff419120fc 100644 --- a/test/js/samples/computed-collapsed-if/expected.js +++ b/test/js/samples/computed-collapsed-if/expected.js @@ -1,10 +1,4 @@ -/* generated by Svelte vX.Y.Z */ -import { - SvelteComponent, - init, - noop, - safe_not_equal -} from "svelte/internal"; +import { SvelteComponent, init, noop, safe_not_equal } from "svelte/internal"; function create_fragment(ctx) { return { @@ -29,7 +23,7 @@ function instance($$self, $$props, $$invalidate) { } $$self.$set = $$props => { - if ('x' in $$props) $$invalidate('x', x = $$props.x); + if ("x" in $$props) $$invalidate("x", x = $$props.x); }; return { x, a, b }; diff --git a/test/js/samples/css-media-query/expected.js b/test/js/samples/css-media-query/expected.js index 82b7c5dfc800..8690f5a34e43 100644 --- a/test/js/samples/css-media-query/expected.js +++ b/test/js/samples/css-media-query/expected.js @@ -1,4 +1,3 @@ -/* generated by Svelte vX.Y.Z */ import { SvelteComponent, append, @@ -13,32 +12,27 @@ import { function add_css() { var style = element("style"); - style.id = 'svelte-1slhpfn-style'; + style.id = "svelte-1slhpfn-style"; style.textContent = "@media(min-width: 1px){div.svelte-1slhpfn{color:red}}"; append(document.head, style); } function create_fragment(ctx) { - var div; + let div; return { c() { div = element("div"); attr(div, "class", "svelte-1slhpfn"); }, - m(target, anchor) { insert(target, div, anchor); }, - p: noop, i: noop, o: noop, - d(detaching) { - if (detaching) { - detach(div); - } + if (detaching) detach(div); } }; } diff --git a/test/js/samples/css-shadow-dom-keyframes/expected.js b/test/js/samples/css-shadow-dom-keyframes/expected.js index 9f70b8ec66b2..817881188008 100644 --- a/test/js/samples/css-shadow-dom-keyframes/expected.js +++ b/test/js/samples/css-shadow-dom-keyframes/expected.js @@ -1,4 +1,3 @@ -/* generated by Svelte vX.Y.Z */ import { SvelteElement, detach, @@ -10,7 +9,7 @@ import { } from "svelte/internal"; function create_fragment(ctx) { - var div; + let div; return { c() { @@ -18,19 +17,14 @@ function create_fragment(ctx) { div.textContent = "fades in"; this.c = noop; }, - m(target, anchor) { insert(target, div, anchor); }, - p: noop, i: noop, o: noop, - d(detaching) { - if (detaching) { - detach(div); - } + if (detaching) detach(div); } }; } @@ -38,9 +32,7 @@ function create_fragment(ctx) { class Component extends SvelteElement { constructor(options) { super(); - this.shadowRoot.innerHTML = ``; - init(this, { target: this.shadowRoot }, null, create_fragment, safe_not_equal, []); if (options) { @@ -52,5 +44,4 @@ class Component extends SvelteElement { } customElements.define("custom-element", Component); - export default Component; \ No newline at end of file diff --git a/test/js/samples/data-attribute/expected.js b/test/js/samples/data-attribute/expected.js index 12ba50e69f4e..a3d450d411a9 100644 --- a/test/js/samples/data-attribute/expected.js +++ b/test/js/samples/data-attribute/expected.js @@ -1,4 +1,3 @@ -/* generated by Svelte vX.Y.Z */ import { SvelteComponent, attr, @@ -12,7 +11,9 @@ import { } from "svelte/internal"; function create_fragment(ctx) { - var div0, t, div1; + let div0; + let t; + let div1; return { c() { @@ -22,28 +23,22 @@ function create_fragment(ctx) { attr(div0, "data-foo", "bar"); attr(div1, "data-foo", ctx.bar); }, - m(target, anchor) { insert(target, div0, anchor); insert(target, t, anchor); insert(target, div1, anchor); }, - p(changed, ctx) { if (changed.bar) { attr(div1, "data-foo", ctx.bar); } }, - i: noop, o: noop, - d(detaching) { - if (detaching) { - detach(div0); - detach(t); - detach(div1); - } + if (detaching) detach(div0); + if (detaching) detach(t); + if (detaching) detach(div1); } }; } @@ -52,7 +47,7 @@ function instance($$self, $$props, $$invalidate) { let { bar } = $$props; $$self.$set = $$props => { - if ('bar' in $$props) $$invalidate('bar', bar = $$props.bar); + if ("bar" in $$props) $$invalidate("bar", bar = $$props.bar); }; return { bar }; diff --git a/test/js/samples/debug-empty/expected.js b/test/js/samples/debug-empty/expected.js index e0988b6222b4..05bcf281c59b 100644 --- a/test/js/samples/debug-empty/expected.js +++ b/test/js/samples/debug-empty/expected.js @@ -1,4 +1,3 @@ -/* generated by Svelte vX.Y.Z */ import { SvelteComponentDev, add_location, @@ -18,7 +17,11 @@ import { const file = undefined; function create_fragment(ctx) { - var h1, t0, t1, t2, t3; + let h1; + let t0; + let t1; + let t2; + let t3; const block = { c: function create() { @@ -30,11 +33,9 @@ function create_fragment(ctx) { debugger; add_location(h1, file, 4, 0, 38); }, - l: function claim(nodes) { throw new Error("options.hydrate only works if the component was compiled with the `hydratable: true` option"); }, - m: function mount(target, anchor) { insert_dev(target, h1, anchor); append_dev(h1, t0); @@ -42,39 +43,39 @@ function create_fragment(ctx) { append_dev(h1, t2); insert_dev(target, t3, anchor); }, - p: function update(changed, ctx) { - if (changed.name) { - set_data_dev(t1, ctx.name); - } - + if (changed.name) set_data_dev(t1, ctx.name); debugger; }, - i: noop, o: noop, - d: function destroy(detaching) { - if (detaching) { - detach_dev(h1); - detach_dev(t3); - } + if (detaching) detach_dev(h1); + if (detaching) detach_dev(t3); } }; - dispatch_dev("SvelteRegisterBlock", { block, id: create_fragment.name, type: "component", source: "", ctx }); + + dispatch_dev("SvelteRegisterBlock", { + block, + id: create_fragment.name, + type: "component", + source: "", + ctx + }); + return block; } function instance($$self, $$props, $$invalidate) { let { name } = $$props; + const writable_props = ["name"]; - const writable_props = ['name']; Object.keys($$props).forEach(key => { - if (!writable_props.includes(key) && !key.startsWith('$$')) console.warn(` was created with unknown prop '${key}'`); + if (!writable_props.includes(key) && !key.startsWith("$$")) console.warn(` was created with unknown prop '${key}'`); }); $$self.$set = $$props => { - if ('name' in $$props) $$invalidate('name', name = $$props.name); + if ("name" in $$props) $$invalidate("name", name = $$props.name); }; $$self.$capture_state = () => { @@ -82,7 +83,7 @@ function instance($$self, $$props, $$invalidate) { }; $$self.$inject_state = $$props => { - if ('name' in $$props) $$invalidate('name', name = $$props.name); + if ("name" in $$props) $$invalidate("name", name = $$props.name); }; return { name }; @@ -92,11 +93,18 @@ class Component extends SvelteComponentDev { constructor(options) { super(options); init(this, options, instance, create_fragment, safe_not_equal, ["name"]); - dispatch_dev("SvelteRegisterComponent", { component: this, tagName: "Component", options, id: create_fragment.name }); + + dispatch_dev("SvelteRegisterComponent", { + component: this, + tagName: "Component", + options, + id: create_fragment.name + }); const { ctx } = this.$$; - const props = options.props || {}; - if (ctx.name === undefined && !('name' in props)) { + const props = options.props || ({}); + + if (ctx.name === undefined && !("name" in props)) { console.warn(" was created without expected prop 'name'"); } } diff --git a/test/js/samples/debug-foo-bar-baz-things/expected.js b/test/js/samples/debug-foo-bar-baz-things/expected.js index 15d953f6bc59..d9628b884b2f 100644 --- a/test/js/samples/debug-foo-bar-baz-things/expected.js +++ b/test/js/samples/debug-foo-bar-baz-things/expected.js @@ -1,4 +1,3 @@ -/* generated by Svelte vX.Y.Z */ import { SvelteComponentDev, add_location, @@ -24,9 +23,11 @@ function get_each_context(ctx, list, i) { return child_ctx; } -// (8:0) {#each things as thing} function create_each_block(ctx) { - var span, t0_value = ctx.thing.name + "", t0, t1; + let span; + let t0_value = ctx.thing.name + ""; + let t0; + let t1; const block = { c: function create() { @@ -39,19 +40,16 @@ function create_each_block(ctx) { console.log({ foo, bar, baz, thing }); debugger; } + add_location(span, file, 8, 1, 116); }, - m: function mount(target, anchor) { insert_dev(target, span, anchor); append_dev(span, t0); insert_dev(target, t1, anchor); }, - p: function update(changed, ctx) { - if ((changed.things) && t0_value !== (t0_value = ctx.thing.name + "")) { - set_data_dev(t0, t0_value); - } + if (changed.things && t0_value !== (t0_value = ctx.thing.name + "")) set_data_dev(t0, t0_value); if (changed.foo || changed.bar || changed.baz || changed.things) { const { foo, bar, baz, thing } = ctx; @@ -59,23 +57,29 @@ function create_each_block(ctx) { debugger; } }, - d: function destroy(detaching) { - if (detaching) { - detach_dev(span); - detach_dev(t1); - } + if (detaching) detach_dev(span); + if (detaching) detach_dev(t1); } }; - dispatch_dev("SvelteRegisterBlock", { block, id: create_each_block.name, type: "each", source: "(8:0) {#each things as thing}", ctx }); + + dispatch_dev("SvelteRegisterBlock", { + block, + id: create_each_block.name, + type: "each", + source: "(8:0) {#each things as thing}", + ctx + }); + return block; } function create_fragment(ctx) { - var t0, p, t1, t2; - + let t0; + let p; + let t1; + let t2; let each_value = ctx.things; - let each_blocks = []; for (let i = 0; i < each_value.length; i += 1) { @@ -94,11 +98,9 @@ function create_fragment(ctx) { t2 = text(ctx.foo); add_location(p, file, 12, 0, 182); }, - l: function claim(nodes) { throw new Error("options.hydrate only works if the component was compiled with the `hydratable: true` option"); }, - m: function mount(target, anchor) { for (let i = 0; i < each_blocks.length; i += 1) { each_blocks[i].m(target, anchor); @@ -109,12 +111,11 @@ function create_fragment(ctx) { append_dev(p, t1); append_dev(p, t2); }, - p: function update(changed, ctx) { if (changed.things) { each_value = ctx.things; - let i; + for (i = 0; i < each_value.length; i += 1) { const child_ctx = get_each_context(ctx, each_value, i); @@ -130,43 +131,48 @@ function create_fragment(ctx) { for (; i < each_blocks.length; i += 1) { each_blocks[i].d(1); } + each_blocks.length = each_value.length; } - if (changed.foo) { - set_data_dev(t2, ctx.foo); - } + if (changed.foo) set_data_dev(t2, ctx.foo); }, - i: noop, o: noop, - d: function destroy(detaching) { destroy_each(each_blocks, detaching); - - if (detaching) { - detach_dev(t0); - detach_dev(p); - } + if (detaching) detach_dev(t0); + if (detaching) detach_dev(p); } }; - dispatch_dev("SvelteRegisterBlock", { block, id: create_fragment.name, type: "component", source: "", ctx }); + + dispatch_dev("SvelteRegisterBlock", { + block, + id: create_fragment.name, + type: "component", + source: "", + ctx + }); + return block; } function instance($$self, $$props, $$invalidate) { - let { things, foo, bar, baz } = $$props; + let { things } = $$props; + let { foo } = $$props; + let { bar } = $$props; + let { baz } = $$props; + const writable_props = ["things", "foo", "bar", "baz"]; - const writable_props = ['things', 'foo', 'bar', 'baz']; Object.keys($$props).forEach(key => { - if (!writable_props.includes(key) && !key.startsWith('$$')) console.warn(` was created with unknown prop '${key}'`); + if (!writable_props.includes(key) && !key.startsWith("$$")) console.warn(` was created with unknown prop '${key}'`); }); $$self.$set = $$props => { - if ('things' in $$props) $$invalidate('things', things = $$props.things); - if ('foo' in $$props) $$invalidate('foo', foo = $$props.foo); - if ('bar' in $$props) $$invalidate('bar', bar = $$props.bar); - if ('baz' in $$props) $$invalidate('baz', baz = $$props.baz); + if ("things" in $$props) $$invalidate("things", things = $$props.things); + if ("foo" in $$props) $$invalidate("foo", foo = $$props.foo); + if ("bar" in $$props) $$invalidate("bar", bar = $$props.bar); + if ("baz" in $$props) $$invalidate("baz", baz = $$props.baz); }; $$self.$capture_state = () => { @@ -174,10 +180,10 @@ function instance($$self, $$props, $$invalidate) { }; $$self.$inject_state = $$props => { - if ('things' in $$props) $$invalidate('things', things = $$props.things); - if ('foo' in $$props) $$invalidate('foo', foo = $$props.foo); - if ('bar' in $$props) $$invalidate('bar', bar = $$props.bar); - if ('baz' in $$props) $$invalidate('baz', baz = $$props.baz); + if ("things" in $$props) $$invalidate("things", things = $$props.things); + if ("foo" in $$props) $$invalidate("foo", foo = $$props.foo); + if ("bar" in $$props) $$invalidate("bar", bar = $$props.bar); + if ("baz" in $$props) $$invalidate("baz", baz = $$props.baz); }; return { things, foo, bar, baz }; @@ -187,20 +193,30 @@ class Component extends SvelteComponentDev { constructor(options) { super(options); init(this, options, instance, create_fragment, safe_not_equal, ["things", "foo", "bar", "baz"]); - dispatch_dev("SvelteRegisterComponent", { component: this, tagName: "Component", options, id: create_fragment.name }); + + dispatch_dev("SvelteRegisterComponent", { + component: this, + tagName: "Component", + options, + id: create_fragment.name + }); const { ctx } = this.$$; - const props = options.props || {}; - if (ctx.things === undefined && !('things' in props)) { + const props = options.props || ({}); + + if (ctx.things === undefined && !("things" in props)) { console.warn(" was created without expected prop 'things'"); } - if (ctx.foo === undefined && !('foo' in props)) { + + if (ctx.foo === undefined && !("foo" in props)) { console.warn(" was created without expected prop 'foo'"); } - if (ctx.bar === undefined && !('bar' in props)) { + + if (ctx.bar === undefined && !("bar" in props)) { console.warn(" was created without expected prop 'bar'"); } - if (ctx.baz === undefined && !('baz' in props)) { + + if (ctx.baz === undefined && !("baz" in props)) { console.warn(" was created without expected prop 'baz'"); } } diff --git a/test/js/samples/debug-foo/expected.js b/test/js/samples/debug-foo/expected.js index 08a92171d19f..c4c7983fd60c 100644 --- a/test/js/samples/debug-foo/expected.js +++ b/test/js/samples/debug-foo/expected.js @@ -1,4 +1,3 @@ -/* generated by Svelte vX.Y.Z */ import { SvelteComponentDev, add_location, @@ -24,9 +23,11 @@ function get_each_context(ctx, list, i) { return child_ctx; } -// (6:0) {#each things as thing} function create_each_block(ctx) { - var span, t0_value = ctx.thing.name + "", t0, t1; + let span; + let t0_value = ctx.thing.name + ""; + let t0; + let t1; const block = { c: function create() { @@ -39,19 +40,16 @@ function create_each_block(ctx) { console.log({ foo }); debugger; } + add_location(span, file, 6, 1, 82); }, - m: function mount(target, anchor) { insert_dev(target, span, anchor); append_dev(span, t0); insert_dev(target, t1, anchor); }, - p: function update(changed, ctx) { - if ((changed.things) && t0_value !== (t0_value = ctx.thing.name + "")) { - set_data_dev(t0, t0_value); - } + if (changed.things && t0_value !== (t0_value = ctx.thing.name + "")) set_data_dev(t0, t0_value); if (changed.foo) { const { foo } = ctx; @@ -59,23 +57,29 @@ function create_each_block(ctx) { debugger; } }, - d: function destroy(detaching) { - if (detaching) { - detach_dev(span); - detach_dev(t1); - } + if (detaching) detach_dev(span); + if (detaching) detach_dev(t1); } }; - dispatch_dev("SvelteRegisterBlock", { block, id: create_each_block.name, type: "each", source: "(6:0) {#each things as thing}", ctx }); + + dispatch_dev("SvelteRegisterBlock", { + block, + id: create_each_block.name, + type: "each", + source: "(6:0) {#each things as thing}", + ctx + }); + return block; } function create_fragment(ctx) { - var t0, p, t1, t2; - + let t0; + let p; + let t1; + let t2; let each_value = ctx.things; - let each_blocks = []; for (let i = 0; i < each_value.length; i += 1) { @@ -94,11 +98,9 @@ function create_fragment(ctx) { t2 = text(ctx.foo); add_location(p, file, 10, 0, 131); }, - l: function claim(nodes) { throw new Error("options.hydrate only works if the component was compiled with the `hydratable: true` option"); }, - m: function mount(target, anchor) { for (let i = 0; i < each_blocks.length; i += 1) { each_blocks[i].m(target, anchor); @@ -109,12 +111,11 @@ function create_fragment(ctx) { append_dev(p, t1); append_dev(p, t2); }, - p: function update(changed, ctx) { if (changed.things) { each_value = ctx.things; - let i; + for (i = 0; i < each_value.length; i += 1) { const child_ctx = get_each_context(ctx, each_value, i); @@ -130,41 +131,44 @@ function create_fragment(ctx) { for (; i < each_blocks.length; i += 1) { each_blocks[i].d(1); } + each_blocks.length = each_value.length; } - if (changed.foo) { - set_data_dev(t2, ctx.foo); - } + if (changed.foo) set_data_dev(t2, ctx.foo); }, - i: noop, o: noop, - d: function destroy(detaching) { destroy_each(each_blocks, detaching); - - if (detaching) { - detach_dev(t0); - detach_dev(p); - } + if (detaching) detach_dev(t0); + if (detaching) detach_dev(p); } }; - dispatch_dev("SvelteRegisterBlock", { block, id: create_fragment.name, type: "component", source: "", ctx }); + + dispatch_dev("SvelteRegisterBlock", { + block, + id: create_fragment.name, + type: "component", + source: "", + ctx + }); + return block; } function instance($$self, $$props, $$invalidate) { - let { things, foo } = $$props; + let { things } = $$props; + let { foo } = $$props; + const writable_props = ["things", "foo"]; - const writable_props = ['things', 'foo']; Object.keys($$props).forEach(key => { - if (!writable_props.includes(key) && !key.startsWith('$$')) console.warn(` was created with unknown prop '${key}'`); + if (!writable_props.includes(key) && !key.startsWith("$$")) console.warn(` was created with unknown prop '${key}'`); }); $$self.$set = $$props => { - if ('things' in $$props) $$invalidate('things', things = $$props.things); - if ('foo' in $$props) $$invalidate('foo', foo = $$props.foo); + if ("things" in $$props) $$invalidate("things", things = $$props.things); + if ("foo" in $$props) $$invalidate("foo", foo = $$props.foo); }; $$self.$capture_state = () => { @@ -172,8 +176,8 @@ function instance($$self, $$props, $$invalidate) { }; $$self.$inject_state = $$props => { - if ('things' in $$props) $$invalidate('things', things = $$props.things); - if ('foo' in $$props) $$invalidate('foo', foo = $$props.foo); + if ("things" in $$props) $$invalidate("things", things = $$props.things); + if ("foo" in $$props) $$invalidate("foo", foo = $$props.foo); }; return { things, foo }; @@ -183,14 +187,22 @@ class Component extends SvelteComponentDev { constructor(options) { super(options); init(this, options, instance, create_fragment, safe_not_equal, ["things", "foo"]); - dispatch_dev("SvelteRegisterComponent", { component: this, tagName: "Component", options, id: create_fragment.name }); + + dispatch_dev("SvelteRegisterComponent", { + component: this, + tagName: "Component", + options, + id: create_fragment.name + }); const { ctx } = this.$$; - const props = options.props || {}; - if (ctx.things === undefined && !('things' in props)) { + const props = options.props || ({}); + + if (ctx.things === undefined && !("things" in props)) { console.warn(" was created without expected prop 'things'"); } - if (ctx.foo === undefined && !('foo' in props)) { + + if (ctx.foo === undefined && !("foo" in props)) { console.warn(" was created without expected prop 'foo'"); } } diff --git a/test/js/samples/debug-hoisted/expected.js b/test/js/samples/debug-hoisted/expected.js index 62327860e2b5..08e1203fecce 100644 --- a/test/js/samples/debug-hoisted/expected.js +++ b/test/js/samples/debug-hoisted/expected.js @@ -1,4 +1,3 @@ -/* generated by Svelte vX.Y.Z */ import { SvelteComponentDev, dispatch_dev, @@ -18,13 +17,10 @@ function create_fragment(ctx) { debugger; } }, - l: function claim(nodes) { throw new Error("options.hydrate only works if the component was compiled with the `hydratable: true` option"); }, - m: noop, - p: function update(changed, ctx) { if (changed.obj || changed.kobzol) { const { obj } = ctx; @@ -32,12 +28,19 @@ function create_fragment(ctx) { debugger; } }, - i: noop, o: noop, d: noop }; - dispatch_dev("SvelteRegisterBlock", { block, id: create_fragment.name, type: "component", source: "", ctx }); + + dispatch_dev("SvelteRegisterBlock", { + block, + id: create_fragment.name, + type: "component", + source: "", + ctx + }); + return block; } @@ -51,8 +54,8 @@ function instance($$self) { }; $$self.$inject_state = $$props => { - if ('obj' in $$props) $$invalidate('obj', obj = $$props.obj); - if ('kobzol' in $$props) $$invalidate('kobzol', kobzol = $$props.kobzol); + if ("obj" in $$props) $$invalidate("obj", obj = $$props.obj); + if ("kobzol" in $$props) $$invalidate("kobzol", kobzol = $$props.kobzol); }; return { obj }; @@ -62,7 +65,13 @@ class Component extends SvelteComponentDev { constructor(options) { super(options); init(this, options, instance, create_fragment, safe_not_equal, []); - dispatch_dev("SvelteRegisterComponent", { component: this, tagName: "Component", options, id: create_fragment.name }); + + dispatch_dev("SvelteRegisterComponent", { + component: this, + tagName: "Component", + options, + id: create_fragment.name + }); } } diff --git a/test/js/samples/reactive-values-non-writable-dependencies/expected.js b/test/js/samples/reactive-values-non-writable-dependencies/expected.js index 8958f1ffbce6..6bbfbbfc41d2 100644 --- a/test/js/samples/reactive-values-non-writable-dependencies/expected.js +++ b/test/js/samples/reactive-values-non-writable-dependencies/expected.js @@ -1,10 +1,4 @@ -/* generated by Svelte vX.Y.Z */ -import { - SvelteComponent, - init, - noop, - safe_not_equal -} from "svelte/internal"; +import { SvelteComponent, init, noop, safe_not_equal } from "svelte/internal"; function create_fragment(ctx) { return { @@ -18,15 +12,18 @@ function create_fragment(ctx) { } function instance($$self, $$props, $$invalidate) { - let { a = 1, b = 2 } = $$props; + let { a = 1 } = $$props; + let { b = 2 } = $$props; $$self.$set = $$props => { - if ('a' in $$props) $$invalidate('a', a = $$props.a); - if ('b' in $$props) $$invalidate('b', b = $$props.b); + if ("a" in $$props) $$invalidate("a", a = $$props.a); + if ("b" in $$props) $$invalidate("b", b = $$props.b); }; $$self.$$.update = ($$dirty = { a: 1, b: 1 }) => { - if ($$dirty.a || $$dirty.b) { console.log('max', Math.max(a, b)); } + if ($$dirty.a || $$dirty.b) { + console.log("max", Math.max(a, b)); + } }; return { a, b }; diff --git a/test/js/samples/select-dynamic-value/expected.js b/test/js/samples/select-dynamic-value/expected.js index 5a0af01f9957..b7ed1e3b7756 100644 --- a/test/js/samples/select-dynamic-value/expected.js +++ b/test/js/samples/select-dynamic-value/expected.js @@ -1,4 +1,3 @@ -/* generated by Svelte vX.Y.Z */ import { SvelteComponent, append, @@ -11,7 +10,10 @@ import { } from "svelte/internal"; function create_fragment(ctx) { - var select, option0, option1, select_value_value; + let select; + let option0; + let option1; + let select_value_value; return { c() { @@ -25,13 +27,12 @@ function create_fragment(ctx) { option1.__value = "2"; option1.value = option1.__value; }, - m(target, anchor) { insert(target, select, anchor); append(select, option0); append(select, option1); - select_value_value = ctx.current; + for (var i = 0; i < select.options.length; i += 1) { var option = select.options[i]; @@ -41,9 +42,8 @@ function create_fragment(ctx) { } } }, - p(changed, ctx) { - if ((changed.current) && select_value_value !== (select_value_value = ctx.current)) { + if (changed.current && select_value_value !== (select_value_value = ctx.current)) { for (var i = 0; i < select.options.length; i += 1) { var option = select.options[i]; @@ -54,14 +54,10 @@ function create_fragment(ctx) { } } }, - i: noop, o: noop, - d(detaching) { - if (detaching) { - detach(select); - } + if (detaching) detach(select); } }; } @@ -70,7 +66,7 @@ function instance($$self, $$props, $$invalidate) { let { current } = $$props; $$self.$set = $$props => { - if ('current' in $$props) $$invalidate('current', current = $$props.current); + if ("current" in $$props) $$invalidate("current", current = $$props.current); }; return { current }; diff --git a/test/js/samples/setup-method/expected.js b/test/js/samples/setup-method/expected.js index e9370d0e2b54..041ac9bc95b3 100644 --- a/test/js/samples/setup-method/expected.js +++ b/test/js/samples/setup-method/expected.js @@ -1,10 +1,4 @@ -/* generated by Svelte vX.Y.Z */ -import { - SvelteComponent, - init, - noop, - safe_not_equal -} from "svelte/internal"; +import { SvelteComponent, init, noop, safe_not_equal } from "svelte/internal"; function create_fragment(ctx) { return { diff --git a/test/js/samples/ssr-no-oncreate-etc/expected.js b/test/js/samples/ssr-no-oncreate-etc/expected.js index 06cdf057e3c6..89d46061c34b 100644 --- a/test/js/samples/ssr-no-oncreate-etc/expected.js +++ b/test/js/samples/ssr-no-oncreate-etc/expected.js @@ -1,4 +1,3 @@ -/* generated by Svelte vX.Y.Z */ import { create_ssr_component } from "svelte/internal"; import { onDestroy, onMount } from "svelte"; @@ -6,21 +5,21 @@ function preload(input) { return output; } -function foo() { - console.log('foo'); +function swipe(node, callback) { + } -function swipe(node, callback) { - // TODO implement +function foo() { + console.log("foo"); } const Component = create_ssr_component(($$result, $$props, $$bindings, $$slots) => { onMount(() => { - console.log('onMount'); + console.log("onMount"); }); onDestroy(() => { - console.log('onDestroy'); + console.log("onDestroy"); }); return ``; diff --git a/test/js/samples/svg-title/expected.js b/test/js/samples/svg-title/expected.js index 57e3fa30507e..5b425482d3b2 100644 --- a/test/js/samples/svg-title/expected.js +++ b/test/js/samples/svg-title/expected.js @@ -1,4 +1,3 @@ -/* generated by Svelte vX.Y.Z */ import { SvelteComponent, append, @@ -12,7 +11,9 @@ import { } from "svelte/internal"; function create_fragment(ctx) { - var svg, title, t; + let svg; + let title; + let t; return { c() { @@ -20,21 +21,16 @@ function create_fragment(ctx) { title = svg_element("title"); t = text("a title"); }, - m(target, anchor) { insert(target, svg, anchor); append(svg, title); append(title, t); }, - p: noop, i: noop, o: noop, - d(detaching) { - if (detaching) { - detach(svg); - } + if (detaching) detach(svg); } }; } diff --git a/test/js/samples/title/expected.js b/test/js/samples/title/expected.js index 884f39e246e9..4a511abf75ed 100644 --- a/test/js/samples/title/expected.js +++ b/test/js/samples/title/expected.js @@ -1,26 +1,17 @@ -/* generated by Svelte vX.Y.Z */ -import { - SvelteComponent, - init, - noop, - safe_not_equal -} from "svelte/internal"; +import { SvelteComponent, init, noop, safe_not_equal } from "svelte/internal"; function create_fragment(ctx) { - var title_value; - + let title_value; document.title = title_value = "a " + ctx.custom + " title"; return { c: noop, m: noop, - p(changed, ctx) { - if ((changed.custom) && title_value !== (title_value = "a " + ctx.custom + " title")) { + if (changed.custom && title_value !== (title_value = "a " + ctx.custom + " title")) { document.title = title_value; } }, - i: noop, o: noop, d: noop @@ -31,7 +22,7 @@ function instance($$self, $$props, $$invalidate) { let { custom } = $$props; $$self.$set = $$props => { - if ('custom' in $$props) $$invalidate('custom', custom = $$props.custom); + if ("custom" in $$props) $$invalidate("custom", custom = $$props.custom); }; return { custom }; diff --git a/test/js/samples/transition-local/expected.js b/test/js/samples/transition-local/expected.js index f1397e63089f..2cdaba0bddfe 100644 --- a/test/js/samples/transition-local/expected.js +++ b/test/js/samples/transition-local/expected.js @@ -1,4 +1,3 @@ -/* generated by Svelte vX.Y.Z */ import { SvelteComponent, add_render_callback, @@ -13,23 +12,19 @@ import { transition_in } from "svelte/internal"; -// (8:0) {#if x} function create_if_block(ctx) { - var if_block_anchor; - - var if_block = (ctx.y) && create_if_block_1(ctx); + let if_block_anchor; + let if_block = ctx.y && create_if_block_1(ctx); return { c() { if (if_block) if_block.c(); if_block_anchor = empty(); }, - m(target, anchor) { if (if_block) if_block.m(target, anchor); insert(target, if_block_anchor, anchor); }, - p(changed, ctx) { if (ctx.y) { if (!if_block) { @@ -37,37 +32,33 @@ function create_if_block(ctx) { if_block.c(); transition_in(if_block, 1); if_block.m(if_block_anchor.parentNode, if_block_anchor); - } else transition_in(if_block, 1); + } else { + transition_in(if_block, 1); + } } else if (if_block) { if_block.d(1); if_block = null; } }, - d(detaching) { if (if_block) if_block.d(detaching); - - if (detaching) { - detach(if_block_anchor); - } + if (detaching) detach(if_block_anchor); } }; } -// (9:1) {#if y} function create_if_block_1(ctx) { - var div, div_intro; + let div; + let div_intro; return { c() { div = element("div"); div.textContent = "..."; }, - m(target, anchor) { insert(target, div, anchor); }, - i(local) { if (local) { if (!div_intro) { @@ -78,33 +69,26 @@ function create_if_block_1(ctx) { } } }, - o: noop, - d(detaching) { - if (detaching) { - detach(div); - } + if (detaching) detach(div); } }; } function create_fragment(ctx) { - var if_block_anchor; - - var if_block = (ctx.x) && create_if_block(ctx); + let if_block_anchor; + let if_block = ctx.x && create_if_block(ctx); return { c() { if (if_block) if_block.c(); if_block_anchor = empty(); }, - m(target, anchor) { if (if_block) if_block.m(target, anchor); insert(target, if_block_anchor, anchor); }, - p(changed, ctx) { if (ctx.x) { if (if_block) { @@ -119,28 +103,26 @@ function create_fragment(ctx) { if_block = null; } }, - i: noop, o: noop, - d(detaching) { if (if_block) if_block.d(detaching); - - if (detaching) { - detach(if_block_anchor); - } + if (detaching) detach(if_block_anchor); } }; } -function foo() {} +function foo() { + +} function instance($$self, $$props, $$invalidate) { - let { x, y } = $$props; + let { x } = $$props; + let { y } = $$props; $$self.$set = $$props => { - if ('x' in $$props) $$invalidate('x', x = $$props.x); - if ('y' in $$props) $$invalidate('y', y = $$props.y); + if ("x" in $$props) $$invalidate("x", x = $$props.x); + if ("y" in $$props) $$invalidate("y", y = $$props.y); }; return { x, y }; diff --git a/test/js/samples/transition-repeated-outro/expected.js b/test/js/samples/transition-repeated-outro/expected.js index 666f13a6aafe..34a0381c9919 100644 --- a/test/js/samples/transition-repeated-outro/expected.js +++ b/test/js/samples/transition-repeated-outro/expected.js @@ -1,4 +1,3 @@ -/* generated by Svelte vX.Y.Z */ import { SvelteComponent, check_outros, @@ -13,62 +12,54 @@ import { transition_in, transition_out } from "svelte/internal"; + import { fade } from "svelte/transition"; -// (7:0) {#if num < 5} function create_if_block(ctx) { - var div, div_outro, current; + let div; + let div_outro; + let current; return { c() { div = element("div"); div.innerHTML = `

wheeee

`; }, - m(target, anchor) { insert(target, div, anchor); current = true; }, - i(local) { if (current) return; if (div_outro) div_outro.end(1); - current = true; }, - o(local) { div_outro = create_out_transition(div, fade, {}); - current = false; }, - d(detaching) { - if (detaching) { - detach(div); - if (div_outro) div_outro.end(); - } + if (detaching) detach(div); + if (detaching && div_outro) div_outro.end(); } }; } function create_fragment(ctx) { - var if_block_anchor, current; - - var if_block = (ctx.num < 5) && create_if_block(ctx); + let if_block_anchor; + let current; + let if_block = ctx.num < 5 && create_if_block(ctx); return { c() { if (if_block) if_block.c(); if_block_anchor = empty(); }, - m(target, anchor) { if (if_block) if_block.m(target, anchor); insert(target, if_block_anchor, anchor); current = true; }, - p(changed, ctx) { if (ctx.num < 5) { if (!if_block) { @@ -76,33 +67,31 @@ function create_fragment(ctx) { if_block.c(); transition_in(if_block, 1); if_block.m(if_block_anchor.parentNode, if_block_anchor); - } else transition_in(if_block, 1); + } else { + transition_in(if_block, 1); + } } else if (if_block) { group_outros(); + transition_out(if_block, 1, 1, () => { if_block = null; }); + check_outros(); } }, - i(local) { if (current) return; transition_in(if_block); current = true; }, - o(local) { transition_out(if_block); current = false; }, - d(detaching) { if (if_block) if_block.d(detaching); - - if (detaching) { - detach(if_block_anchor); - } + if (detaching) detach(if_block_anchor); } }; } @@ -111,7 +100,7 @@ function instance($$self, $$props, $$invalidate) { let { num = 1 } = $$props; $$self.$set = $$props => { - if ('num' in $$props) $$invalidate('num', num = $$props.num); + if ("num" in $$props) $$invalidate("num", num = $$props.num); }; return { num }; diff --git a/test/js/samples/unreferenced-state-not-invalidated/expected.js b/test/js/samples/unreferenced-state-not-invalidated/expected.js index 17b5638a84a8..a7b25440da37 100644 --- a/test/js/samples/unreferenced-state-not-invalidated/expected.js +++ b/test/js/samples/unreferenced-state-not-invalidated/expected.js @@ -1,4 +1,3 @@ -/* generated by Svelte vX.Y.Z */ import { SvelteComponent, append, @@ -11,35 +10,29 @@ import { set_data, text } from "svelte/internal"; + import { onMount } from "svelte"; function create_fragment(ctx) { - var p, t; + let p; + let t; return { c() { p = element("p"); t = text(ctx.y); }, - m(target, anchor) { insert(target, p, anchor); append(p, t); }, - p(changed, ctx) { - if (changed.y) { - set_data(t, ctx.y); - } + if (changed.y) set_data(t, ctx.y); }, - i: noop, o: noop, - d(detaching) { - if (detaching) { - detach(p); - } + if (detaching) detach(p); } }; } @@ -48,21 +41,29 @@ function instance($$self, $$props, $$invalidate) { let a, b, c; onMount(() => { - const interval = setInterval(() => { - $$invalidate('b', b += 1); - c += 1; - - console.log(b, c); - }, 1000); + const interval = setInterval( + () => { + $$invalidate("b", b += 1); + c += 1; + console.log(b, c); + }, + 1000 + ); return () => clearInterval(interval); }); - let x, y; + let x; + let y; $$self.$$.update = ($$dirty = { a: 1, b: 1 }) => { - if ($$dirty.a) { x = a * 2; } - if ($$dirty.b) { $$invalidate('y', y = b * 2); } + if ($$dirty.a) { + x = a * 2; + } + + if ($$dirty.b) { + $$invalidate("y", y = b * 2); + } }; return { y }; diff --git a/test/js/samples/use-elements-as-anchors/expected.js b/test/js/samples/use-elements-as-anchors/expected.js index b93817d416a6..eab09dfaf9f0 100644 --- a/test/js/samples/use-elements-as-anchors/expected.js +++ b/test/js/samples/use-elements-as-anchors/expected.js @@ -1,4 +1,3 @@ -/* generated by Svelte vX.Y.Z */ import { SvelteComponent, append, @@ -12,128 +11,107 @@ import { space } from "svelte/internal"; -// (10:1) {#if a} function create_if_block_4(ctx) { - var p; + let p; return { c() { p = element("p"); p.textContent = "a"; }, - m(target, anchor) { insert(target, p, anchor); }, - d(detaching) { - if (detaching) { - detach(p); - } + if (detaching) detach(p); } }; } -// (16:1) {#if b} function create_if_block_3(ctx) { - var p; + let p; return { c() { p = element("p"); p.textContent = "b"; }, - m(target, anchor) { insert(target, p, anchor); }, - d(detaching) { - if (detaching) { - detach(p); - } + if (detaching) detach(p); } }; } -// (20:1) {#if c} function create_if_block_2(ctx) { - var p; + let p; return { c() { p = element("p"); p.textContent = "c"; }, - m(target, anchor) { insert(target, p, anchor); }, - d(detaching) { - if (detaching) { - detach(p); - } + if (detaching) detach(p); } }; } -// (26:1) {#if d} function create_if_block_1(ctx) { - var p; + let p; return { c() { p = element("p"); p.textContent = "d"; }, - m(target, anchor) { insert(target, p, anchor); }, - d(detaching) { - if (detaching) { - detach(p); - } + if (detaching) detach(p); } }; } -// (33:0) {#if e} function create_if_block(ctx) { - var p; + let p; return { c() { p = element("p"); p.textContent = "e"; }, - m(target, anchor) { insert(target, p, anchor); }, - d(detaching) { - if (detaching) { - detach(p); - } + if (detaching) detach(p); } }; } function create_fragment(ctx) { - var div, t0, p0, t2, t3, t4, p1, t6, t7, if_block4_anchor; - - var if_block0 = (ctx.a) && create_if_block_4(ctx); - - var if_block1 = (ctx.b) && create_if_block_3(ctx); - - var if_block2 = (ctx.c) && create_if_block_2(ctx); - - var if_block3 = (ctx.d) && create_if_block_1(ctx); - - var if_block4 = (ctx.e) && create_if_block(ctx); + let div; + let t0; + let p0; + let t2; + let t3; + let t4; + let p1; + let t6; + let t7; + let if_block4_anchor; + let if_block0 = ctx.a && create_if_block_4(ctx); + let if_block1 = ctx.b && create_if_block_3(ctx); + let if_block2 = ctx.c && create_if_block_2(ctx); + let if_block3 = ctx.d && create_if_block_1(ctx); + let if_block4 = ctx.e && create_if_block(ctx); return { c() { @@ -155,7 +133,6 @@ function create_fragment(ctx) { if (if_block4) if_block4.c(); if_block4_anchor = empty(); }, - m(target, anchor) { insert(target, div, anchor); if (if_block0) if_block0.m(div, null); @@ -173,13 +150,14 @@ function create_fragment(ctx) { if (if_block4) if_block4.m(target, anchor); insert(target, if_block4_anchor, anchor); }, - p(changed, ctx) { if (ctx.a) { if (!if_block0) { if_block0 = create_if_block_4(ctx); if_block0.c(); if_block0.m(div, t0); + } else { + } } else if (if_block0) { if_block0.d(1); @@ -191,6 +169,8 @@ function create_fragment(ctx) { if_block1 = create_if_block_3(ctx); if_block1.c(); if_block1.m(div, t3); + } else { + } } else if (if_block1) { if_block1.d(1); @@ -202,6 +182,8 @@ function create_fragment(ctx) { if_block2 = create_if_block_2(ctx); if_block2.c(); if_block2.m(div, t4); + } else { + } } else if (if_block2) { if_block2.d(1); @@ -213,6 +195,8 @@ function create_fragment(ctx) { if_block3 = create_if_block_1(ctx); if_block3.c(); if_block3.m(div, null); + } else { + } } else if (if_block3) { if_block3.d(1); @@ -224,48 +208,42 @@ function create_fragment(ctx) { if_block4 = create_if_block(ctx); if_block4.c(); if_block4.m(if_block4_anchor.parentNode, if_block4_anchor); + } else { + } } else if (if_block4) { if_block4.d(1); if_block4 = null; } }, - i: noop, o: noop, - d(detaching) { - if (detaching) { - detach(div); - } - + if (detaching) detach(div); if (if_block0) if_block0.d(); if (if_block1) if_block1.d(); if (if_block2) if_block2.d(); if (if_block3) if_block3.d(); - - if (detaching) { - detach(t7); - } - + if (detaching) detach(t7); if (if_block4) if_block4.d(detaching); - - if (detaching) { - detach(if_block4_anchor); - } + if (detaching) detach(if_block4_anchor); } }; } function instance($$self, $$props, $$invalidate) { - let { a, b, c, d, e } = $$props; + let { a } = $$props; + let { b } = $$props; + let { c } = $$props; + let { d } = $$props; + let { e } = $$props; $$self.$set = $$props => { - if ('a' in $$props) $$invalidate('a', a = $$props.a); - if ('b' in $$props) $$invalidate('b', b = $$props.b); - if ('c' in $$props) $$invalidate('c', c = $$props.c); - if ('d' in $$props) $$invalidate('d', d = $$props.d); - if ('e' in $$props) $$invalidate('e', e = $$props.e); + if ("a" in $$props) $$invalidate("a", a = $$props.a); + if ("b" in $$props) $$invalidate("b", b = $$props.b); + if ("c" in $$props) $$invalidate("c", c = $$props.c); + if ("d" in $$props) $$invalidate("d", d = $$props.d); + if ("e" in $$props) $$invalidate("e", e = $$props.e); }; return { a, b, c, d, e }; diff --git a/test/js/samples/window-binding-scroll/expected.js b/test/js/samples/window-binding-scroll/expected.js index fbe4596e2b1f..d85046c11bff 100644 --- a/test/js/samples/window-binding-scroll/expected.js +++ b/test/js/samples/window-binding-scroll/expected.js @@ -1,4 +1,3 @@ -/* generated by Svelte vX.Y.Z */ import { SvelteComponent, add_render_callback, @@ -15,8 +14,17 @@ import { } from "svelte/internal"; function create_fragment(ctx) { - var scrolling = false, clear_scrolling = () => { scrolling = false }, scrolling_timeout, p, t0, t1, dispose; + let scrolling = false; + let clear_scrolling = () => { + scrolling = false; + }; + + let scrolling_timeout; + let p; + let t0; + let t1; + let dispose; add_render_callback(ctx.onwindowscroll); return { @@ -24,6 +32,7 @@ function create_fragment(ctx) { p = element("p"); t0 = text("scrolled to "); t1 = text(ctx.y); + dispose = listen(window, "scroll", () => { scrolling = true; clearTimeout(scrolling_timeout); @@ -31,13 +40,11 @@ function create_fragment(ctx) { ctx.onwindowscroll(); }); }, - m(target, anchor) { insert(target, p, anchor); append(p, t0); append(p, t1); }, - p(changed, ctx) { if (changed.y && !scrolling) { scrolling = true; @@ -46,19 +53,12 @@ function create_fragment(ctx) { scrolling_timeout = setTimeout(clear_scrolling, 100); } - if (changed.y) { - set_data(t1, ctx.y); - } + if (changed.y) set_data(t1, ctx.y); }, - i: noop, o: noop, - d(detaching) { - if (detaching) { - detach(p); - } - + if (detaching) detach(p); dispose(); } }; @@ -68,11 +68,11 @@ function instance($$self, $$props, $$invalidate) { let { y } = $$props; function onwindowscroll() { - y = window.pageYOffset; $$invalidate('y', y); + $$invalidate("y", y = window.pageYOffset); } $$self.$set = $$props => { - if ('y' in $$props) $$invalidate('y', y = $$props.y); + if ("y" in $$props) $$invalidate("y", y = $$props.y); }; return { y, onwindowscroll }; From 51f2b1cd04981e2b295c2e8f1bf0e9c2b0767e16 Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Sun, 13 Oct 2019 14:57:03 -0400 Subject: [PATCH 84/93] more tests passing --- src/compiler/compile/render_dom/index.ts | 11 +-- .../render_dom/wrappers/Element/Attribute.ts | 4 +- .../wrappers/Element/StyleAttribute.ts | 7 +- .../samples/deconflict-builtins/expected.js | 41 ++++------ .../js/samples/deconflict-globals/expected.js | 12 +-- .../expected.js | 65 +++++++++------- .../samples/dont-invalidate-this/expected.js | 12 +-- test/js/samples/dynamic-import/expected.js | 12 +-- .../each-block-array-literal/expected.js | 56 ++++++-------- .../each-block-changed-check/expected.js | 75 +++++++++---------- .../each-block-keyed-animated/expected.js | 48 ++++-------- test/js/samples/each-block-keyed/expected.js | 43 ++++------- .../event-handler-no-passive/expected.js | 14 +--- test/js/samples/event-modifiers/expected.js | 21 +++--- .../js/samples/head-no-whitespace/expected.js | 7 +- test/js/samples/hoisted-const/expected.js | 16 ++-- test/js/samples/hoisted-let/expected.js | 16 ++-- test/js/samples/if-block-complex/expected.js | 29 ++----- .../js/samples/if-block-no-update/expected.js | 36 +++------ test/js/samples/if-block-simple/expected.js | 28 ++----- .../expected.js | 21 ++---- .../inline-style-optimized-url/expected.js | 13 +--- .../inline-style-optimized/expected.js | 13 +--- .../inline-style-unoptimized/expected.js | 32 ++++---- .../inline-style-without-updates/expected.js | 12 +-- test/js/samples/input-files/expected.js | 16 ++-- .../input-no-initial-value/expected.js | 32 ++++---- test/js/samples/input-range/expected.js | 22 ++---- .../input-without-blowback-guard/expected.js | 22 ++---- .../expected.js | 27 +++---- .../expected.js | 28 +++---- .../expected.js | 27 +++---- .../expected.js | 31 ++++---- test/js/samples/legacy-input-type/expected.js | 10 +-- .../non-imported-component/expected.js | 23 ++---- .../samples/non-mutable-reference/expected.js | 15 ++-- .../expected.js | 22 +++--- .../expected.js | 6 +- .../expected.js | 10 +-- 39 files changed, 358 insertions(+), 577 deletions(-) diff --git a/src/compiler/compile/render_dom/index.ts b/src/compiler/compile/render_dom/index.ts index f793e41ac32e..0d8a29d63b95 100644 --- a/src/compiler/compile/render_dom/index.ts +++ b/src/compiler/compile/render_dom/index.ts @@ -8,7 +8,7 @@ import add_to_set from '../utils/add_to_set'; import { extract_names } from '../utils/scope'; import { invalidate } from '../utils/invalidate'; import Block from './Block'; -import { ClassDeclaration, FunctionExpression, Node } from 'estree'; +import { ClassDeclaration, FunctionExpression, Node, LabeledStatement, Statement } from 'estree'; export default function dom( component: Component, @@ -332,11 +332,12 @@ export default function dom( }); const condition = !uses_props && writable.length > 0 && (writable - .map(n => x`$$dirty.${n}`) + .map(n => x`#changed.${n}`) .reduce((lhs, rhs) => x`${lhs} || ${rhs}`)); - let statement = d.node; - if (condition) statement = b`if (${condition}) { ${statement} }`[0]; + let statement = d.node; // TODO remove label (use d.node.body) if it's not referenced + + if (condition) statement = b`if (${condition}) { ${statement} }`[0] as Statement; if (condition || uses_props) { reactive_declarations.push(statement); @@ -418,7 +419,7 @@ export default function dom( ${injected.map(name => b`let ${name};`)} ${reactive_declarations.length > 0 && b` - $$self.$$.update = ($$dirty = ${reactive_dependencies}) => { + $$self.$$.update = (#changed = ${reactive_dependencies}) => { ${reactive_declarations} }; `} diff --git a/src/compiler/compile/render_dom/wrappers/Element/Attribute.ts b/src/compiler/compile/render_dom/wrappers/Element/Attribute.ts index ee85dd860b7e..77f0a6d92dd1 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/Attribute.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/Attribute.ts @@ -123,8 +123,8 @@ export default class AttributeWrapper { : b` if (${option}.__value === ${last}) { ${option}.selected = true; - ${'break'}; - }`; // TODO the 'break' is gross, but it's unsyntactic otherwise... + ${{ type: 'BreakStatement' }}; + }`; // TODO the BreakStatement is gross, but it's unsyntactic otherwise... updater = b` for (var ${i} = 0; ${i} < ${element.var}.options.length; ${i} += 1) { diff --git a/src/compiler/compile/render_dom/wrappers/Element/StyleAttribute.ts b/src/compiler/compile/render_dom/wrappers/Element/StyleAttribute.ts index dec62dcb4a15..b4198ed29853 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/StyleAttribute.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/StyleAttribute.ts @@ -40,9 +40,10 @@ export default class StyleAttributeWrapper extends AttributeWrapper { }) .reduce((lhs, rhs) => x`${lhs} + ${rhs}`) - if (prop.value.length === 1 || prop.value[0].type === 'Text') { - value = x`"" + ${value}`; - } + // TODO is this necessary? style.setProperty always treats value as string, no? + // if (prop.value.length === 1 || prop.value[0].type !== 'Text') { + // value = x`"" + ${value}`; + // } if (prop_dependencies.size) { let condition = changed(Array.from(prop_dependencies)); diff --git a/test/js/samples/deconflict-builtins/expected.js b/test/js/samples/deconflict-builtins/expected.js index 6609fcccf7d0..222d47320175 100644 --- a/test/js/samples/deconflict-builtins/expected.js +++ b/test/js/samples/deconflict-builtins/expected.js @@ -1,4 +1,3 @@ -/* generated by Svelte vX.Y.Z */ import { SvelteComponent, append, @@ -20,40 +19,32 @@ function get_each_context(ctx, list, i) { return child_ctx; } -// (5:0) {#each createElement as node} function create_each_block(ctx) { - var span, t_value = ctx.node + "", t; + let span; + let t_value = ctx.node + ""; + let t; return { c() { span = element("span"); t = text(t_value); }, - m(target, anchor) { insert(target, span, anchor); append(span, t); }, - p(changed, ctx) { - if ((changed.createElement) && t_value !== (t_value = ctx.node + "")) { - set_data(t, t_value); - } + if (changed.createElement && t_value !== (t_value = ctx.node + "")) set_data(t, t_value); }, - d(detaching) { - if (detaching) { - detach(span); - } + if (detaching) detach(span); } }; } function create_fragment(ctx) { - var each_1_anchor; - + let each_anchor; let each_value = ctx.createElement; - let each_blocks = []; for (let i = 0; i < each_value.length; i += 1) { @@ -66,22 +57,20 @@ function create_fragment(ctx) { each_blocks[i].c(); } - each_1_anchor = empty(); + each_anchor = empty(); }, - m(target, anchor) { for (let i = 0; i < each_blocks.length; i += 1) { each_blocks[i].m(target, anchor); } - insert(target, each_1_anchor, anchor); + insert(target, each_anchor, anchor); }, - p(changed, ctx) { if (changed.createElement) { each_value = ctx.createElement; - let i; + for (i = 0; i < each_value.length; i += 1) { const child_ctx = get_each_context(ctx, each_value, i); @@ -90,26 +79,22 @@ function create_fragment(ctx) { } else { each_blocks[i] = create_each_block(child_ctx); each_blocks[i].c(); - each_blocks[i].m(each_1_anchor.parentNode, each_1_anchor); + each_blocks[i].m(each_anchor.parentNode, each_anchor); } } for (; i < each_blocks.length; i += 1) { each_blocks[i].d(1); } + each_blocks.length = each_value.length; } }, - i: noop, o: noop, - d(detaching) { destroy_each(each_blocks, detaching); - - if (detaching) { - detach(each_1_anchor); - } + if (detaching) detach(each_anchor); } }; } @@ -118,7 +103,7 @@ function instance($$self, $$props, $$invalidate) { let { createElement } = $$props; $$self.$set = $$props => { - if ('createElement' in $$props) $$invalidate('createElement', createElement = $$props.createElement); + if ("createElement" in $$props) $$invalidate("createElement", createElement = $$props.createElement); }; return { createElement }; diff --git a/test/js/samples/deconflict-globals/expected.js b/test/js/samples/deconflict-globals/expected.js index 347d0417ecd1..360045a5b980 100644 --- a/test/js/samples/deconflict-globals/expected.js +++ b/test/js/samples/deconflict-globals/expected.js @@ -1,10 +1,4 @@ -/* generated by Svelte vX.Y.Z */ -import { - SvelteComponent, - init, - noop, - safe_not_equal -} from "svelte/internal"; +import { SvelteComponent, init, noop, safe_not_equal } from "svelte/internal"; import { onMount } from "svelte"; function create_fragment(ctx) { @@ -19,14 +13,14 @@ function create_fragment(ctx) { } function instance($$self, $$props, $$invalidate) { - let { foo = 'bar' } = $$props; + let { foo = "bar" } = $$props; onMount(() => { alert(JSON.stringify(data())); }); $$self.$set = $$props => { - if ('foo' in $$props) $$invalidate('foo', foo = $$props.foo); + if ("foo" in $$props) $$invalidate("foo", foo = $$props.foo); }; return { foo }; diff --git a/test/js/samples/dev-warning-missing-data-computed/expected.js b/test/js/samples/dev-warning-missing-data-computed/expected.js index ad0cbc8abab8..69f19eb2589b 100644 --- a/test/js/samples/dev-warning-missing-data-computed/expected.js +++ b/test/js/samples/dev-warning-missing-data-computed/expected.js @@ -1,4 +1,3 @@ -/* generated by Svelte vX.Y.Z */ import { SvelteComponentDev, add_location, @@ -18,7 +17,11 @@ import { const file = undefined; function create_fragment(ctx) { - var p, t0_value = Math.max(0, ctx.foo) + "", t0, t1, t2; + let p; + let t0_value = Math.max(0, ctx.foo) + ""; + let t0; + let t1; + let t2; const block = { c: function create() { @@ -28,53 +31,48 @@ function create_fragment(ctx) { t2 = text(ctx.bar); add_location(p, file, 7, 0, 67); }, - l: function claim(nodes) { throw new Error("options.hydrate only works if the component was compiled with the `hydratable: true` option"); }, - m: function mount(target, anchor) { insert_dev(target, p, anchor); append_dev(p, t0); append_dev(p, t1); append_dev(p, t2); }, - p: function update(changed, ctx) { - if ((changed.foo) && t0_value !== (t0_value = Math.max(0, ctx.foo) + "")) { - set_data_dev(t0, t0_value); - } - - if (changed.bar) { - set_data_dev(t2, ctx.bar); - } + if (changed.foo && t0_value !== (t0_value = Math.max(0, ctx.foo) + "")) set_data_dev(t0, t0_value); + if (changed.bar) set_data_dev(t2, ctx.bar); }, - i: noop, o: noop, - d: function destroy(detaching) { - if (detaching) { - detach_dev(p); - } + if (detaching) detach_dev(p); } }; - dispatch_dev("SvelteRegisterBlock", { block, id: create_fragment.name, type: "component", source: "", ctx }); + + dispatch_dev("SvelteRegisterBlock", { + block, + id: create_fragment.name, + type: "component", + source: "", + ctx + }); + return block; } function instance($$self, $$props, $$invalidate) { let { foo } = $$props; - let bar; + const writable_props = ["foo"]; - const writable_props = ['foo']; Object.keys($$props).forEach(key => { - if (!writable_props.includes(key) && !key.startsWith('$$')) console.warn(` was created with unknown prop '${key}'`); + if (!writable_props.includes(key) && !key.startsWith("$$")) console.warn(` was created with unknown prop '${key}'`); }); $$self.$set = $$props => { - if ('foo' in $$props) $$invalidate('foo', foo = $$props.foo); + if ("foo" in $$props) $$invalidate("foo", foo = $$props.foo); }; $$self.$capture_state = () => { @@ -82,12 +80,14 @@ function instance($$self, $$props, $$invalidate) { }; $$self.$inject_state = $$props => { - if ('foo' in $$props) $$invalidate('foo', foo = $$props.foo); - if ('bar' in $$props) $$invalidate('bar', bar = $$props.bar); + if ("foo" in $$props) $$invalidate("foo", foo = $$props.foo); + if ("bar" in $$props) $$invalidate("bar", bar = $$props.bar); }; - $$self.$$.update = ($$dirty = { foo: 1 }) => { - if ($$dirty.foo) { $$invalidate('bar', bar = foo * 2); } + $$self.$$.update = (changed = { foo: 1 }) => { + if (changed.foo) { + $: $$invalidate("bar", bar = foo * 2); + } }; return { foo, bar }; @@ -97,11 +97,18 @@ class Component extends SvelteComponentDev { constructor(options) { super(options); init(this, options, instance, create_fragment, safe_not_equal, ["foo"]); - dispatch_dev("SvelteRegisterComponent", { component: this, tagName: "Component", options, id: create_fragment.name }); + + dispatch_dev("SvelteRegisterComponent", { + component: this, + tagName: "Component", + options, + id: create_fragment.name + }); const { ctx } = this.$$; - const props = options.props || {}; - if (ctx.foo === undefined && !('foo' in props)) { + const props = options.props || ({}); + + if (ctx.foo === undefined && !("foo" in props)) { console.warn(" was created without expected prop 'foo'"); } } diff --git a/test/js/samples/dont-invalidate-this/expected.js b/test/js/samples/dont-invalidate-this/expected.js index 92033148eb64..0cdc5bb903c3 100644 --- a/test/js/samples/dont-invalidate-this/expected.js +++ b/test/js/samples/dont-invalidate-this/expected.js @@ -1,4 +1,3 @@ -/* generated by Svelte vX.Y.Z */ import { SvelteComponent, detach, @@ -11,27 +10,22 @@ import { } from "svelte/internal"; function create_fragment(ctx) { - var input, dispose; + let input; + let dispose; return { c() { input = element("input"); dispose = listen(input, "input", make_uppercase); }, - m(target, anchor) { insert(target, input, anchor); }, - p: noop, i: noop, o: noop, - d(detaching) { - if (detaching) { - detach(input); - } - + if (detaching) detach(input); dispose(); } }; diff --git a/test/js/samples/dynamic-import/expected.js b/test/js/samples/dynamic-import/expected.js index 8692cd89b26f..948cf183e1d6 100644 --- a/test/js/samples/dynamic-import/expected.js +++ b/test/js/samples/dynamic-import/expected.js @@ -1,4 +1,3 @@ -/* generated by Svelte vX.Y.Z */ import { SvelteComponent, destroy_component, @@ -12,34 +11,27 @@ import { import LazyLoad from "./LazyLoad.svelte"; function create_fragment(ctx) { - var current; - - var lazyload = new LazyLoad({ props: { load: func } }); + let current; + const lazyload = new LazyLoad({ props: { load: func } }); return { c() { lazyload.$$.fragment.c(); }, - m(target, anchor) { mount_component(lazyload, target, anchor); current = true; }, - p: noop, - i(local) { if (current) return; transition_in(lazyload.$$.fragment, local); - current = true; }, - o(local) { transition_out(lazyload.$$.fragment, local); current = false; }, - d(detaching) { destroy_component(lazyload, detaching); } diff --git a/test/js/samples/each-block-array-literal/expected.js b/test/js/samples/each-block-array-literal/expected.js index 6ca6773f6bf4..2eb1d903dead 100644 --- a/test/js/samples/each-block-array-literal/expected.js +++ b/test/js/samples/each-block-array-literal/expected.js @@ -1,4 +1,3 @@ -/* generated by Svelte vX.Y.Z */ import { SvelteComponent, append, @@ -20,40 +19,32 @@ function get_each_context(ctx, list, i) { return child_ctx; } -// (9:0) {#each [a, b, c, d, e] as num} function create_each_block(ctx) { - var span, t_value = ctx.num + "", t; + let span; + let t_value = ctx.num + ""; + let t; return { c() { span = element("span"); t = text(t_value); }, - m(target, anchor) { insert(target, span, anchor); append(span, t); }, - p(changed, ctx) { - if ((changed.a || changed.b || changed.c || changed.d || changed.e) && t_value !== (t_value = ctx.num + "")) { - set_data(t, t_value); - } + if ((changed.a || changed.b || changed.c || changed.d || changed.e) && t_value !== (t_value = ctx.num + "")) set_data(t, t_value); }, - d(detaching) { - if (detaching) { - detach(span); - } + if (detaching) detach(span); } }; } function create_fragment(ctx) { - var each_1_anchor; - + let each_anchor; let each_value = [ctx.a, ctx.b, ctx.c, ctx.d, ctx.e]; - let each_blocks = []; for (let i = 0; i < 5; i += 1) { @@ -66,23 +57,21 @@ function create_fragment(ctx) { each_blocks[i].c(); } - each_1_anchor = empty(); + each_anchor = empty(); }, - m(target, anchor) { for (let i = 0; i < 5; i += 1) { each_blocks[i].m(target, anchor); } - insert(target, each_1_anchor, anchor); + insert(target, each_anchor, anchor); }, - p(changed, ctx) { if (changed.a || changed.b || changed.c || changed.d || changed.e) { each_value = [ctx.a, ctx.b, ctx.c, ctx.d, ctx.e]; - let i; - for (i = 0; i < each_value.length; i += 1) { + + for (i = 0; i < 5; i += 1) { const child_ctx = get_each_context(ctx, each_value, i); if (each_blocks[i]) { @@ -90,7 +79,7 @@ function create_fragment(ctx) { } else { each_blocks[i] = create_each_block(child_ctx); each_blocks[i].c(); - each_blocks[i].m(each_1_anchor.parentNode, each_1_anchor); + each_blocks[i].m(each_anchor.parentNode, each_anchor); } } @@ -99,29 +88,28 @@ function create_fragment(ctx) { } } }, - i: noop, o: noop, - d(detaching) { destroy_each(each_blocks, detaching); - - if (detaching) { - detach(each_1_anchor); - } + if (detaching) detach(each_anchor); } }; } function instance($$self, $$props, $$invalidate) { - let { a, b, c, d, e } = $$props; + let { a } = $$props; + let { b } = $$props; + let { c } = $$props; + let { d } = $$props; + let { e } = $$props; $$self.$set = $$props => { - if ('a' in $$props) $$invalidate('a', a = $$props.a); - if ('b' in $$props) $$invalidate('b', b = $$props.b); - if ('c' in $$props) $$invalidate('c', c = $$props.c); - if ('d' in $$props) $$invalidate('d', d = $$props.d); - if ('e' in $$props) $$invalidate('e', e = $$props.e); + if ("a" in $$props) $$invalidate("a", a = $$props.a); + if ("b" in $$props) $$invalidate("b", b = $$props.b); + if ("c" in $$props) $$invalidate("c", c = $$props.c); + if ("d" in $$props) $$invalidate("d", d = $$props.d); + if ("e" in $$props) $$invalidate("e", e = $$props.e); }; return { a, b, c, d, e }; diff --git a/test/js/samples/each-block-changed-check/expected.js b/test/js/samples/each-block-changed-check/expected.js index 0601c3133448..7e528d1c6bdc 100644 --- a/test/js/samples/each-block-changed-check/expected.js +++ b/test/js/samples/each-block-changed-check/expected.js @@ -1,4 +1,3 @@ -/* generated by Svelte vX.Y.Z */ import { HtmlTag, SvelteComponent, @@ -23,9 +22,21 @@ function get_each_context(ctx, list, i) { return child_ctx; } -// (8:0) {#each comments as comment, i} function create_each_block(ctx) { - var div, strong, t0, t1, span, t2_value = ctx.comment.author + "", t2, t3, t4_value = ctx.elapsed(ctx.comment.time, ctx.time) + "", t4, t5, t6, html_tag, raw_value = ctx.comment.html + ""; + let div; + let strong; + let t0; + let t1; + let span; + let t2_value = ctx.comment.author + ""; + let t2; + let t3; + let t4_value = ctx.elapsed(ctx.comment.time, ctx.time) + ""; + let t4; + let t5; + let t6; + let html_tag; + let raw_value = ctx.comment.html + ""; return { c() { @@ -43,7 +54,6 @@ function create_each_block(ctx) { html_tag = new HtmlTag(raw_value, null); attr(div, "class", "comment"); }, - m(target, anchor) { insert(target, div, anchor); append(div, strong); @@ -57,34 +67,22 @@ function create_each_block(ctx) { append(div, t6); html_tag.m(div); }, - p(changed, ctx) { - if ((changed.comments) && t2_value !== (t2_value = ctx.comment.author + "")) { - set_data(t2, t2_value); - } - - if ((changed.elapsed || changed.comments || changed.time) && t4_value !== (t4_value = ctx.elapsed(ctx.comment.time, ctx.time) + "")) { - set_data(t4, t4_value); - } - - if ((changed.comments) && raw_value !== (raw_value = ctx.comment.html + "")) { - html_tag.p(raw_value); - } + if (changed.comments && t2_value !== (t2_value = ctx.comment.author + "")) set_data(t2, t2_value); + if ((changed.elapsed || changed.comments || changed.time) && t4_value !== (t4_value = ctx.elapsed(ctx.comment.time, ctx.time) + "")) set_data(t4, t4_value); + if (changed.comments && raw_value !== (raw_value = ctx.comment.html + "")) html_tag.p(raw_value); }, - d(detaching) { - if (detaching) { - detach(div); - } + if (detaching) detach(div); } }; } function create_fragment(ctx) { - var t0, p, t1; - + let t0; + let p; + let t1; let each_value = ctx.comments; - let each_blocks = []; for (let i = 0; i < each_value.length; i += 1) { @@ -101,7 +99,6 @@ function create_fragment(ctx) { p = element("p"); t1 = text(ctx.foo); }, - m(target, anchor) { for (let i = 0; i < each_blocks.length; i += 1) { each_blocks[i].m(target, anchor); @@ -111,12 +108,11 @@ function create_fragment(ctx) { insert(target, p, anchor); append(p, t1); }, - p(changed, ctx) { if (changed.comments || changed.elapsed || changed.time) { each_value = ctx.comments; - let i; + for (i = 0; i < each_value.length; i += 1) { const child_ctx = get_each_context(ctx, each_value, i); @@ -132,36 +128,33 @@ function create_fragment(ctx) { for (; i < each_blocks.length; i += 1) { each_blocks[i].d(1); } + each_blocks.length = each_value.length; } - if (changed.foo) { - set_data(t1, ctx.foo); - } + if (changed.foo) set_data(t1, ctx.foo); }, - i: noop, o: noop, - d(detaching) { destroy_each(each_blocks, detaching); - - if (detaching) { - detach(t0); - detach(p); - } + if (detaching) detach(t0); + if (detaching) detach(p); } }; } function instance($$self, $$props, $$invalidate) { - let { comments, elapsed, time, foo } = $$props; + let { comments } = $$props; + let { elapsed } = $$props; + let { time } = $$props; + let { foo } = $$props; $$self.$set = $$props => { - if ('comments' in $$props) $$invalidate('comments', comments = $$props.comments); - if ('elapsed' in $$props) $$invalidate('elapsed', elapsed = $$props.elapsed); - if ('time' in $$props) $$invalidate('time', time = $$props.time); - if ('foo' in $$props) $$invalidate('foo', foo = $$props.foo); + if ("comments" in $$props) $$invalidate("comments", comments = $$props.comments); + if ("elapsed" in $$props) $$invalidate("elapsed", elapsed = $$props.elapsed); + if ("time" in $$props) $$invalidate("time", time = $$props.time); + if ("foo" in $$props) $$invalidate("foo", foo = $$props.foo); }; return { comments, elapsed, time, foo }; diff --git a/test/js/samples/each-block-keyed-animated/expected.js b/test/js/samples/each-block-keyed-animated/expected.js index 25aa1e5c5df6..e2e835780590 100644 --- a/test/js/samples/each-block-keyed-animated/expected.js +++ b/test/js/samples/each-block-keyed-animated/expected.js @@ -1,4 +1,3 @@ -/* generated by Svelte vX.Y.Z */ import { SvelteComponent, append, @@ -23,65 +22,56 @@ function get_each_context(ctx, list, i) { return child_ctx; } -// (19:0) {#each things as thing (thing.id)} function create_each_block(key_1, ctx) { - var div, t_value = ctx.thing.name + "", t, rect, stop_animation = noop; + let div; + let t_value = ctx.thing.name + ""; + let t; + let rect; + let stop_animation = noop; return { key: key_1, - first: null, - c() { div = element("div"); t = text(t_value); this.first = div; }, - m(target, anchor) { insert(target, div, anchor); append(div, t); }, - p(changed, ctx) { - if ((changed.things) && t_value !== (t_value = ctx.thing.name + "")) { - set_data(t, t_value); - } + if (changed.things && t_value !== (t_value = ctx.thing.name + "")) set_data(t, t_value); }, - r() { rect = div.getBoundingClientRect(); }, - f() { fix_position(div); stop_animation(); }, - a() { stop_animation(); stop_animation = create_animation(div, rect, foo, {}); }, - d(detaching) { - if (detaching) { - detach(div); - } + if (detaching) detach(div); } }; } function create_fragment(ctx) { - var each_blocks = [], each_1_lookup = new Map(), each_1_anchor; - + let each_blocks = []; + let each_lookup = new Map(); + let each_anchor; let each_value = ctx.things; - const get_key = ctx => ctx.thing.id; for (let i = 0; i < each_value.length; i += 1) { let child_ctx = get_each_context(ctx, each_value, i); let key = get_key(child_ctx); - each_1_lookup.set(key, each_blocks[i] = create_each_block(key, child_ctx)); + each_lookup.set(key, each_blocks[i] = create_each_block(key, child_ctx)); } return { @@ -90,35 +80,29 @@ function create_fragment(ctx) { each_blocks[i].c(); } - each_1_anchor = empty(); + each_anchor = empty(); }, - m(target, anchor) { for (let i = 0; i < each_blocks.length; i += 1) { each_blocks[i].m(target, anchor); } - insert(target, each_1_anchor, anchor); + insert(target, each_anchor, anchor); }, - p(changed, ctx) { const each_value = ctx.things; for (let i = 0; i < each_blocks.length; i += 1) each_blocks[i].r(); - each_blocks = update_keyed_each(each_blocks, changed, get_key, 1, ctx, each_value, each_1_lookup, each_1_anchor.parentNode, fix_and_destroy_block, create_each_block, each_1_anchor, get_each_context); + each_blocks = update_keyed_each(each_blocks, changed, get_key, 1, ctx, each_value, each_lookup, each_anchor.parentNode, fix_and_destroy_block, create_each_block, each_anchor, get_each_context); for (let i = 0; i < each_blocks.length; i += 1) each_blocks[i].a(); }, - i: noop, o: noop, - d(detaching) { for (let i = 0; i < each_blocks.length; i += 1) { each_blocks[i].d(detaching); } - if (detaching) { - detach(each_1_anchor); - } + if (detaching) detach(each_anchor); } }; } @@ -141,7 +125,7 @@ function instance($$self, $$props, $$invalidate) { let { things } = $$props; $$self.$set = $$props => { - if ('things' in $$props) $$invalidate('things', things = $$props.things); + if ("things" in $$props) $$invalidate("things", things = $$props.things); }; return { things }; diff --git a/test/js/samples/each-block-keyed/expected.js b/test/js/samples/each-block-keyed/expected.js index ae20825344b2..5e149826b811 100644 --- a/test/js/samples/each-block-keyed/expected.js +++ b/test/js/samples/each-block-keyed/expected.js @@ -1,4 +1,3 @@ -/* generated by Svelte vX.Y.Z */ import { SvelteComponent, append, @@ -21,51 +20,43 @@ function get_each_context(ctx, list, i) { return child_ctx; } -// (5:0) {#each things as thing (thing.id)} function create_each_block(key_1, ctx) { - var div, t_value = ctx.thing.name + "", t; + let div; + let t_value = ctx.thing.name + ""; + let t; return { key: key_1, - first: null, - c() { div = element("div"); t = text(t_value); this.first = div; }, - m(target, anchor) { insert(target, div, anchor); append(div, t); }, - p(changed, ctx) { - if ((changed.things) && t_value !== (t_value = ctx.thing.name + "")) { - set_data(t, t_value); - } + if (changed.things && t_value !== (t_value = ctx.thing.name + "")) set_data(t, t_value); }, - d(detaching) { - if (detaching) { - detach(div); - } + if (detaching) detach(div); } }; } function create_fragment(ctx) { - var each_blocks = [], each_1_lookup = new Map(), each_1_anchor; - + let each_blocks = []; + let each_lookup = new Map(); + let each_anchor; let each_value = ctx.things; - const get_key = ctx => ctx.thing.id; for (let i = 0; i < each_value.length; i += 1) { let child_ctx = get_each_context(ctx, each_value, i); let key = get_key(child_ctx); - each_1_lookup.set(key, each_blocks[i] = create_each_block(key, child_ctx)); + each_lookup.set(key, each_blocks[i] = create_each_block(key, child_ctx)); } return { @@ -74,33 +65,27 @@ function create_fragment(ctx) { each_blocks[i].c(); } - each_1_anchor = empty(); + each_anchor = empty(); }, - m(target, anchor) { for (let i = 0; i < each_blocks.length; i += 1) { each_blocks[i].m(target, anchor); } - insert(target, each_1_anchor, anchor); + insert(target, each_anchor, anchor); }, - p(changed, ctx) { const each_value = ctx.things; - each_blocks = update_keyed_each(each_blocks, changed, get_key, 1, ctx, each_value, each_1_lookup, each_1_anchor.parentNode, destroy_block, create_each_block, each_1_anchor, get_each_context); + each_blocks = update_keyed_each(each_blocks, changed, get_key, 1, ctx, each_value, each_lookup, each_anchor.parentNode, destroy_block, create_each_block, each_anchor, get_each_context); }, - i: noop, o: noop, - d(detaching) { for (let i = 0; i < each_blocks.length; i += 1) { each_blocks[i].d(detaching); } - if (detaching) { - detach(each_1_anchor); - } + if (detaching) detach(each_anchor); } }; } @@ -109,7 +94,7 @@ function instance($$self, $$props, $$invalidate) { let { things } = $$props; $$self.$set = $$props => { - if ('things' in $$props) $$invalidate('things', things = $$props.things); + if ("things" in $$props) $$invalidate("things", things = $$props.things); }; return { things }; diff --git a/test/js/samples/event-handler-no-passive/expected.js b/test/js/samples/event-handler-no-passive/expected.js index 69285a29c6c4..305b4153b17f 100644 --- a/test/js/samples/event-handler-no-passive/expected.js +++ b/test/js/samples/event-handler-no-passive/expected.js @@ -1,4 +1,3 @@ -/* generated by Svelte vX.Y.Z */ import { SvelteComponent, attr, @@ -12,7 +11,8 @@ import { } from "svelte/internal"; function create_fragment(ctx) { - var a, dispose; + let a; + let dispose; return { c() { @@ -21,26 +21,20 @@ function create_fragment(ctx) { attr(a, "href", "https://example.com"); dispose = listen(a, "touchstart", touchstart_handler); }, - m(target, anchor) { insert(target, a, anchor); }, - p: noop, i: noop, o: noop, - d(detaching) { - if (detaching) { - detach(a); - } - + if (detaching) detach(a); dispose(); } }; } -const touchstart_handler = (e) => e.preventDefault(); +const touchstart_handler = e => e.preventDefault(); class Component extends SvelteComponent { constructor(options) { diff --git a/test/js/samples/event-modifiers/expected.js b/test/js/samples/event-modifiers/expected.js index bd449ea5a402..55ed17dace0e 100644 --- a/test/js/samples/event-modifiers/expected.js +++ b/test/js/samples/event-modifiers/expected.js @@ -1,4 +1,3 @@ -/* generated by Svelte vX.Y.Z */ import { SvelteComponent, append, @@ -16,7 +15,13 @@ import { } from "svelte/internal"; function create_fragment(ctx) { - var div, button0, t1, button1, t3, button2, dispose; + let div; + let button0; + let t1; + let button1; + let t3; + let button2; + let dispose; return { c() { @@ -36,7 +41,6 @@ function create_fragment(ctx) { listen(div, "touchstart", handleTouchstart, { passive: true }) ]; }, - m(target, anchor) { insert(target, div, anchor); append(div, button0); @@ -45,27 +49,22 @@ function create_fragment(ctx) { append(div, t3); append(div, button2); }, - p: noop, i: noop, o: noop, - d(detaching) { - if (detaching) { - detach(div); - } - + if (detaching) detach(div); run_all(dispose); } }; } function handleTouchstart() { - // ... + } function handleClick() { - // ... + } class Component extends SvelteComponent { diff --git a/test/js/samples/head-no-whitespace/expected.js b/test/js/samples/head-no-whitespace/expected.js index 457df77dc861..34545ab65685 100644 --- a/test/js/samples/head-no-whitespace/expected.js +++ b/test/js/samples/head-no-whitespace/expected.js @@ -1,4 +1,3 @@ -/* generated by Svelte vX.Y.Z */ import { SvelteComponent, append, @@ -11,7 +10,8 @@ import { } from "svelte/internal"; function create_fragment(ctx) { - var meta0, meta1; + let meta0; + let meta1; return { c() { @@ -22,16 +22,13 @@ function create_fragment(ctx) { attr(meta1, "name", "twitter:title"); attr(meta1, "content", "Svelte"); }, - m(target, anchor) { append(document.head, meta0); append(document.head, meta1); }, - p: noop, i: noop, o: noop, - d(detaching) { detach(meta0); detach(meta1); diff --git a/test/js/samples/hoisted-const/expected.js b/test/js/samples/hoisted-const/expected.js index ccd0b3c4803f..af4d360d35db 100644 --- a/test/js/samples/hoisted-const/expected.js +++ b/test/js/samples/hoisted-const/expected.js @@ -1,4 +1,3 @@ -/* generated by Svelte vX.Y.Z */ import { SvelteComponent, append, @@ -12,34 +11,33 @@ import { } from "svelte/internal"; function create_fragment(ctx) { - var b, t_value = get_answer() + "", t; + let b; + let t_value = get_answer() + ""; + let t; return { c() { b = element("b"); t = text(t_value); }, - m(target, anchor) { insert(target, b, anchor); append(b, t); }, - p: noop, i: noop, o: noop, - d(detaching) { - if (detaching) { - detach(b); - } + if (detaching) detach(b); } }; } const ANSWER = 42; -function get_answer() { return ANSWER; } +function get_answer() { + return ANSWER; +} class Component extends SvelteComponent { constructor(options) { diff --git a/test/js/samples/hoisted-let/expected.js b/test/js/samples/hoisted-let/expected.js index e2a9186dbdb2..5392a5018c12 100644 --- a/test/js/samples/hoisted-let/expected.js +++ b/test/js/samples/hoisted-let/expected.js @@ -1,4 +1,3 @@ -/* generated by Svelte vX.Y.Z */ import { SvelteComponent, append, @@ -12,34 +11,33 @@ import { } from "svelte/internal"; function create_fragment(ctx) { - var b, t_value = get_answer() + "", t; + let b; + let t_value = get_answer() + ""; + let t; return { c() { b = element("b"); t = text(t_value); }, - m(target, anchor) { insert(target, b, anchor); append(b, t); }, - p: noop, i: noop, o: noop, - d(detaching) { - if (detaching) { - detach(b); - } + if (detaching) detach(b); } }; } let ANSWER = 42; -function get_answer() { return ANSWER; } +function get_answer() { + return ANSWER; +} class Component extends SvelteComponent { constructor(options) { diff --git a/test/js/samples/if-block-complex/expected.js b/test/js/samples/if-block-complex/expected.js index 67d537f343da..fd882d75617e 100644 --- a/test/js/samples/if-block-complex/expected.js +++ b/test/js/samples/if-block-complex/expected.js @@ -1,4 +1,3 @@ -/* generated by Svelte vX.Y.Z */ import { SvelteComponent, attr, @@ -11,63 +10,49 @@ import { safe_not_equal } from "svelte/internal"; -// (7:0) {#if (item.divider && item.divider.includes(1))} function create_if_block(ctx) { - var div; + let div; return { c() { div = element("div"); attr(div, "class", "divider"); }, - m(target, anchor) { insert(target, div, anchor); }, - d(detaching) { - if (detaching) { - detach(div); - } + if (detaching) detach(div); } }; } function create_fragment(ctx) { - var show_if = (ctx.item.divider && ctx.item.divider.includes(1)), if_block_anchor; - - var if_block = (show_if) && create_if_block(ctx); + let show_if = ctx.item.divider && ctx.item.divider.includes(1); + let if_block_anchor; + let if_block = show_if && create_if_block(ctx); return { c() { if (if_block) if_block.c(); if_block_anchor = empty(); }, - m(target, anchor) { if (if_block) if_block.m(target, anchor); insert(target, if_block_anchor, anchor); }, - p: noop, i: noop, o: noop, - d(detaching) { if (if_block) if_block.d(detaching); - - if (detaching) { - detach(if_block_anchor); - } + if (detaching) detach(if_block_anchor); } }; } function instance($$self) { - let item = { - divider: [1] - } - + let item = { divider: [1] }; return { item }; } diff --git a/test/js/samples/if-block-no-update/expected.js b/test/js/samples/if-block-no-update/expected.js index 5cb29e859367..3ce3c4db79e9 100644 --- a/test/js/samples/if-block-no-update/expected.js +++ b/test/js/samples/if-block-no-update/expected.js @@ -1,4 +1,3 @@ -/* generated by Svelte vX.Y.Z */ import { SvelteComponent, detach, @@ -10,72 +9,60 @@ import { safe_not_equal } from "svelte/internal"; -// (7:0) {:else} function create_else_block(ctx) { - var p; + let p; return { c() { p = element("p"); p.textContent = "not foo!"; }, - m(target, anchor) { insert(target, p, anchor); }, - d(detaching) { - if (detaching) { - detach(p); - } + if (detaching) detach(p); } }; } -// (5:0) {#if foo} function create_if_block(ctx) { - var p; + let p; return { c() { p = element("p"); p.textContent = "foo!"; }, - m(target, anchor) { insert(target, p, anchor); }, - d(detaching) { - if (detaching) { - detach(p); - } + if (detaching) detach(p); } }; } function create_fragment(ctx) { - var if_block_anchor; + let if_block_anchor; function select_block_type(changed, ctx) { if (ctx.foo) return create_if_block; return create_else_block; } - var current_block_type = select_block_type(null, ctx); - var if_block = current_block_type(ctx); + let current_block_type = select_block_type(null, ctx); + let if_block = current_block_type(ctx); return { c() { if_block.c(); if_block_anchor = empty(); }, - m(target, anchor) { if_block.m(target, anchor); insert(target, if_block_anchor, anchor); }, - p(changed, ctx) { if (current_block_type !== (current_block_type = select_block_type(changed, ctx))) { if_block.d(1); @@ -86,16 +73,11 @@ function create_fragment(ctx) { } } }, - i: noop, o: noop, - d(detaching) { if_block.d(detaching); - - if (detaching) { - detach(if_block_anchor); - } + if (detaching) detach(if_block_anchor); } }; } @@ -104,7 +86,7 @@ function instance($$self, $$props, $$invalidate) { let { foo } = $$props; $$self.$set = $$props => { - if ('foo' in $$props) $$invalidate('foo', foo = $$props.foo); + if ("foo" in $$props) $$invalidate("foo", foo = $$props.foo); }; return { foo }; diff --git a/test/js/samples/if-block-simple/expected.js b/test/js/samples/if-block-simple/expected.js index 94b0f37f31e1..8f4cd20e2857 100644 --- a/test/js/samples/if-block-simple/expected.js +++ b/test/js/samples/if-block-simple/expected.js @@ -1,4 +1,3 @@ -/* generated by Svelte vX.Y.Z */ import { SvelteComponent, detach, @@ -10,66 +9,55 @@ import { safe_not_equal } from "svelte/internal"; -// (5:0) {#if foo} function create_if_block(ctx) { - var p; + let p; return { c() { p = element("p"); p.textContent = "foo!"; }, - m(target, anchor) { insert(target, p, anchor); }, - d(detaching) { - if (detaching) { - detach(p); - } + if (detaching) detach(p); } }; } function create_fragment(ctx) { - var if_block_anchor; - - var if_block = (ctx.foo) && create_if_block(ctx); + let if_block_anchor; + let if_block = ctx.foo && create_if_block(ctx); return { c() { if (if_block) if_block.c(); if_block_anchor = empty(); }, - m(target, anchor) { if (if_block) if_block.m(target, anchor); insert(target, if_block_anchor, anchor); }, - p(changed, ctx) { if (ctx.foo) { if (!if_block) { if_block = create_if_block(ctx); if_block.c(); if_block.m(if_block_anchor.parentNode, if_block_anchor); + } else { + } } else if (if_block) { if_block.d(1); if_block = null; } }, - i: noop, o: noop, - d(detaching) { if (if_block) if_block.d(detaching); - - if (detaching) { - detach(if_block_anchor); - } + if (detaching) detach(if_block_anchor); } }; } @@ -78,7 +66,7 @@ function instance($$self, $$props, $$invalidate) { let { foo } = $$props; $$self.$set = $$props => { - if ('foo' in $$props) $$invalidate('foo', foo = $$props.foo); + if ("foo" in $$props) $$invalidate("foo", foo = $$props.foo); }; return { foo }; diff --git a/test/js/samples/inline-style-optimized-multiple/expected.js b/test/js/samples/inline-style-optimized-multiple/expected.js index ea1d90e83137..1296548b999d 100644 --- a/test/js/samples/inline-style-optimized-multiple/expected.js +++ b/test/js/samples/inline-style-optimized-multiple/expected.js @@ -1,4 +1,3 @@ -/* generated by Svelte vX.Y.Z */ import { SvelteComponent, detach, @@ -11,7 +10,7 @@ import { } from "svelte/internal"; function create_fragment(ctx) { - var div; + let div; return { c() { @@ -19,11 +18,9 @@ function create_fragment(ctx) { set_style(div, "color", ctx.color); set_style(div, "transform", "translate(" + ctx.x + "px," + ctx.y + "px)"); }, - m(target, anchor) { insert(target, div, anchor); }, - p(changed, ctx) { if (changed.color) { set_style(div, "color", ctx.color); @@ -33,25 +30,23 @@ function create_fragment(ctx) { set_style(div, "transform", "translate(" + ctx.x + "px," + ctx.y + "px)"); } }, - i: noop, o: noop, - d(detaching) { - if (detaching) { - detach(div); - } + if (detaching) detach(div); } }; } function instance($$self, $$props, $$invalidate) { - let { color, x, y } = $$props; + let { color } = $$props; + let { x } = $$props; + let { y } = $$props; $$self.$set = $$props => { - if ('color' in $$props) $$invalidate('color', color = $$props.color); - if ('x' in $$props) $$invalidate('x', x = $$props.x); - if ('y' in $$props) $$invalidate('y', y = $$props.y); + if ("color" in $$props) $$invalidate("color", color = $$props.color); + if ("x" in $$props) $$invalidate("x", x = $$props.x); + if ("y" in $$props) $$invalidate("y", y = $$props.y); }; return { color, x, y }; diff --git a/test/js/samples/inline-style-optimized-url/expected.js b/test/js/samples/inline-style-optimized-url/expected.js index 8dfc48447d9e..c094fb73d618 100644 --- a/test/js/samples/inline-style-optimized-url/expected.js +++ b/test/js/samples/inline-style-optimized-url/expected.js @@ -1,4 +1,3 @@ -/* generated by Svelte vX.Y.Z */ import { SvelteComponent, detach, @@ -11,31 +10,25 @@ import { } from "svelte/internal"; function create_fragment(ctx) { - var div; + let div; return { c() { div = element("div"); set_style(div, "background", "url(data:image/png;base64," + ctx.data + ")"); }, - m(target, anchor) { insert(target, div, anchor); }, - p(changed, ctx) { if (changed.data) { set_style(div, "background", "url(data:image/png;base64," + ctx.data + ")"); } }, - i: noop, o: noop, - d(detaching) { - if (detaching) { - detach(div); - } + if (detaching) detach(div); } }; } @@ -44,7 +37,7 @@ function instance($$self, $$props, $$invalidate) { let { data } = $$props; $$self.$set = $$props => { - if ('data' in $$props) $$invalidate('data', data = $$props.data); + if ("data" in $$props) $$invalidate("data", data = $$props.data); }; return { data }; diff --git a/test/js/samples/inline-style-optimized/expected.js b/test/js/samples/inline-style-optimized/expected.js index 1170c254581c..d77f465dea49 100644 --- a/test/js/samples/inline-style-optimized/expected.js +++ b/test/js/samples/inline-style-optimized/expected.js @@ -1,4 +1,3 @@ -/* generated by Svelte vX.Y.Z */ import { SvelteComponent, detach, @@ -11,31 +10,25 @@ import { } from "svelte/internal"; function create_fragment(ctx) { - var div; + let div; return { c() { div = element("div"); set_style(div, "color", ctx.color); }, - m(target, anchor) { insert(target, div, anchor); }, - p(changed, ctx) { if (changed.color) { set_style(div, "color", ctx.color); } }, - i: noop, o: noop, - d(detaching) { - if (detaching) { - detach(div); - } + if (detaching) detach(div); } }; } @@ -44,7 +37,7 @@ function instance($$self, $$props, $$invalidate) { let { color } = $$props; $$self.$set = $$props => { - if ('color' in $$props) $$invalidate('color', color = $$props.color); + if ("color" in $$props) $$invalidate("color", color = $$props.color); }; return { color }; diff --git a/test/js/samples/inline-style-unoptimized/expected.js b/test/js/samples/inline-style-unoptimized/expected.js index 9349ade12caa..d1a36c12ca7b 100644 --- a/test/js/samples/inline-style-unoptimized/expected.js +++ b/test/js/samples/inline-style-unoptimized/expected.js @@ -1,4 +1,3 @@ -/* generated by Svelte vX.Y.Z */ import { SvelteComponent, attr, @@ -12,7 +11,10 @@ import { } from "svelte/internal"; function create_fragment(ctx) { - var div0, t, div1, div1_style_value; + let div0; + let t; + let div1; + let div1_style_value; return { c() { @@ -20,45 +22,41 @@ function create_fragment(ctx) { t = space(); div1 = element("div"); attr(div0, "style", ctx.style); - attr(div1, "style", div1_style_value = "" + ctx.key + ": " + ctx.value); + attr(div1, "style", div1_style_value = "" + (ctx.key + ": " + ctx.value)); }, - m(target, anchor) { insert(target, div0, anchor); insert(target, t, anchor); insert(target, div1, anchor); }, - p(changed, ctx) { if (changed.style) { attr(div0, "style", ctx.style); } - if ((changed.key || changed.value) && div1_style_value !== (div1_style_value = "" + ctx.key + ": " + ctx.value)) { + if ((changed.key || changed.value) && div1_style_value !== (div1_style_value = "" + (ctx.key + ": " + ctx.value))) { attr(div1, "style", div1_style_value); } }, - i: noop, o: noop, - d(detaching) { - if (detaching) { - detach(div0); - detach(t); - detach(div1); - } + if (detaching) detach(div0); + if (detaching) detach(t); + if (detaching) detach(div1); } }; } function instance($$self, $$props, $$invalidate) { - let { style, key, value } = $$props; + let { style } = $$props; + let { key } = $$props; + let { value } = $$props; $$self.$set = $$props => { - if ('style' in $$props) $$invalidate('style', style = $$props.style); - if ('key' in $$props) $$invalidate('key', key = $$props.key); - if ('value' in $$props) $$invalidate('value', value = $$props.value); + if ("style" in $$props) $$invalidate("style", style = $$props.style); + if ("key" in $$props) $$invalidate("key", key = $$props.key); + if ("value" in $$props) $$invalidate("value", value = $$props.value); }; return { style, key, value }; diff --git a/test/js/samples/inline-style-without-updates/expected.js b/test/js/samples/inline-style-without-updates/expected.js index 73995c47559e..6e566412362f 100644 --- a/test/js/samples/inline-style-without-updates/expected.js +++ b/test/js/samples/inline-style-without-updates/expected.js @@ -1,4 +1,3 @@ -/* generated by Svelte vX.Y.Z */ import { SvelteComponent, detach, @@ -11,31 +10,26 @@ import { } from "svelte/internal"; function create_fragment(ctx) { - var div; + let div; return { c() { div = element("div"); set_style(div, "color", color); }, - m(target, anchor) { insert(target, div, anchor); }, - p: noop, i: noop, o: noop, - d(detaching) { - if (detaching) { - detach(div); - } + if (detaching) detach(div); } }; } -let color = 'red'; +let color = "red"; class Component extends SvelteComponent { constructor(options) { diff --git a/test/js/samples/input-files/expected.js b/test/js/samples/input-files/expected.js index d4442d57ee17..3584fde535a3 100644 --- a/test/js/samples/input-files/expected.js +++ b/test/js/samples/input-files/expected.js @@ -1,4 +1,3 @@ -/* generated by Svelte vX.Y.Z */ import { SvelteComponent, attr, @@ -12,7 +11,8 @@ import { } from "svelte/internal"; function create_fragment(ctx) { - var input, dispose; + let input; + let dispose; return { c() { @@ -21,20 +21,14 @@ function create_fragment(ctx) { input.multiple = true; dispose = listen(input, "change", ctx.input_change_handler); }, - m(target, anchor) { insert(target, input, anchor); }, - p: noop, i: noop, o: noop, - d(detaching) { - if (detaching) { - detach(input); - } - + if (detaching) detach(input); dispose(); } }; @@ -45,11 +39,11 @@ function instance($$self, $$props, $$invalidate) { function input_change_handler() { files = this.files; - $$invalidate('files', files); + $$invalidate("files", files); } $$self.$set = $$props => { - if ('files' in $$props) $$invalidate('files', files = $$props.files); + if ("files" in $$props) $$invalidate("files", files = $$props.files); }; return { files, input_change_handler }; diff --git a/test/js/samples/input-no-initial-value/expected.js b/test/js/samples/input-no-initial-value/expected.js index a651d72059a9..598bc0177f94 100644 --- a/test/js/samples/input-no-initial-value/expected.js +++ b/test/js/samples/input-no-initial-value/expected.js @@ -1,4 +1,3 @@ -/* generated by Svelte vX.Y.Z */ import { SvelteComponent, append, @@ -16,7 +15,11 @@ import { } from "svelte/internal"; function create_fragment(ctx) { - var form, input, t, button, dispose; + let form; + let input; + let t; + let button; + let dispose; return { c() { @@ -33,29 +36,22 @@ function create_fragment(ctx) { listen(form, "submit", ctx.handleSubmit) ]; }, - m(target, anchor) { insert(target, form, anchor); append(form, input); - set_input_value(input, ctx.test); - append(form, t); append(form, button); }, - p(changed, ctx) { - if (changed.test && (input.value !== ctx.test)) set_input_value(input, ctx.test); + if (changed.test && input.value !== ctx.test) { + set_input_value(input, ctx.test); + } }, - i: noop, o: noop, - d(detaching) { - if (detaching) { - detach(form); - } - + if (detaching) detach(form); run_all(dispose); } }; @@ -66,15 +62,19 @@ function instance($$self, $$props, $$invalidate) { function handleSubmit(event) { event.preventDefault(); - console.log('value', test); + console.log("value", test); } function input_input_handler() { test = this.value; - $$invalidate('test', test); + $$invalidate("test", test); } - return { test, handleSubmit, input_input_handler }; + return { + test, + handleSubmit, + input_input_handler + }; } class Component extends SvelteComponent { diff --git a/test/js/samples/input-range/expected.js b/test/js/samples/input-range/expected.js index 04552d20cd35..e9b10c75b34d 100644 --- a/test/js/samples/input-range/expected.js +++ b/test/js/samples/input-range/expected.js @@ -1,4 +1,3 @@ -/* generated by Svelte vX.Y.Z */ import { SvelteComponent, attr, @@ -15,7 +14,8 @@ import { } from "svelte/internal"; function create_fragment(ctx) { - var input, dispose; + let input; + let dispose; return { c() { @@ -27,25 +27,19 @@ function create_fragment(ctx) { listen(input, "input", ctx.input_change_input_handler) ]; }, - m(target, anchor) { insert(target, input, anchor); - set_input_value(input, ctx.value); }, - p(changed, ctx) { - if (changed.value) set_input_value(input, ctx.value); + if (changed.value) { + set_input_value(input, ctx.value); + } }, - i: noop, o: noop, - d(detaching) { - if (detaching) { - detach(input); - } - + if (detaching) detach(input); run_all(dispose); } }; @@ -56,11 +50,11 @@ function instance($$self, $$props, $$invalidate) { function input_change_input_handler() { value = to_number(this.value); - $$invalidate('value', value); + $$invalidate("value", value); } $$self.$set = $$props => { - if ('value' in $$props) $$invalidate('value', value = $$props.value); + if ("value" in $$props) $$invalidate("value", value = $$props.value); }; return { value, input_change_input_handler }; diff --git a/test/js/samples/input-without-blowback-guard/expected.js b/test/js/samples/input-without-blowback-guard/expected.js index d97326fcea8b..f4a7399bda23 100644 --- a/test/js/samples/input-without-blowback-guard/expected.js +++ b/test/js/samples/input-without-blowback-guard/expected.js @@ -1,4 +1,3 @@ -/* generated by Svelte vX.Y.Z */ import { SvelteComponent, attr, @@ -12,7 +11,8 @@ import { } from "svelte/internal"; function create_fragment(ctx) { - var input, dispose; + let input; + let dispose; return { c() { @@ -20,25 +20,19 @@ function create_fragment(ctx) { attr(input, "type", "checkbox"); dispose = listen(input, "change", ctx.input_change_handler); }, - m(target, anchor) { insert(target, input, anchor); - input.checked = ctx.foo; }, - p(changed, ctx) { - if (changed.foo) input.checked = ctx.foo; + if (changed.foo) { + input.checked = ctx.foo; + } }, - i: noop, o: noop, - d(detaching) { - if (detaching) { - detach(input); - } - + if (detaching) detach(input); dispose(); } }; @@ -49,11 +43,11 @@ function instance($$self, $$props, $$invalidate) { function input_change_handler() { foo = this.checked; - $$invalidate('foo', foo); + $$invalidate("foo", foo); } $$self.$set = $$props => { - if ('foo' in $$props) $$invalidate('foo', foo = $$props.foo); + if ("foo" in $$props) $$invalidate("foo", foo = $$props.foo); }; return { foo, input_change_handler }; diff --git a/test/js/samples/instrumentation-script-if-no-block/expected.js b/test/js/samples/instrumentation-script-if-no-block/expected.js index ce5948de731b..819263603a73 100644 --- a/test/js/samples/instrumentation-script-if-no-block/expected.js +++ b/test/js/samples/instrumentation-script-if-no-block/expected.js @@ -1,4 +1,3 @@ -/* generated by Svelte vX.Y.Z */ import { SvelteComponent, append, @@ -15,7 +14,12 @@ import { } from "svelte/internal"; function create_fragment(ctx) { - var button, t1, p, t2, t3, dispose; + let button; + let t1; + let p; + let t2; + let t3; + let dispose; return { c() { @@ -27,7 +31,6 @@ function create_fragment(ctx) { t3 = text(ctx.x); dispose = listen(button, "click", ctx.foo); }, - m(target, anchor) { insert(target, button, anchor); insert(target, t1, anchor); @@ -35,23 +38,15 @@ function create_fragment(ctx) { append(p, t2); append(p, t3); }, - p(changed, ctx) { - if (changed.x) { - set_data(t3, ctx.x); - } + if (changed.x) set_data(t3, ctx.x); }, - i: noop, o: noop, - d(detaching) { - if (detaching) { - detach(button); - detach(t1); - detach(p); - } - + if (detaching) detach(button); + if (detaching) detach(t1); + if (detaching) detach(p); dispose(); } }; @@ -61,7 +56,7 @@ function instance($$self, $$props, $$invalidate) { let x = 0; function foo() { - if (true) $$invalidate('x', x += 1); + if (true) $$invalidate("x", x += 1); } return { x, foo }; diff --git a/test/js/samples/instrumentation-script-x-equals-x/expected.js b/test/js/samples/instrumentation-script-x-equals-x/expected.js index 0d7740b55d64..bcae49d2a1c3 100644 --- a/test/js/samples/instrumentation-script-x-equals-x/expected.js +++ b/test/js/samples/instrumentation-script-x-equals-x/expected.js @@ -1,4 +1,3 @@ -/* generated by Svelte vX.Y.Z */ import { SvelteComponent, append, @@ -15,7 +14,13 @@ import { } from "svelte/internal"; function create_fragment(ctx) { - var button, t1, p, t2, t3_value = ctx.things.length + "", t3, dispose; + let button; + let t1; + let p; + let t2; + let t3_value = ctx.things.length + ""; + let t3; + let dispose; return { c() { @@ -27,7 +32,6 @@ function create_fragment(ctx) { t3 = text(t3_value); dispose = listen(button, "click", ctx.foo); }, - m(target, anchor) { insert(target, button, anchor); insert(target, t1, anchor); @@ -35,23 +39,15 @@ function create_fragment(ctx) { append(p, t2); append(p, t3); }, - p(changed, ctx) { - if ((changed.things) && t3_value !== (t3_value = ctx.things.length + "")) { - set_data(t3, t3_value); - } + if (changed.things && t3_value !== (t3_value = ctx.things.length + "")) set_data(t3, t3_value); }, - i: noop, o: noop, - d(detaching) { - if (detaching) { - detach(button); - detach(t1); - detach(p); - } - + if (detaching) detach(button); + if (detaching) detach(t1); + if (detaching) detach(p); dispose(); } }; @@ -62,7 +58,7 @@ function instance($$self, $$props, $$invalidate) { function foo() { things.push(1); - $$invalidate('things', things); + $$invalidate("things", things); } return { things, foo }; diff --git a/test/js/samples/instrumentation-template-if-no-block/expected.js b/test/js/samples/instrumentation-template-if-no-block/expected.js index 4591d8c797d0..a3859b1b1321 100644 --- a/test/js/samples/instrumentation-template-if-no-block/expected.js +++ b/test/js/samples/instrumentation-template-if-no-block/expected.js @@ -1,4 +1,3 @@ -/* generated by Svelte vX.Y.Z */ import { SvelteComponent, append, @@ -15,7 +14,12 @@ import { } from "svelte/internal"; function create_fragment(ctx) { - var button, t1, p, t2, t3, dispose; + let button; + let t1; + let p; + let t2; + let t3; + let dispose; return { c() { @@ -27,7 +31,6 @@ function create_fragment(ctx) { t3 = text(ctx.x); dispose = listen(button, "click", ctx.click_handler); }, - m(target, anchor) { insert(target, button, anchor); insert(target, t1, anchor); @@ -35,23 +38,15 @@ function create_fragment(ctx) { append(p, t2); append(p, t3); }, - p(changed, ctx) { - if (changed.x) { - set_data(t3, ctx.x); - } + if (changed.x) set_data(t3, ctx.x); }, - i: noop, o: noop, - d(detaching) { - if (detaching) { - detach(button); - detach(t1); - detach(p); - } - + if (detaching) detach(button); + if (detaching) detach(t1); + if (detaching) detach(p); dispose(); } }; @@ -61,7 +56,7 @@ function instance($$self, $$props, $$invalidate) { let x = 0; const click_handler = () => { - if (true) $$invalidate('x', x += 1); + if (true) $$invalidate("x", x += 1); }; return { x, click_handler }; diff --git a/test/js/samples/instrumentation-template-x-equals-x/expected.js b/test/js/samples/instrumentation-template-x-equals-x/expected.js index b08130016b89..a1f3149aa1de 100644 --- a/test/js/samples/instrumentation-template-x-equals-x/expected.js +++ b/test/js/samples/instrumentation-template-x-equals-x/expected.js @@ -1,4 +1,3 @@ -/* generated by Svelte vX.Y.Z */ import { SvelteComponent, append, @@ -15,7 +14,13 @@ import { } from "svelte/internal"; function create_fragment(ctx) { - var button, t1, p, t2, t3_value = ctx.things.length + "", t3, dispose; + let button; + let t1; + let p; + let t2; + let t3_value = ctx.things.length + ""; + let t3; + let dispose; return { c() { @@ -27,7 +32,6 @@ function create_fragment(ctx) { t3 = text(t3_value); dispose = listen(button, "click", ctx.click_handler); }, - m(target, anchor) { insert(target, button, anchor); insert(target, t1, anchor); @@ -35,23 +39,15 @@ function create_fragment(ctx) { append(p, t2); append(p, t3); }, - p(changed, ctx) { - if ((changed.things) && t3_value !== (t3_value = ctx.things.length + "")) { - set_data(t3, t3_value); - } + if (changed.things && t3_value !== (t3_value = ctx.things.length + "")) set_data(t3, t3_value); }, - i: noop, o: noop, - d(detaching) { - if (detaching) { - detach(button); - detach(t1); - detach(p); - } - + if (detaching) detach(button); + if (detaching) detach(t1); + if (detaching) detach(p); dispose(); } }; @@ -60,7 +56,10 @@ function create_fragment(ctx) { function instance($$self, $$props, $$invalidate) { let things = []; - const click_handler = () => { things.push(1); $$invalidate('things', things) }; + const click_handler = () => { + things.push(1); + $$invalidate("things", things); + }; return { things, click_handler }; } diff --git a/test/js/samples/legacy-input-type/expected.js b/test/js/samples/legacy-input-type/expected.js index 4c77259a64d7..3cd5243db661 100644 --- a/test/js/samples/legacy-input-type/expected.js +++ b/test/js/samples/legacy-input-type/expected.js @@ -1,4 +1,3 @@ -/* generated by Svelte vX.Y.Z */ import { SvelteComponent, detach, @@ -11,26 +10,21 @@ import { } from "svelte/internal"; function create_fragment(ctx) { - var input; + let input; return { c() { input = element("input"); set_input_type(input, "search"); }, - m(target, anchor) { insert(target, input, anchor); }, - p: noop, i: noop, o: noop, - d(detaching) { - if (detaching) { - detach(input); - } + if (detaching) detach(input); } }; } diff --git a/test/js/samples/non-imported-component/expected.js b/test/js/samples/non-imported-component/expected.js index 42a21aa496ad..7bc92ec560d6 100644 --- a/test/js/samples/non-imported-component/expected.js +++ b/test/js/samples/non-imported-component/expected.js @@ -1,4 +1,3 @@ -/* generated by Svelte vX.Y.Z */ import { SvelteComponent, destroy_component, @@ -15,11 +14,10 @@ import { import Imported from "Imported.svelte"; function create_fragment(ctx) { - var t, current; - - var imported = new Imported({}); - - var nonimported = new NonImported({}); + let t; + let current; + const imported = new Imported({}); + const nonimported = new NonImported({}); return { c() { @@ -27,38 +25,27 @@ function create_fragment(ctx) { t = space(); nonimported.$$.fragment.c(); }, - m(target, anchor) { mount_component(imported, target, anchor); insert(target, t, anchor); mount_component(nonimported, target, anchor); current = true; }, - p: noop, - i(local) { if (current) return; transition_in(imported.$$.fragment, local); - transition_in(nonimported.$$.fragment, local); - current = true; }, - o(local) { transition_out(imported.$$.fragment, local); transition_out(nonimported.$$.fragment, local); current = false; }, - d(detaching) { destroy_component(imported, detaching); - - if (detaching) { - detach(t); - } - + if (detaching) detach(t); destroy_component(nonimported, detaching); } }; diff --git a/test/js/samples/non-mutable-reference/expected.js b/test/js/samples/non-mutable-reference/expected.js index b6d63a387f0d..246850aaf4b4 100644 --- a/test/js/samples/non-mutable-reference/expected.js +++ b/test/js/samples/non-mutable-reference/expected.js @@ -1,4 +1,3 @@ -/* generated by Svelte vX.Y.Z */ import { SvelteComponent, append, @@ -12,7 +11,10 @@ import { } from "svelte/internal"; function create_fragment(ctx) { - var h1, t0, t1, t2; + let h1; + let t0; + let t1; + let t2; return { c() { @@ -21,27 +23,22 @@ function create_fragment(ctx) { t1 = text(name); t2 = text("!"); }, - m(target, anchor) { insert(target, h1, anchor); append(h1, t0); append(h1, t1); append(h1, t2); }, - p: noop, i: noop, o: noop, - d(detaching) { - if (detaching) { - detach(h1); - } + if (detaching) detach(h1); } }; } -let name = 'world'; +let name = "world"; class Component extends SvelteComponent { constructor(options) { diff --git a/test/js/samples/reactive-values-non-topologically-ordered/expected.js b/test/js/samples/reactive-values-non-topologically-ordered/expected.js index b5e2b04f7595..adf0f240192f 100644 --- a/test/js/samples/reactive-values-non-topologically-ordered/expected.js +++ b/test/js/samples/reactive-values-non-topologically-ordered/expected.js @@ -1,10 +1,4 @@ -/* generated by Svelte vX.Y.Z */ -import { - SvelteComponent, - init, - noop, - safe_not_equal -} from "svelte/internal"; +import { SvelteComponent, init, noop, safe_not_equal } from "svelte/internal"; function create_fragment(ctx) { return { @@ -19,17 +13,21 @@ function create_fragment(ctx) { function instance($$self, $$props, $$invalidate) { let { x } = $$props; - let a; let b; $$self.$set = $$props => { - if ('x' in $$props) $$invalidate('x', x = $$props.x); + if ("x" in $$props) $$invalidate("x", x = $$props.x); }; - $$self.$$.update = ($$dirty = { x: 1, b: 1 }) => { - if ($$dirty.x) { $$invalidate('b', b = x); } - if ($$dirty.b) { a = b; } + $$self.$$.update = (changed = { x: 1, b: 1 }) => { + if (changed.x) { + $: $$invalidate("b", b = x); + } + + if (changed.b) { + $: a = b; + } }; return { x }; diff --git a/test/js/samples/reactive-values-non-writable-dependencies/expected.js b/test/js/samples/reactive-values-non-writable-dependencies/expected.js index 6bbfbbfc41d2..f8ec29d70fe3 100644 --- a/test/js/samples/reactive-values-non-writable-dependencies/expected.js +++ b/test/js/samples/reactive-values-non-writable-dependencies/expected.js @@ -20,9 +20,9 @@ function instance($$self, $$props, $$invalidate) { if ("b" in $$props) $$invalidate("b", b = $$props.b); }; - $$self.$$.update = ($$dirty = { a: 1, b: 1 }) => { - if ($$dirty.a || $$dirty.b) { - console.log("max", Math.max(a, b)); + $$self.$$.update = (changed = { a: 1, b: 1 }) => { + if (changed.a || changed.b) { + $: console.log("max", Math.max(a, b)); } }; diff --git a/test/js/samples/unreferenced-state-not-invalidated/expected.js b/test/js/samples/unreferenced-state-not-invalidated/expected.js index a7b25440da37..e2ce31d9f8a5 100644 --- a/test/js/samples/unreferenced-state-not-invalidated/expected.js +++ b/test/js/samples/unreferenced-state-not-invalidated/expected.js @@ -56,13 +56,13 @@ function instance($$self, $$props, $$invalidate) { let x; let y; - $$self.$$.update = ($$dirty = { a: 1, b: 1 }) => { - if ($$dirty.a) { - x = a * 2; + $$self.$$.update = (changed = { a: 1, b: 1 }) => { + if (changed.a) { + $: x = a * 2; } - if ($$dirty.b) { - $$invalidate("y", y = b * 2); + if (changed.b) { + $: $$invalidate("y", y = b * 2); } }; From 85afdef2e533e693a9d184e63f50c63a5870bd99 Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Sun, 13 Oct 2019 15:25:23 -0400 Subject: [PATCH 85/93] dynamic imports, hoisting order --- src/compiler/compile/Component.ts | 6 +++--- test/js/samples/action-custom-event-handler/expected.js | 8 ++++---- test/js/samples/dynamic-import/expected.js | 3 ++- test/js/samples/event-modifiers/expected.js | 1 + 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/compiler/compile/Component.ts b/src/compiler/compile/Component.ts index bab3466c0b69..678f79f3c936 100644 --- a/src/compiler/compile/Component.ts +++ b/src/compiler/compile/Component.ts @@ -947,8 +947,8 @@ export default class Component { const top_level_function_declarations = new Map(); const { body } = this.ast.instance.content; - let i = body.length; - while (i--) { + + for (let i = 0; i < body.length; i += 1) { const node = body[i]; if (node.type === 'VariableDeclaration') { @@ -981,7 +981,7 @@ export default class Component { hoistable_nodes.add(node); - body.splice(i, 1); + body.splice(i--, 1); this.fully_hoisted.push(node); } } diff --git a/test/js/samples/action-custom-event-handler/expected.js b/test/js/samples/action-custom-event-handler/expected.js index ec65b83cd22b..c54ad932023d 100644 --- a/test/js/samples/action-custom-event-handler/expected.js +++ b/test/js/samples/action-custom-event-handler/expected.js @@ -34,14 +34,14 @@ function create_fragment(ctx) { }; } -function foo(node, callback) { - -} - function handleFoo(bar) { console.log(bar); } +function foo(node, callback) { + +} + function instance($$self, $$props, $$invalidate) { let { bar } = $$props; const foo_function = () => handleFoo(bar); diff --git a/test/js/samples/dynamic-import/expected.js b/test/js/samples/dynamic-import/expected.js index 948cf183e1d6..50172bcb4027 100644 --- a/test/js/samples/dynamic-import/expected.js +++ b/test/js/samples/dynamic-import/expected.js @@ -8,6 +8,7 @@ import { transition_in, transition_out } from "svelte/internal"; + import LazyLoad from "./LazyLoad.svelte"; function create_fragment(ctx) { @@ -38,7 +39,7 @@ function create_fragment(ctx) { }; } -const func = () => import('./Foo.svelte'); +const func = () => import("./Foo.svelte"); class Component extends SvelteComponent { constructor(options) { diff --git a/test/js/samples/event-modifiers/expected.js b/test/js/samples/event-modifiers/expected.js index 55ed17dace0e..f586a89be2d0 100644 --- a/test/js/samples/event-modifiers/expected.js +++ b/test/js/samples/event-modifiers/expected.js @@ -34,6 +34,7 @@ function create_fragment(ctx) { t3 = space(); button2 = element("button"); button2.textContent = "or me!"; + dispose = [ listen(button0, "click", stop_propagation(prevent_default(handleClick))), listen(button1, "click", handleClick, { once: true, capture: true }), From 96b9343ce75952a6d9c06dce2caf812ae3bcac65 Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Sun, 13 Oct 2019 16:24:10 -0400 Subject: [PATCH 86/93] various --- .../render_dom/wrappers/Element/index.ts | 2 +- .../compile/render_dom/wrappers/IfBlock.ts | 61 ++++++++---- .../wrappers/InlineComponent/index.ts | 4 +- .../compile/render_ssr/handlers/Comment.ts | 8 +- .../compile/render_ssr/handlers/DebugTag.ts | 4 +- test/js/index.js | 2 +- test/js/samples/debug-ssr-foo/expected.js | 18 ++-- .../js/samples/if-block-no-update/expected.js | 1 + test/js/samples/media-bindings/expected.js | 95 ++++++++++++------- .../non-imported-component/expected.js | 1 + .../samples/ssr-no-oncreate-etc/expected.js | 8 +- .../samples/ssr-preserve-comments/expected.js | 5 +- 12 files changed, 130 insertions(+), 79 deletions(-) diff --git a/src/compiler/compile/render_dom/wrappers/Element/index.ts b/src/compiler/compile/render_dom/wrappers/Element/index.ts index d91f9caa2227..a33e88f95ff4 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/index.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/index.ts @@ -460,7 +460,7 @@ export default class ElementWrapper extends Wrapper { @_cancelAnimationFrame(${animation_frame}); if (!${this.var}.paused) { ${animation_frame} = @raf(${handler}); - ${needs_lock && `${lock} = true;`} + ${needs_lock && b`${lock} = true;`} } #ctx.${handler}.call(${this.var}, ${contextual_dependencies.size > 0 ? '#ctx' : null}); } diff --git a/src/compiler/compile/render_dom/wrappers/IfBlock.ts b/src/compiler/compile/render_dom/wrappers/IfBlock.ts index 7273845fbe0e..261002df3be0 100644 --- a/src/compiler/compile/render_dom/wrappers/IfBlock.ts +++ b/src/compiler/compile/render_dom/wrappers/IfBlock.ts @@ -182,7 +182,7 @@ export default class IfBlockWrapper extends Wrapper { : (this.next && this.next.var) || 'null'; const has_else = !(this.branches[this.branches.length - 1].condition); - const if_exists_condition = has_else ? x`true` : name; + const if_exists_condition = has_else ? null : name; const dynamic = this.branches[0].block.has_update_method; // can use [0] as proxy for all, since they necessarily have the same value const has_intros = this.branches[0].block.has_intro_method; @@ -213,12 +213,22 @@ export default class IfBlockWrapper extends Wrapper { } } - block.chunks.create.push(b`if (${if_exists_condition}) ${name}.c();`); + if (if_exists_condition) { + block.chunks.create.push(b`if (${if_exists_condition}) ${name}.c();`); + } else { + block.chunks.create.push(b`${name}.c();`); + } if (parent_nodes && this.renderer.options.hydratable) { - block.chunks.claim.push( - b`if (${if_exists_condition}) ${name}.l(${parent_nodes});` - ); + if (if_exists_condition) { + block.chunks.claim.push( + b`if (${if_exists_condition}) ${name}.l(${parent_nodes});` + ); + } else { + block.chunks.claim.push( + b`${name}.l(${parent_nodes});` + ); + } } if (has_intros || has_outros) { @@ -286,15 +296,22 @@ export default class IfBlockWrapper extends Wrapper { const initial_mount_node = parent_node || '#target'; const anchor_node = parent_node ? 'null' : 'anchor'; - block.chunks.mount.push( - b`if (${if_exists_condition}) ${name}.m(${initial_mount_node}, ${anchor_node});` - ); + + if (if_exists_condition) { + block.chunks.mount.push( + b`if (${if_exists_condition}) ${name}.m(${initial_mount_node}, ${anchor_node});` + ); + } else { + block.chunks.mount.push( + b`${name}.m(${initial_mount_node}, ${anchor_node});` + ); + } if (this.needs_update) { const update_mount_node = this.get_update_mount_node(anchor); const change_block = b` - if (${if_exists_condition}) ${name}.d(1); + ${if_exists_condition ? b`if (${if_exists_condition}) ${name}.d(1)` : b`${name}.d(1)`}; ${name} = ${get_block}; if (${name}) { ${name}.c(); @@ -322,11 +339,17 @@ export default class IfBlockWrapper extends Wrapper { block.chunks.update.push(b`${name}.p(#changed, #ctx);`); } - block.chunks.destroy.push(b` - if (${if_exists_condition}) { + if (if_exists_condition) { + block.chunks.destroy.push(b` + if (${if_exists_condition}) { + ${name}.d(${detaching}); + } + `); + } else { + block.chunks.destroy.push(b` ${name}.d(${detaching}); - } - `); + `); + } } // if any of the siblings have outros, we need to keep references to the blocks @@ -554,8 +577,14 @@ export default class IfBlockWrapper extends Wrapper { `); } - block.chunks.destroy.push(b` - if (${if_exists_condition}) ${name}.d(${detaching}); - `); + if (if_exists_condition) { + block.chunks.destroy.push(b` + if (${if_exists_condition}) ${name}.d(${detaching}); + `); + } else { + block.chunks.destroy.push(b` + ${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 3a0646491928..0de8066999fd 100644 --- a/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts +++ b/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts @@ -380,7 +380,7 @@ export default class InlineComponentWrapper extends Wrapper { var ${switch_value} = ${snippet}; function ${switch_props}(#ctx) { - ${(this.node.attributes.length || this.node.bindings.length) && b` + ${(this.node.attributes.length > 0 || this.node.bindings.length > 0) && b` ${props && b`let ${props} = ${attribute_object};`}`} ${statements} return ${component_opts}; @@ -462,7 +462,7 @@ export default class InlineComponentWrapper extends Wrapper { : component.qualify(this.node.name); block.chunks.init.push(b` - ${(this.node.attributes.length || this.node.bindings.length) && b` + ${(this.node.attributes.length > 0 || this.node.bindings.length > 0) && b` ${props && b`let ${props} = ${attribute_object};`}`} ${statements} const ${name} = new ${expression}(${component_opts}); diff --git a/src/compiler/compile/render_ssr/handlers/Comment.ts b/src/compiler/compile/render_ssr/handlers/Comment.ts index 237c260230de..2e1c98106697 100644 --- a/src/compiler/compile/render_ssr/handlers/Comment.ts +++ b/src/compiler/compile/render_ssr/handlers/Comment.ts @@ -2,7 +2,9 @@ import Renderer, { RenderOptions } from '../Renderer'; import Comment from '../../nodes/Comment'; export default function(node: Comment, renderer: Renderer, options: RenderOptions) { - if (options.preserveComments) { - renderer.append(``); - } + // TODO preserve comments + + // if (options.preserveComments) { + // renderer.append(``); + // } } diff --git a/src/compiler/compile/render_ssr/handlers/DebugTag.ts b/src/compiler/compile/render_ssr/handlers/DebugTag.ts index 7c45d386402c..6955d1d1e64b 100644 --- a/src/compiler/compile/render_ssr/handlers/DebugTag.ts +++ b/src/compiler/compile/render_ssr/handlers/DebugTag.ts @@ -1,6 +1,6 @@ import DebugTag from '../../nodes/DebugTag'; import Renderer, { RenderOptions } from '../Renderer'; -import { x } from 'code-red'; +import { x, p } from 'code-red'; export default function(node: DebugTag, renderer: Renderer, options: RenderOptions) { if (!options.dev) return; @@ -9,7 +9,7 @@ export default function(node: DebugTag, renderer: Renderer, options: RenderOptio const { line, column } = options.locate(node.start + 1); const obj = x`{ - ${node.expressions.map(e => e.node.name)} + ${node.expressions.map(e => p`${e.node.name}`)} }`; renderer.add_expression(x`@debug(${filename ? x`"${filename}"` : x`null`}, ${line}, ${column}, ${obj})`); diff --git a/test/js/index.js b/test/js/index.js index e0fdaa1175a1..14d73d6c6572 100644 --- a/test/js/index.js +++ b/test/js/index.js @@ -3,7 +3,7 @@ import * as fs from "fs"; import * as path from "path"; import { loadConfig, svelte } from "../helpers.js"; -describe.only("js", () => { +describe("js", () => { fs.readdirSync("test/js/samples").forEach(dir => { if (dir[0] === ".") return; diff --git a/test/js/samples/debug-ssr-foo/expected.js b/test/js/samples/debug-ssr-foo/expected.js index 1b51af25921c..38d07e994e07 100644 --- a/test/js/samples/debug-ssr-foo/expected.js +++ b/test/js/samples/debug-ssr-foo/expected.js @@ -1,21 +1,15 @@ -/* generated by Svelte vX.Y.Z */ -import { - create_ssr_component, - debug, - each, - escape -} from "svelte/internal"; +import { create_ssr_component, debug, each, escape } from "svelte/internal"; const Component = create_ssr_component(($$result, $$props, $$bindings, $$slots) => { - let { things, foo } = $$props; - + let { things } = $$props; + let { foo } = $$props; if ($$props.things === void 0 && $$bindings.things && things !== void 0) $$bindings.things(things); if ($$props.foo === void 0 && $$bindings.foo && foo !== void 0) $$bindings.foo(foo); - return `${each(things, (thing) => `${escape(thing.name)} - ${debug(null, 7, 2, { foo })}`)} + return `${each(things, thing => `${escape(thing.name)} + ${debug(null, 7, 2, { foo })}`)} -

foo: ${escape(foo)}

`; +

foo: ${escape(foo)}

`; }); export default Component; \ No newline at end of file diff --git a/test/js/samples/if-block-no-update/expected.js b/test/js/samples/if-block-no-update/expected.js index 3ce3c4db79e9..829ddf8ddd59 100644 --- a/test/js/samples/if-block-no-update/expected.js +++ b/test/js/samples/if-block-no-update/expected.js @@ -67,6 +67,7 @@ function create_fragment(ctx) { if (current_block_type !== (current_block_type = select_block_type(changed, ctx))) { if_block.d(1); if_block = current_block_type(ctx); + if (if_block) { if_block.c(); if_block.m(if_block_anchor.parentNode, if_block_anchor); diff --git a/test/js/samples/media-bindings/expected.js b/test/js/samples/media-bindings/expected.js index b67bc31ed352..25d21137e479 100644 --- a/test/js/samples/media-bindings/expected.js +++ b/test/js/samples/media-bindings/expected.js @@ -1,4 +1,3 @@ -/* generated by Svelte vX.Y.Z */ import { SvelteComponent, add_render_callback, @@ -15,14 +14,20 @@ import { } from "svelte/internal"; function create_fragment(ctx) { - var audio, audio_updating = false, audio_animationframe, audio_is_paused = true, dispose; + let audio; + let audio_updating = false; + let audio_animationframe; + let audio_is_paused = true; + let dispose; function audio_timeupdate_handler() { cancelAnimationFrame(audio_animationframe); + if (!audio.paused) { audio_animationframe = raf(audio_timeupdate_handler); audio_updating = true; } + ctx.audio_timeupdate_handler.call(audio); } @@ -45,87 +50,97 @@ function create_fragment(ctx) { listen(audio, "ratechange", ctx.audio_ratechange_handler) ]; }, - m(target, anchor) { insert(target, audio, anchor); - audio.volume = ctx.volume; - audio.playbackRate = ctx.playbackRate; }, - p(changed, ctx) { - if (!audio_updating && changed.currentTime && !isNaN(ctx.currentTime)) audio.currentTime = ctx.currentTime; - if (changed.paused && audio_is_paused !== (audio_is_paused = ctx.paused)) audio[audio_is_paused ? "pause" : "play"](); - if (changed.volume && !isNaN(ctx.volume)) audio.volume = ctx.volume; - if (changed.playbackRate && !isNaN(ctx.playbackRate)) audio.playbackRate = ctx.playbackRate; + if (!audio_updating && changed.currentTime && !isNaN(ctx.currentTime)) { + audio.currentTime = ctx.currentTime; + } + + if (changed.paused && audio_is_paused !== (audio_is_paused = ctx.paused)) { + audio[audio_is_paused ? "pause" : "play"](); + } + + if (changed.volume && !isNaN(ctx.volume)) { + audio.volume = ctx.volume; + } + + if (changed.playbackRate && !isNaN(ctx.playbackRate)) { + audio.playbackRate = ctx.playbackRate; + } + audio_updating = false; }, - i: noop, o: noop, - d(detaching) { - if (detaching) { - detach(audio); - } - + if (detaching) detach(audio); run_all(dispose); } }; } function instance($$self, $$props, $$invalidate) { - let { buffered, seekable, played, currentTime, duration, paused, volume, playbackRate } = $$props; + let { buffered } = $$props; + let { seekable } = $$props; + let { played } = $$props; + let { currentTime } = $$props; + let { duration } = $$props; + let { paused } = $$props; + let { volume } = $$props; + let { playbackRate } = $$props; function audio_timeupdate_handler() { played = time_ranges_to_array(this.played); currentTime = this.currentTime; - $$invalidate('played', played); - $$invalidate('currentTime', currentTime); + $$invalidate("played", played); + $$invalidate("currentTime", currentTime); } function audio_durationchange_handler() { duration = this.duration; - $$invalidate('duration', duration); + $$invalidate("duration", duration); } function audio_play_pause_handler() { paused = this.paused; - $$invalidate('paused', paused); + $$invalidate("paused", paused); } function audio_progress_handler() { buffered = time_ranges_to_array(this.buffered); - $$invalidate('buffered', buffered); + $$invalidate("buffered", buffered); } function audio_loadedmetadata_handler() { buffered = time_ranges_to_array(this.buffered); seekable = time_ranges_to_array(this.seekable); - $$invalidate('buffered', buffered); - $$invalidate('seekable', seekable); + $$invalidate("buffered", buffered); + $$invalidate("seekable", seekable); } function audio_volumechange_handler() { volume = this.volume; - $$invalidate('volume', volume); + $$invalidate("volume", volume); } function audio_ratechange_handler() { playbackRate = this.playbackRate; - $$invalidate('playbackRate', playbackRate); + $$invalidate("playbackRate", playbackRate); } $$self.$set = $$props => { - if ('buffered' in $$props) $$invalidate('buffered', buffered = $$props.buffered); - if ('seekable' in $$props) $$invalidate('seekable', seekable = $$props.seekable); - if ('played' in $$props) $$invalidate('played', played = $$props.played); - if ('currentTime' in $$props) $$invalidate('currentTime', currentTime = $$props.currentTime); - if ('duration' in $$props) $$invalidate('duration', duration = $$props.duration); - if ('paused' in $$props) $$invalidate('paused', paused = $$props.paused); - if ('volume' in $$props) $$invalidate('volume', volume = $$props.volume); - if ('playbackRate' in $$props) $$invalidate('playbackRate', playbackRate = $$props.playbackRate); + if ("buffered" in $$props) $$invalidate("buffered", buffered = $$props.buffered); + if ("seekable" in $$props) $$invalidate("seekable", seekable = $$props.seekable); + if ("played" in $$props) $$invalidate("played", played = $$props.played); + if ("currentTime" in $$props) $$invalidate("currentTime", currentTime = $$props.currentTime); + if ("duration" in $$props) $$invalidate("duration", duration = $$props.duration); + if ("paused" in $$props) $$invalidate("paused", paused = $$props.paused); + if ("volume" in $$props) $$invalidate("volume", volume = $$props.volume); + if ("playbackRate" in $$props) $$invalidate("playbackRate", playbackRate = $$props.playbackRate); }; return { @@ -150,7 +165,17 @@ function instance($$self, $$props, $$invalidate) { class Component extends SvelteComponent { constructor(options) { super(); - init(this, options, instance, create_fragment, safe_not_equal, ["buffered", "seekable", "played", "currentTime", "duration", "paused", "volume", "playbackRate"]); + + init(this, options, instance, create_fragment, safe_not_equal, [ + "buffered", + "seekable", + "played", + "currentTime", + "duration", + "paused", + "volume", + "playbackRate" + ]); } } diff --git a/test/js/samples/non-imported-component/expected.js b/test/js/samples/non-imported-component/expected.js index 7bc92ec560d6..1cbc13fac3ac 100644 --- a/test/js/samples/non-imported-component/expected.js +++ b/test/js/samples/non-imported-component/expected.js @@ -11,6 +11,7 @@ import { transition_in, transition_out } from "svelte/internal"; + import Imported from "Imported.svelte"; function create_fragment(ctx) { diff --git a/test/js/samples/ssr-no-oncreate-etc/expected.js b/test/js/samples/ssr-no-oncreate-etc/expected.js index 89d46061c34b..59edcaee16c2 100644 --- a/test/js/samples/ssr-no-oncreate-etc/expected.js +++ b/test/js/samples/ssr-no-oncreate-etc/expected.js @@ -5,14 +5,14 @@ function preload(input) { return output; } -function swipe(node, callback) { - -} - function foo() { console.log("foo"); } +function swipe(node, callback) { + +} + const Component = create_ssr_component(($$result, $$props, $$bindings, $$slots) => { onMount(() => { console.log("onMount"); diff --git a/test/js/samples/ssr-preserve-comments/expected.js b/test/js/samples/ssr-preserve-comments/expected.js index d9a63e6011cc..872cc2bca0fa 100644 --- a/test/js/samples/ssr-preserve-comments/expected.js +++ b/test/js/samples/ssr-preserve-comments/expected.js @@ -1,10 +1,9 @@ -/* generated by Svelte vX.Y.Z */ import { create_ssr_component } from "svelte/internal"; const Component = create_ssr_component(($$result, $$props, $$bindings, $$slots) => { return `
content
- -
more content
`; + +
more content
`; }); export default Component; \ No newline at end of file From bc066d35626f4952c1d1a9dd429a91c40415c40c Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Sun, 13 Oct 2019 19:57:05 -0400 Subject: [PATCH 87/93] ALL TESTS PASSING --- package-lock.json | 12 ++++++------ package.json | 2 +- src/compiler/compile/render_dom/Block.ts | 2 +- test/js/samples/input-no-initial-value/expected.js | 6 +++--- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/package-lock.json b/package-lock.json index 26b2b8b62714..97fa374f9db8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -490,9 +490,9 @@ "dev": true }, "code-red": { - "version": "0.0.16", - "resolved": "https://registry.npmjs.org/code-red/-/code-red-0.0.16.tgz", - "integrity": "sha512-40SV6oWnBVVfUP+i8NYeTo9EQWtTnlZ17LIv91dKhLa6R/iZKqxOAV/5HEkj86EhLmNiRB7O6hEnga2jy0hoBA==", + "version": "0.0.17", + "resolved": "https://registry.npmjs.org/code-red/-/code-red-0.0.17.tgz", + "integrity": "sha512-RJJ48sXYOqyd0J4QelF4dRdYb+4DaLV/jHs4mNoxOdLroUGB840cMc9pMtEAbGKjFFzoTKREypFzqphBD8knMg==", "dev": true, "requires": { "acorn": "^7.0.0", @@ -2721,9 +2721,9 @@ "dev": true }, "periscopic": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/periscopic/-/periscopic-1.0.1.tgz", - "integrity": "sha512-JcSQ6sufVNGT04lPr2f2qGuJ2FCkZcbWBw0gQ8mzSVf9+6bEX9ea6l48+PdAekjJIHlEwSrqJND1TR2cC1FbtQ==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/periscopic/-/periscopic-1.0.2.tgz", + "integrity": "sha512-KpKBKadLf8THXOxswQBhOY8E1lVVhfUidacPtQBrq7KDXaNkQLUPiTmXagzqpJGECP3/0gDXYFO6CZHVbGvOSw==", "dev": true, "requires": { "is-reference": "^1.1.4" diff --git a/package.json b/package.json index 44c4cda6d168..515ef716e7e3 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,7 @@ "acorn": "^7.0.0", "agadoo": "^1.1.0", "c8": "^5.0.1", - "code-red": "0.0.16", + "code-red": "0.0.17", "codecov": "^3.5.0", "css-tree": "1.0.0-alpha22", "eslint": "^6.3.0", diff --git a/src/compiler/compile/render_dom/Block.ts b/src/compiler/compile/render_dom/Block.ts index 8f96520780f1..60044ab03794 100644 --- a/src/compiler/compile/render_dom/Block.ts +++ b/src/compiler/compile/render_dom/Block.ts @@ -128,7 +128,7 @@ export default class Block { const wrapper = this.wrappers[i]; if (!wrapper.var) continue; - if (wrapper.parent && wrapper.parent.can_use_innerhtml) continue; + // if (wrapper.parent && wrapper.parent.can_use_innerhtml) continue; if (seen.has(wrapper.var.name)) { dupes.add(wrapper.var.name); diff --git a/test/js/samples/input-no-initial-value/expected.js b/test/js/samples/input-no-initial-value/expected.js index 598bc0177f94..db7f7df0c4fe 100644 --- a/test/js/samples/input-no-initial-value/expected.js +++ b/test/js/samples/input-no-initial-value/expected.js @@ -17,7 +17,7 @@ import { function create_fragment(ctx) { let form; let input; - let t; + let t0; let button; let dispose; @@ -25,7 +25,7 @@ function create_fragment(ctx) { c() { form = element("form"); input = element("input"); - t = space(); + t0 = space(); button = element("button"); button.textContent = "Store"; attr(input, "type", "text"); @@ -40,7 +40,7 @@ function create_fragment(ctx) { insert(target, form, anchor); append(form, input); set_input_value(input, ctx.test); - append(form, t); + append(form, t0); append(form, button); }, p(changed, ctx) { From 7efcca82ccd603f398449dd929a02f8992c879d1 Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Sun, 13 Oct 2019 20:53:40 -0400 Subject: [PATCH 88/93] lint --- .eslintrc.js | 9 +----- src/compiler/compile/Component.ts | 4 +-- src/compiler/compile/create_module.ts | 2 +- src/compiler/compile/css/interfaces.ts | 2 +- src/compiler/compile/nodes/EachBlock.ts | 2 +- .../compile/nodes/shared/Expression.ts | 2 +- src/compiler/compile/render_dom/Block.ts | 28 +++++++++---------- src/compiler/compile/render_dom/Renderer.ts | 2 +- src/compiler/compile/render_dom/index.ts | 2 +- .../compile/render_dom/wrappers/AwaitBlock.ts | 2 +- .../compile/render_dom/wrappers/EachBlock.ts | 2 +- .../render_dom/wrappers/Element/Attribute.ts | 2 +- .../render_dom/wrappers/Element/Binding.ts | 2 +- .../wrappers/Element/StyleAttribute.ts | 2 +- .../render_dom/wrappers/Element/index.ts | 8 +++--- .../compile/render_dom/wrappers/IfBlock.ts | 2 +- .../wrappers/InlineComponent/index.ts | 4 +-- .../render_dom/wrappers/shared/add_actions.ts | 3 +- src/compiler/compile/render_ssr/Renderer.ts | 15 ++-------- src/compiler/compile/utils/get_slot_data.ts | 2 +- src/compiler/interfaces.ts | 4 +-- src/compiler/parse/read/script.ts | 2 +- src/compiler/parse/state/tag.ts | 4 +-- 23 files changed, 44 insertions(+), 63 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 2c7f2ed1b474..2023207f74de 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -22,14 +22,7 @@ module.exports = { 'arrow-spacing': 2, 'no-inner-declarations': 0, 'require-atomic-updates': 'off', - '@typescript-eslint/indent': [ - 'error', - 'tab', - { - SwitchCase: 1, - ignoredNodes: ['TemplateLiteral'] - } - ], + '@typescript-eslint/indent': 'off', '@typescript-eslint/camelcase': 'off', '@typescript-eslint/no-use-before-define': 'off', '@typescript-eslint/array-type': ['error', 'array-simple'], diff --git a/src/compiler/compile/Component.ts b/src/compiler/compile/Component.ts index 678f79f3c936..032358b151c8 100644 --- a/src/compiler/compile/Component.ts +++ b/src/compiler/compile/Component.ts @@ -71,8 +71,8 @@ export default class Component { hoistable_nodes: Set = new Set(); node_for_declaration: Map = new Map(); - partly_hoisted: (Node | Node[])[] = []; - fully_hoisted: (Node | Node[])[] = []; + partly_hoisted: Array<(Node | Node[])> = []; + fully_hoisted: Array<(Node | Node[])> = []; reactive_declarations: Array<{ assignees: Set; dependencies: Set; diff --git a/src/compiler/compile/create_module.ts b/src/compiler/compile/create_module.ts index 5f2f0cebfd22..df85c276ea11 100644 --- a/src/compiler/compile/create_module.ts +++ b/src/compiler/compile/create_module.ts @@ -62,7 +62,7 @@ function esm( imported: { type: 'Identifier', name: h.name } })), source: { type: 'Literal', value: internal_path } - } + }; const internal_globals = globals.length > 0 && { type: 'VariableDeclaration', diff --git a/src/compiler/compile/css/interfaces.ts b/src/compiler/compile/css/interfaces.ts index 64dd8b33742a..103bc18d792e 100644 --- a/src/compiler/compile/css/interfaces.ts +++ b/src/compiler/compile/css/interfaces.ts @@ -1,4 +1,4 @@ -export type CssNode = { +export interface CssNode { type: string; start: number; end: number; diff --git a/src/compiler/compile/nodes/EachBlock.ts b/src/compiler/compile/nodes/EachBlock.ts index 70b3340ce57e..85da0a221021 100644 --- a/src/compiler/compile/nodes/EachBlock.ts +++ b/src/compiler/compile/nodes/EachBlock.ts @@ -37,7 +37,7 @@ function unpack_destructuring(contexts: Context[], node: Node, modifier: (node: const replacement: RestElement = { type: 'RestElement', argument: property.key as Identifier - } + }; node.properties[i] = replacement; diff --git a/src/compiler/compile/nodes/shared/Expression.ts b/src/compiler/compile/nodes/shared/Expression.ts index 24753ee40b89..99d063a98d65 100644 --- a/src/compiler/compile/nodes/shared/Expression.ts +++ b/src/compiler/compile/nodes/shared/Expression.ts @@ -32,7 +32,7 @@ export default class Expression { // TODO apparently unnecessary? // is_synthetic: boolean; - declarations: (Node | Node[])[] = []; + declarations: Array<(Node | Node[])> = []; uses_context = false; manipulated: Node; diff --git a/src/compiler/compile/render_dom/Block.ts b/src/compiler/compile/render_dom/Block.ts index 60044ab03794..7e25cd0f5628 100644 --- a/src/compiler/compile/render_dom/Block.ts +++ b/src/compiler/compile/render_dom/Block.ts @@ -44,18 +44,18 @@ export default class Block { }>; chunks: { - init: (Node | Node[])[]; - create: (Node | Node[])[]; - claim: (Node | Node[])[]; - hydrate: (Node | Node[])[]; - mount: (Node | Node[])[]; - measure: (Node | Node[])[]; - fix: (Node | Node[])[]; - animate: (Node | Node[])[]; - intro: (Node | Node[])[]; - update: (Node | Node[])[]; - outro: (Node | Node[])[]; - destroy: (Node | Node[])[]; + init: Array; + create: Array; + claim: Array; + hydrate: Array; + mount: Array; + measure: Array; + fix: Array; + animate: Array; + intro: Array; + update: Array; + outro: Array; + destroy: Array; }; event_listeners: Node[] = []; @@ -69,7 +69,7 @@ export default class Block { outros: number; aliases: Map; - variables: Map = new Map(); + variables: Map = new Map(); get_unique_name: (name: string) => Identifier; has_update_method = false; @@ -249,7 +249,7 @@ export default class Block { const noop = x`@noop`; - properties.key = key + properties.key = key; if (this.first) { properties.first = x`null`; diff --git a/src/compiler/compile/render_dom/Renderer.ts b/src/compiler/compile/render_dom/Renderer.ts index cf148df30405..624886c2c722 100644 --- a/src/compiler/compile/render_dom/Renderer.ts +++ b/src/compiler/compile/render_dom/Renderer.ts @@ -11,7 +11,7 @@ export default class Renderer { blocks: Array = []; readonly: Set = new Set(); - meta_bindings: (Node | Node[])[] = []; // initial values for e.g. window.innerWidth, if there's a meta tag + meta_bindings: Array = []; // 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 0d8a29d63b95..4dbe5bb0595b 100644 --- a/src/compiler/compile/render_dom/index.ts +++ b/src/compiler/compile/render_dom/index.ts @@ -475,7 +475,7 @@ export default function dom( value: x`function() { return [${props.map(prop => x`"${prop.export_name}"`)}]; }` as FunctionExpression - }) + }); } declaration.body.body.push(...accessors); diff --git a/src/compiler/compile/render_dom/wrappers/AwaitBlock.ts b/src/compiler/compile/render_dom/wrappers/AwaitBlock.ts index 0a4262181eda..0497ca5d5630 100644 --- a/src/compiler/compile/render_dom/wrappers/AwaitBlock.ts +++ b/src/compiler/compile/render_dom/wrappers/AwaitBlock.ts @@ -188,7 +188,7 @@ export default class AwaitBlockWrapper extends Wrapper { const dependencies = this.node.expression.dynamic_dependencies(); if (dependencies.length > 0) { - let condition = x` + const condition = x` ${changed(dependencies)} && ${promise} !== (${promise} = ${snippet}) && @handle_promise(${promise}, ${info})`; diff --git a/src/compiler/compile/render_dom/wrappers/EachBlock.ts b/src/compiler/compile/render_dom/wrappers/EachBlock.ts index 33968c762a63..5c8d193f5693 100644 --- a/src/compiler/compile/render_dom/wrappers/EachBlock.ts +++ b/src/compiler/compile/render_dom/wrappers/EachBlock.ts @@ -61,7 +61,7 @@ export default class EachBlockWrapper extends Wrapper { view_length: string; } - context_props: (Node | Node[])[]; + context_props: Array; index_name: Identifier; var: Identifier = { type: 'Identifier', name: 'each' }; diff --git a/src/compiler/compile/render_dom/wrappers/Element/Attribute.ts b/src/compiler/compile/render_dom/wrappers/Element/Attribute.ts index 77f0a6d92dd1..876be588d660 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/Attribute.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/Attribute.ts @@ -84,7 +84,7 @@ export default class AttributeWrapper { } else { value = this.node.name === 'class' ? this.get_class_name_text() - : this.render_chunks().reduce((lhs, rhs) => x`${lhs} + ${rhs}`) + : this.render_chunks().reduce((lhs, rhs) => x`${lhs} + ${rhs}`); // '{foo} {bar}' — treat as string concatenation if (this.node.chunks[0].type !== 'Text') { diff --git a/src/compiler/compile/render_dom/wrappers/Element/Binding.ts b/src/compiler/compile/render_dom/wrappers/Element/Binding.ts index e9fc9a87ef27..d0baf4aa4aee 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/Binding.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/Binding.ts @@ -267,7 +267,7 @@ function get_event_handler( } } - let mutation = b` + const mutation = b` ${lhs} = ${value}; ${set_store} `; diff --git a/src/compiler/compile/render_dom/wrappers/Element/StyleAttribute.ts b/src/compiler/compile/render_dom/wrappers/Element/StyleAttribute.ts index b4198ed29853..c60a89f66f03 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/StyleAttribute.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/StyleAttribute.ts @@ -38,7 +38,7 @@ export default class StyleAttributeWrapper extends AttributeWrapper { return chunk.manipulate(block); } }) - .reduce((lhs, rhs) => x`${lhs} + ${rhs}`) + .reduce((lhs, rhs) => x`${lhs} + ${rhs}`); // TODO is this necessary? style.setProperty always treats value as string, no? // if (prop.value.length === 1 || prop.value[0].type !== 'Text') { diff --git a/src/compiler/compile/render_dom/wrappers/Element/index.ts b/src/compiler/compile/render_dom/wrappers/Element/index.ts index a33e88f95ff4..1744b5af12e4 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/index.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/index.ts @@ -310,7 +310,7 @@ export default class ElementWrapper extends Wrapper { quasis: [] }; - to_html((this.fragment.nodes as unknown as (ElementWrapper | TextWrapper)[]), block, literal, state); + to_html((this.fragment.nodes as unknown as Array), block, literal, state); literal.quasis.push(state.quasi); block.chunks.create.push( @@ -832,7 +832,7 @@ export default class ElementWrapper extends Wrapper { } } -function to_html(wrappers: (ElementWrapper | TextWrapper)[], block: Block, literal: any, state: any) { +function to_html(wrappers: Array, block: Block, literal: any, state: any) { wrappers.forEach(wrapper => { if (wrapper.node.type === 'Text') { if ((wrapper as TextWrapper).use_space()) state.quasi.value.raw += ' '; @@ -866,7 +866,7 @@ function to_html(wrappers: (ElementWrapper | TextWrapper)[], block: Block, liter state.quasi.value.raw += chunk.data; } else { literal.quasis.push(state.quasi); - literal.expressions.push(chunk.manipulate(block)) + literal.expressions.push(chunk.manipulate(block)); state.quasi = { type: 'TemplateElement', @@ -881,7 +881,7 @@ function to_html(wrappers: (ElementWrapper | TextWrapper)[], block: Block, liter state.quasi.value.raw += '>'; if (!is_void(wrapper.node.name)) { - to_html((wrapper as ElementWrapper).fragment.nodes as (ElementWrapper | TextWrapper)[], block, literal, state); + to_html((wrapper as ElementWrapper).fragment.nodes as Array, block, literal, state); state.quasi.value.raw += ``; } diff --git a/src/compiler/compile/render_dom/wrappers/IfBlock.ts b/src/compiler/compile/render_dom/wrappers/IfBlock.ts index 261002df3be0..c54994a36ca5 100644 --- a/src/compiler/compile/render_dom/wrappers/IfBlock.ts +++ b/src/compiler/compile/render_dom/wrappers/IfBlock.ts @@ -261,7 +261,7 @@ export default class IfBlockWrapper extends Wrapper { const current_block_type = block.get_unique_name(`current_block_type`); const get_block = has_else ? x`${current_block_type}(#ctx)` - : x`${current_block_type} && ${current_block_type}(#ctx)` + : x`${current_block_type} && ${current_block_type}(#ctx)`; /* eslint-disable @typescript-eslint/indent,indent */ if (this.needs_update) { diff --git a/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts b/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts index 0de8066999fd..431affbcad95 100644 --- a/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts +++ b/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts @@ -116,8 +116,8 @@ export default class InlineComponentWrapper extends Wrapper { const component_opts = x`{}` as ObjectExpression; - const statements: (Node | Node[])[] = []; - const updates: (Node | Node[])[] = []; + const statements: Array = []; + const updates: Array = []; let props; const name_changes = block.get_unique_name(`${name.name}_changes`); 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 331a71708efc..538bfc7a9558 100644 --- a/src/compiler/compile/render_dom/wrappers/shared/add_actions.ts +++ b/src/compiler/compile/render_dom/wrappers/shared/add_actions.ts @@ -1,8 +1,7 @@ -import { b } from 'code-red'; +import { b, x } from 'code-red'; import Block from '../../Block'; import Action from '../../../nodes/Action'; import Component from '../../../Component'; -import { x } from 'code-red'; export default function add_actions( component: Component, diff --git a/src/compiler/compile/render_ssr/Renderer.ts b/src/compiler/compile/render_ssr/Renderer.ts index c8b2d14ff6fa..00a7ee2fb535 100644 --- a/src/compiler/compile/render_ssr/Renderer.ts +++ b/src/compiler/compile/render_ssr/Renderer.ts @@ -48,7 +48,7 @@ export default class Renderer { name: Identifier; - stack: { current: { value: string }, literal: TemplateLiteral }[] = []; + stack: Array<{ current: { value: string }; literal: TemplateLiteral }> = []; current: { value: string }; // TODO can it just be `current: string`? literal: TemplateLiteral; @@ -59,17 +59,6 @@ export default class Renderer { this.push(); } - append() { - throw new Error('no more append'); - // if (this.targets.length) { - // const target = this.targets[this.targets.length - 1]; - // const slot_name = target.slot_stack[target.slot_stack.length - 1]; - // target.slots[slot_name] += code; - // } else { - // this.code += code; - // } - } - add_string(str: string) { this.current.value += escape_template(str); } @@ -94,7 +83,7 @@ export default class Renderer { quasis: [] }; - this.stack.push({ current, literal }) + this.stack.push({ current, literal }); } pop() { diff --git a/src/compiler/compile/utils/get_slot_data.ts b/src/compiler/compile/utils/get_slot_data.ts index 18df4e311816..c81dc83c92a4 100644 --- a/src/compiler/compile/utils/get_slot_data.ts +++ b/src/compiler/compile/utils/get_slot_data.ts @@ -11,7 +11,7 @@ export default function get_slot_data(values: Map, is_ssr: bo const value = get_value(attribute); return p`${attribute.name}: ${value}`; }) - } + }; } // TODO fairly sure this is duplicated at least once diff --git a/src/compiler/interfaces.ts b/src/compiler/interfaces.ts index 5d3acda67b5a..1e0028e8aa82 100644 --- a/src/compiler/interfaces.ts +++ b/src/compiler/interfaces.ts @@ -67,7 +67,7 @@ export interface Parser { } export interface Script extends BaseNode { - type: 'Script', + type: 'Script'; context: string; content: Program; } @@ -80,7 +80,7 @@ export interface Style extends BaseNode { start: number; end: number; styles: string; - } + }; } export interface Ast { diff --git a/src/compiler/parse/read/script.ts b/src/compiler/parse/read/script.ts index ed427d655105..efc93066772f 100644 --- a/src/compiler/parse/read/script.ts +++ b/src/compiler/parse/read/script.ts @@ -29,7 +29,7 @@ function get_context(parser: Parser, attributes: any[], start: number): string { return value; } -export default function read_script(parser: Parser, start: number, attributes: Node[]) : Script { +export default function read_script(parser: Parser, start: number, attributes: Node[]): Script { const script_start = parser.index; const script_end = parser.template.indexOf(script_closing_tag, script_start); diff --git a/src/compiler/parse/state/tag.ts b/src/compiler/parse/state/tag.ts index dca23012035d..880c866ffe8b 100644 --- a/src/compiler/parse/state/tag.ts +++ b/src/compiler/parse/state/tag.ts @@ -37,8 +37,8 @@ const specials = new Map([ ], ]); -const SELF = /^svelte:self(?=[\s\/>])/; -const COMPONENT = /^svelte:component(?=[\s\/>])/; +const SELF = /^svelte:self(?=[\s/>])/; +const COMPONENT = /^svelte:component(?=[\s/>])/; function parent_is_head(stack) { let i = stack.length; From 682707ff60f7fd519a363507b7a80996e175d520 Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Sun, 13 Oct 2019 21:21:03 -0400 Subject: [PATCH 89/93] typescript stuff --- src/compiler/compile/nodes/EachBlock.ts | 4 ++-- src/compiler/compile/render_dom/Block.ts | 2 ++ src/compiler/compile/render_dom/index.ts | 3 +-- .../render_dom/wrappers/Element/Binding.ts | 2 +- .../wrappers/InlineComponent/index.ts | 2 +- .../compile/render_dom/wrappers/Slot.ts | 2 +- .../compile/render_ssr/handlers/Comment.ts | 2 +- .../compile/render_ssr/handlers/Element.ts | 17 +++++++++-------- .../render_ssr/handlers/InlineComponent.ts | 1 - .../compile/render_ssr/handlers/Slot.ts | 2 +- src/compiler/compile/render_ssr/index.ts | 9 +++++++-- src/compiler/compile/utils/get_slot_data.ts | 2 +- src/compiler/utils/names.ts | 10 ---------- 13 files changed, 27 insertions(+), 31 deletions(-) diff --git a/src/compiler/compile/nodes/EachBlock.ts b/src/compiler/compile/nodes/EachBlock.ts index 85da0a221021..31850f874546 100644 --- a/src/compiler/compile/nodes/EachBlock.ts +++ b/src/compiler/compile/nodes/EachBlock.ts @@ -4,7 +4,7 @@ import map_children from './shared/map_children'; import TemplateScope from './shared/TemplateScope'; import AbstractBlock from './shared/AbstractBlock'; import Element from './Element'; -import { x, p } from 'code-red'; +import { x } from 'code-red'; import { Node, Identifier, RestElement } from 'estree'; interface Context { @@ -39,7 +39,7 @@ function unpack_destructuring(contexts: Context[], node: Node, modifier: (node: argument: property.key as Identifier }; - node.properties[i] = replacement; + node.properties[i] = replacement as any; unpack_destructuring( contexts, diff --git a/src/compiler/compile/render_dom/Block.ts b/src/compiler/compile/render_dom/Block.ts index 7e25cd0f5628..fc501143d1d1 100644 --- a/src/compiler/compile/render_dom/Block.ts +++ b/src/compiler/compile/render_dom/Block.ts @@ -17,6 +17,7 @@ export interface BlockOptions { snippet: Node; store: string; tail: Node; + modifier: (node: Node) => Node; }>; dependencies?: Set; } @@ -41,6 +42,7 @@ export default class Block { snippet: Node; store: string; tail: Node; + modifier: (node: Node) => Node; }>; chunks: { diff --git a/src/compiler/compile/render_dom/index.ts b/src/compiler/compile/render_dom/index.ts index 4dbe5bb0595b..a972baf5c85a 100644 --- a/src/compiler/compile/render_dom/index.ts +++ b/src/compiler/compile/render_dom/index.ts @@ -1,5 +1,4 @@ import { b, x, p } from 'code-red'; -import { escape } from '../utils/stringify'; import Component from '../Component'; import Renderer from './Renderer'; import { CompileOptions } from '../../interfaces'; @@ -8,7 +7,7 @@ import add_to_set from '../utils/add_to_set'; import { extract_names } from '../utils/scope'; import { invalidate } from '../utils/invalidate'; import Block from './Block'; -import { ClassDeclaration, FunctionExpression, Node, LabeledStatement, Statement } from 'estree'; +import { ClassDeclaration, FunctionExpression, Node, Statement } from 'estree'; export default function dom( component: Component, diff --git a/src/compiler/compile/render_dom/wrappers/Element/Binding.ts b/src/compiler/compile/render_dom/wrappers/Element/Binding.ts index d0baf4aa4aee..90727743fa4a 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/Binding.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/Binding.ts @@ -7,7 +7,7 @@ import Renderer from '../../Renderer'; import flatten_reference from '../../../utils/flatten_reference'; import EachBlock from '../../../nodes/EachBlock'; import { changed } from '../shared/changed'; -import { Node, Identifier, MemberExpression } from 'estree'; +import { Node, Identifier } from 'estree'; export default class BindingWrapper { node: Binding; diff --git a/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts b/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts index 431affbcad95..f6e3039243f7 100644 --- a/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts +++ b/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts @@ -15,7 +15,7 @@ import TemplateScope from '../../../nodes/shared/TemplateScope'; import is_dynamic from '../shared/is_dynamic'; import bind_this from '../shared/bind_this'; import { changed } from '../shared/changed'; -import { Node, Identifier, Expression, ObjectExpression, Property } from 'estree'; +import { Node, Identifier, ObjectExpression } from 'estree'; export default class InlineComponentWrapper extends Wrapper { var: Identifier; diff --git a/src/compiler/compile/render_dom/wrappers/Slot.ts b/src/compiler/compile/render_dom/wrappers/Slot.ts index 1934ea14cd12..1ab1b6abcb5d 100644 --- a/src/compiler/compile/render_dom/wrappers/Slot.ts +++ b/src/compiler/compile/render_dom/wrappers/Slot.ts @@ -66,7 +66,7 @@ export default class SlotWrapper extends Wrapper { get_slot_changes = renderer.component.get_unique_name(`get_${sanitize(slot_name)}_slot_changes`); get_slot_context = renderer.component.get_unique_name(`get_${sanitize(slot_name)}_slot_context`); - const context = get_slot_data(this.node.values, false); + const context = get_slot_data(this.node.values); const changes = x`{}` as ObjectExpression; const dependencies = new Set(); diff --git a/src/compiler/compile/render_ssr/handlers/Comment.ts b/src/compiler/compile/render_ssr/handlers/Comment.ts index 2e1c98106697..4595274bc0f4 100644 --- a/src/compiler/compile/render_ssr/handlers/Comment.ts +++ b/src/compiler/compile/render_ssr/handlers/Comment.ts @@ -1,7 +1,7 @@ import Renderer, { RenderOptions } from '../Renderer'; import Comment from '../../nodes/Comment'; -export default function(node: Comment, renderer: Renderer, options: RenderOptions) { +export default function(_node: Comment, _renderer: Renderer, _options: RenderOptions) { // TODO preserve comments // if (options.preserveComments) { diff --git a/src/compiler/compile/render_ssr/handlers/Element.ts b/src/compiler/compile/render_ssr/handlers/Element.ts index 8de08c51f37b..2e24b0e471ad 100644 --- a/src/compiler/compile/render_ssr/handlers/Element.ts +++ b/src/compiler/compile/render_ssr/handlers/Element.ts @@ -1,12 +1,12 @@ -import { is_void, quote_prop_if_necessary } from '../../../utils/names'; +import { is_void } from '../../../utils/names'; import Attribute from '../../nodes/Attribute'; import Class from '../../nodes/Class'; import { get_attribute_value, get_class_attribute_value } from './shared/get_attribute_value'; import { get_slot_scope } from './shared/get_slot_scope'; import Renderer, { RenderOptions } from '../Renderer'; import Element from '../../nodes/Element'; -import Text from '../../nodes/Text'; import { x } from 'code-red'; +import Expression from '../../nodes/shared/Expression'; // source: https://gist.github.com/ArjanSchouten/0b8574a6ad7f5065a5e7 const boolean_attributes = new Set([ @@ -54,7 +54,6 @@ export default function(node: Element, renderer: Renderer, options: RenderOption }) { // awkward special case let node_contents; - let value; const contenteditable = ( node.name !== 'textarea' && @@ -112,12 +111,12 @@ export default function(node: Element, renderer: Renderer, options: RenderOption attribute.chunks[0].type !== 'Text' ) { // a boolean attribute with one non-Text chunk - args.push(x`{ ${attribute.name}: ${attribute.chunks[0].node} }`); + args.push(x`{ ${attribute.name}: ${(attribute.chunks[0] as Expression).node} }`); } else if (attribute.name === 'class' && class_expression) { // Add class expression args.push(x`{ ${attribute.name}: [${get_class_attribute_value(attribute)}, ${class_expression}].join(' ').trim() }`); } else { - args.push(x`{ ${attribute.name}: ${attribute.name === 'class' ? get_class_attribute_value(attribute) : get_attribute_value(attribute, true)} }`); + args.push(x`{ ${attribute.name}: ${attribute.name === 'class' ? get_class_attribute_value(attribute) : get_attribute_value(attribute)} }`); } } }); @@ -138,7 +137,7 @@ export default function(node: Element, renderer: Renderer, options: RenderOption ) { // a boolean attribute with one non-Text chunk renderer.add_string(` `); - renderer.add_expression(x`${attribute.chunks[0].node} ? "${attribute.name}" : ""`); + renderer.add_expression(x`${(attribute.chunks[0] as Expression).node} ? "${attribute.name}" : ""`); } else if (attribute.name === 'class' && class_expression) { add_class_attribute = false; renderer.add_string(` class="`); @@ -146,7 +145,7 @@ export default function(node: Element, renderer: Renderer, options: RenderOption renderer.add_string(`"`); } else if (attribute.chunks.length === 1 && attribute.chunks[0].type !== 'Text') { const { name } = attribute; - const snippet = attribute.chunks[0].node; + const snippet = (attribute.chunks[0] as Expression).node; renderer.add_expression(x`@add_attribute("${name}", ${snippet}, ${boolean_attributes.has(name) ? 1 : 0})`); } else { renderer.add_string(` ${attribute.name}="`); @@ -167,7 +166,9 @@ export default function(node: Element, renderer: Renderer, options: RenderOption // TODO server-render group bindings } else if (contenteditable && (name === 'textContent' || name === 'innerHTML')) { node_contents = expression.node; - value = name === 'textContent' ? x`@escape($$value)` : x`$$value`; + + // TODO where was this used? + // value = name === 'textContent' ? x`@escape($$value)` : x`$$value`; } else if (binding.name === 'value' && node.name === 'textarea') { const snippet = expression.node; node_contents = x`${snippet} || ""`; diff --git a/src/compiler/compile/render_ssr/handlers/InlineComponent.ts b/src/compiler/compile/render_ssr/handlers/InlineComponent.ts index e9ebb189cbfe..5c4d9c73b8a8 100644 --- a/src/compiler/compile/render_ssr/handlers/InlineComponent.ts +++ b/src/compiler/compile/render_ssr/handlers/InlineComponent.ts @@ -1,5 +1,4 @@ import { string_literal } from '../../utils/stringify'; -import { quote_name_if_necessary } from '../../../utils/names'; import Renderer, { RenderOptions } from '../Renderer'; import { get_slot_scope } from './shared/get_slot_scope'; import InlineComponent from '../../nodes/InlineComponent'; diff --git a/src/compiler/compile/render_ssr/handlers/Slot.ts b/src/compiler/compile/render_ssr/handlers/Slot.ts index c8da24cd79ab..9f8d617c531f 100644 --- a/src/compiler/compile/render_ssr/handlers/Slot.ts +++ b/src/compiler/compile/render_ssr/handlers/Slot.ts @@ -4,7 +4,7 @@ import Slot from '../../nodes/Slot'; import { x } from 'code-red'; export default function(node: Slot, renderer: Renderer, options: RenderOptions) { - const slot_data = get_slot_data(node.values, true); + const slot_data = get_slot_data(node.values); renderer.push(); renderer.render(node.children, options); diff --git a/src/compiler/compile/render_ssr/index.ts b/src/compiler/compile/render_ssr/index.ts index 7a7796ed29e2..f63b73d56484 100644 --- a/src/compiler/compile/render_ssr/index.ts +++ b/src/compiler/compile/render_ssr/index.ts @@ -6,6 +6,7 @@ import Renderer from './Renderer'; import { INode as TemplateNode } from '../nodes/interfaces'; // TODO import Text from '../nodes/Text'; import { extract_names } from '../utils/scope'; +import { LabeledStatement, Statement, ExpressionStatement, AssignmentExpression } from 'estree'; export default function ssr( component: Component, @@ -72,7 +73,9 @@ export default function ssr( : []; const reactive_declarations = component.reactive_declarations.map(d => { - let statement = b`${d.node.body}`; + const body: Statement = (d.node as LabeledStatement).body; + + let statement = b`${body}`; if (d.declaration) { const declared = extract_names(d.declaration); @@ -90,12 +93,14 @@ export default function ssr( declared.length > injected.length ); + const { left, right } = (body as ExpressionStatement).expression as AssignmentExpression; + statement = separate ? b` ${injected.map(name => b`let ${name};`)} ${statement}` : b` - let ${d.node.body.expression.left} = ${d.node.body.expression.right}`; + let ${left} = ${right}`; } } diff --git a/src/compiler/compile/utils/get_slot_data.ts b/src/compiler/compile/utils/get_slot_data.ts index c81dc83c92a4..936dc85977cf 100644 --- a/src/compiler/compile/utils/get_slot_data.ts +++ b/src/compiler/compile/utils/get_slot_data.ts @@ -2,7 +2,7 @@ import Attribute from '../nodes/Attribute'; import { p, x } from 'code-red'; import { string_literal } from './stringify'; -export default function get_slot_data(values: Map, is_ssr: boolean) { +export default function get_slot_data(values: Map) { return { type: 'ObjectExpression', properties: Array.from(values.values()) diff --git a/src/compiler/utils/names.ts b/src/compiler/utils/names.ts index 7796e5a11b49..5015c22f8f11 100644 --- a/src/compiler/utils/names.ts +++ b/src/compiler/utils/names.ts @@ -117,16 +117,6 @@ export function is_valid(str: string): boolean { return true; } -export function quote_name_if_necessary(name: string) { - if (!is_valid(name)) return `"${name}"`; - return name; -} - -export function quote_prop_if_necessary(name: string) { - if (!is_valid(name)) return `["${name}"]`; - return `.${name}`; -} - export function sanitize(name: string) { return name .replace(/[^a-zA-Z0-9_]+/g, '_') From 7cbb65878b76106b14074e6e0f495adb108bbf6b Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Mon, 14 Oct 2019 08:12:17 -0400 Subject: [PATCH 90/93] get lint check to pass --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 515ef716e7e3..786870024611 100644 --- a/package.json +++ b/package.json @@ -30,12 +30,12 @@ "coverage": "c8 report --reporter=text-lcov > coverage.lcov && c8 report --reporter=html", "codecov": "codecov", "precodecov": "npm run coverage", - "build": "rollup -c", + "build": "rollup -c && npm run tsd", "prepare": "npm run build", "dev": "rollup -cw", "pretest": "npm run build", "posttest": "agadoo internal/index.mjs", - "prepublishOnly": "npm run lint && npm run tsd && PUBLISH=true npm test", + "prepublishOnly": "npm run lint && PUBLISH=true npm test", "tsd": "tsc -p src/compiler --emitDeclarationOnly && tsc -p src/runtime --emitDeclarationOnly", "lint": "eslint \"{src,test}/**/*.{ts,js}\"" }, From 0982fea5acd1d32c73317f697c943f3cb93ebfe4 Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Mon, 14 Oct 2019 08:46:51 -0400 Subject: [PATCH 91/93] delete some junk --- src/compiler/compile/Component.ts | 17 ---------------- src/compiler/compile/create_module.ts | 12 +++++------ src/compiler/compile/nodes/Attribute.ts | 4 ---- src/compiler/compile/nodes/Binding.ts | 18 ----------------- .../compile/nodes/shared/Expression.ts | 20 ++----------------- src/compiler/compile/render_ssr/index.ts | 11 +++++----- .../compile/utils/flatten_reference.ts | 5 ----- test/runtime/index.js | 1 - 8 files changed, 12 insertions(+), 76 deletions(-) diff --git a/src/compiler/compile/Component.ts b/src/compiler/compile/Component.ts index 032358b151c8..6e4b09c77390 100644 --- a/src/compiler/compile/Component.ts +++ b/src/compiler/compile/Component.ts @@ -260,18 +260,8 @@ export default class Component { walk(program, { enter: (node, parent, key) => { - if (node.type === 'Identifier' && !('name' in node)) { - console.log(node); - throw new Error('this should never happen'); // TODO remove once satisfied - } - if (node.type === 'Identifier') { if (node.name[0] === '@') { - // TODO temp - if (!/@\w+$/.test(node.name)) { - throw new Error(`wut "${node.name}"`); - } - if (node.name[1] === '_') { const alias = this.global(node.name.slice(2)); node.name = alias.name; @@ -303,11 +293,6 @@ export default class Component { parent.property = literal; parent.computed = true; } - - else { - console.log(node); - throw new Error('this should never happen'); // TODO remove once satisfied - } } } } @@ -853,8 +838,6 @@ export default class Component { if (node.type === 'VariableDeclaration') { if (node.kind === 'var' || scope === instance_scope) { node.declarations.forEach(declarator => { - // const next = node.declarations[i + 1]; - if (declarator.id.type !== 'Identifier') { const inserts = []; diff --git a/src/compiler/compile/create_module.ts b/src/compiler/compile/create_module.ts index df85c276ea11..76e68e758f9c 100644 --- a/src/compiler/compile/create_module.ts +++ b/src/compiler/compile/create_module.ts @@ -23,10 +23,8 @@ export default function create_module( ) { const internal_path = `${sveltePath}/internal`; - helpers.sort((a, b) => { - if (a.name < b.name) return -1; - return 1; - }); + helpers.sort((a, b) => (a.name < b.name) ? -1 : 1); + globals.sort((a, b) => (a.name < b.name) ? -1 : 1); if (format === 'esm') { return esm(program, name, banner, sveltePath, internal_path, helpers, globals, imports, module_exports); @@ -71,7 +69,7 @@ function esm( type: 'VariableDeclarator', id: { type: 'ObjectPattern', - properties: globals.sort((a, b) => a.name < b.name ? -1 : 1).map(g => ({ + properties: globals.map(g => ({ type: 'Property', method: false, shorthand: false, @@ -129,7 +127,7 @@ function cjs( type: 'VariableDeclarator', id: { type: 'ObjectPattern', - properties: helpers.sort((a, b) => a.name < b.name ? -1 : 1).map(h => ({ + properties: helpers.map(h => ({ type: 'Property', method: false, shorthand: false, @@ -150,7 +148,7 @@ function cjs( type: 'VariableDeclarator', id: { type: 'ObjectPattern', - properties: globals.sort((a, b) => a.name < b.name ? -1 : 1).map(g => ({ + properties: globals.map(g => ({ type: 'Property', method: false, shorthand: false, diff --git a/src/compiler/compile/nodes/Attribute.ts b/src/compiler/compile/nodes/Attribute.ts index 5bedc2183860..c09f9c307449 100644 --- a/src/compiler/compile/nodes/Attribute.ts +++ b/src/compiler/compile/nodes/Attribute.ts @@ -20,8 +20,6 @@ export default class Attribute extends Node { is_spread: boolean; is_true: boolean; is_static: boolean; - // TODO apparently unnecessary? - // is_synthetic: boolean; expression?: Expression; chunks: Array; dependencies: Set; @@ -34,7 +32,6 @@ export default class Attribute extends Node { this.name = null; this.is_spread = true; this.is_true = false; - // this.is_synthetic = false; this.expression = new Expression(component, this, scope, info.expression); this.dependencies = this.expression.dependencies; @@ -47,7 +44,6 @@ export default class Attribute extends Node { this.name = info.name; this.is_true = info.value === true; this.is_static = true; - // this.is_synthetic = info.synthetic; this.dependencies = new Set(); diff --git a/src/compiler/compile/nodes/Binding.ts b/src/compiler/compile/nodes/Binding.ts index 8fc983254b03..969232a17c30 100644 --- a/src/compiler/compile/nodes/Binding.ts +++ b/src/compiler/compile/nodes/Binding.ts @@ -5,7 +5,6 @@ import Component from '../Component'; import TemplateScope from './shared/TemplateScope'; import {dimensions} from "../../utils/patterns"; import { Node as ESTreeNode } from 'estree'; -import { x } from 'code-red'; // TODO this should live in a specific binding const read_only_media_attributes = new Set([ @@ -21,8 +20,6 @@ export default class Binding extends Node { expression: Expression; raw_expression: ESTreeNode; // TODO exists only for bind:this — is there a more elegant solution? is_contextual: boolean; - obj: string; - prop: string; is_readonly: boolean; constructor(component: Component, parent, scope: TemplateScope, info) { @@ -39,9 +36,6 @@ export default class Binding extends Node { this.expression = new Expression(component, this, scope, info.expression); this.raw_expression = JSON.parse(JSON.stringify(info.expression)); - let obj; - let prop; - const { name } = get_object(this.expression.node); this.is_contextual = scope.names.has(name); @@ -67,18 +61,6 @@ export default class Binding extends Node { variable[this.expression.node.type === 'MemberExpression' ? 'mutated' : 'reassigned'] = true; } - if (this.expression.node.type === 'MemberExpression') { - prop = `[✂${this.expression.node.property.start}-${this.expression.node.property.end}✂]`; - if (!this.expression.node.computed) prop = `'${prop}'`; - obj = `[✂${this.expression.node.object.start}-${this.expression.node.object.end}✂]`; - } else { - obj = x`#ctx`; - prop = x`'${name}'`; - } - - this.obj = obj; - this.prop = prop; - const type = parent.get_static_attribute_value('type'); this.is_readonly = ( diff --git a/src/compiler/compile/nodes/shared/Expression.ts b/src/compiler/compile/nodes/shared/Expression.ts index 99d063a98d65..f69ff074105a 100644 --- a/src/compiler/compile/nodes/shared/Expression.ts +++ b/src/compiler/compile/nodes/shared/Expression.ts @@ -9,7 +9,7 @@ import TemplateScope from './TemplateScope'; import get_object from '../../utils/get_object'; import Block from '../../render_dom/Block'; import is_dynamic from '../../render_dom/wrappers/shared/is_dynamic'; -import { x, b } from 'code-red'; +import { x, b, p } from 'code-red'; import { invalidate } from '../../utils/invalidate'; import { Node, FunctionExpression } from 'estree'; import { TemplateNode } from '../../../interfaces'; @@ -29,9 +29,6 @@ export default class Expression { scope: Scope; scope_map: WeakMap; - // TODO apparently unnecessary? - // is_synthetic: boolean; - declarations: Array<(Node | Node[])> = []; uses_context = false; @@ -49,8 +46,6 @@ export default class Expression { this.node = info; this.template_scope = template_scope; this.owner = owner; - // @ts-ignore - // this.is_synthetic = owner.is_synthetic; const { dependencies, contextual_dependencies } = this; @@ -253,7 +248,6 @@ export default class Expression { if (dependencies.size === 0 && contextual_dependencies.size === 0) { // we can hoist this out of the component completely component.fully_hoisted.push(declaration); - // node.name = id; this.replace(id as any); @@ -268,7 +262,6 @@ export default class Expression { else if (contextual_dependencies.size === 0) { // function can be hoisted inside the component init component.partly_hoisted.push(declaration); - // node.name = id; this.replace(x`#ctx.${id}` as any); @@ -283,19 +276,10 @@ export default class Expression { // we need a combo block/init recipe (node as FunctionExpression).params.unshift({ type: 'ObjectPattern', - properties: Array.from(contextual_dependencies).map(name => ({ - type: 'Property', - kind: 'init', - method: false, - shorthand: false, - computed: false, - key: { type: 'Identifier', name }, - value: { type: 'Identifier', name } - })) + properties: Array.from(contextual_dependencies).map(name => p`${name}` as any) }); component.partly_hoisted.push(declaration); - // node.name = id; this.replace(id as any); diff --git a/src/compiler/compile/render_ssr/index.ts b/src/compiler/compile/render_ssr/index.ts index f63b73d56484..e20e95dbd425 100644 --- a/src/compiler/compile/render_ssr/index.ts +++ b/src/compiler/compile/render_ssr/index.ts @@ -46,9 +46,6 @@ export default function ssr( }) .filter(Boolean); - // TODO remove this, just use component.vars everywhere - const props = component.vars.filter(variable => !variable.module && variable.export_name); - component.rewrite_props(({ name }) => { const value = `$${name}`; @@ -67,9 +64,11 @@ export default function ssr( // TODO only do this for props with a default value const parent_bindings = instance_javascript - ? props.map(prop => { - return b`if ($$props.${prop.export_name} === void 0 && $$bindings.${prop.export_name} && ${prop.name} !== void 0) $$bindings.${prop.export_name}(${prop.name});`; - }) + ? component.vars + .filter(variable => !variable.module && variable.export_name) + .map(prop => { + return b`if ($$props.${prop.export_name} === void 0 && $$bindings.${prop.export_name} && ${prop.name} !== void 0) $$bindings.${prop.export_name}(${prop.name});`; + }) : []; const reactive_declarations = component.reactive_declarations.map(d => { diff --git a/src/compiler/compile/utils/flatten_reference.ts b/src/compiler/compile/utils/flatten_reference.ts index 9ea42fd00a31..e0d05ee7c444 100644 --- a/src/compiler/compile/utils/flatten_reference.ts +++ b/src/compiler/compile/utils/flatten_reference.ts @@ -1,11 +1,6 @@ import { Node, Identifier } from 'estree'; export default function flatten_reference(node: Node) { - // TODO temporary (#3539) - if ((node as any).type === 'Expression') { - throw new Error('flatten_reference bad'); - } - const nodes = []; const parts = []; diff --git a/test/runtime/index.js b/test/runtime/index.js index 22ffcc36b308..646eeb99b6c5 100644 --- a/test/runtime/index.js +++ b/test/runtime/index.js @@ -65,7 +65,6 @@ describe("runtime", () => { unhandled_rejection = null; - config.preserveIdentifiers = true; // TODO remove later compile = (config.preserveIdentifiers ? svelte : svelte$).compile; const cwd = path.resolve(`test/runtime/samples/${dir}`); From 76053cf1003fed832b5aad795af93cc16689d35c Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Mon, 14 Oct 2019 09:13:11 -0400 Subject: [PATCH 92/93] remove more junk --- src/compiler/compile/Component.ts | 11 ++-- src/compiler/compile/nodes/Element.ts | 1 - src/compiler/compile/render_dom/Block.ts | 15 ------ src/compiler/compile/render_dom/index.ts | 10 ++-- .../compile/render_dom/wrappers/AwaitBlock.ts | 3 -- .../compile/render_ssr/handlers/Element.ts | 14 ----- src/compiler/compile/render_ssr/index.ts | 10 ++-- src/compiler/compile/utils/deindent.ts | 53 ------------------- test/helpers.js | 41 -------------- 9 files changed, 10 insertions(+), 148 deletions(-) delete mode 100644 src/compiler/compile/utils/deindent.ts diff --git a/src/compiler/compile/Component.ts b/src/compiler/compile/Component.ts index 6e4b09c77390..aad7cfe69e8f 100644 --- a/src/compiler/compile/Component.ts +++ b/src/compiler/compile/Component.ts @@ -233,12 +233,6 @@ export default class Component { return this.aliases.get(name); } - helper(name: string) { - const alias = this.alias(name); - this.helpers.set(name, alias); - return alias; - } - global(name: string) { const alias = this.alias(name); this.globals.set(name, alias); @@ -276,7 +270,8 @@ export default class Component { } } - const alias = this.helper(name); + const alias = this.alias(name); + this.helpers.set(name, alias); node.name = alias.name; } } @@ -303,7 +298,7 @@ export default class Component { ([name, alias]) => name !== alias.name && { name, alias } ).filter(Boolean); if (referenced_globals.length) { - this.helper('globals'); + this.helpers.set('globals', this.alias('globals')); } const imported_helpers = Array.from(this.helpers, ([name, alias]) => ({ name, diff --git a/src/compiler/compile/nodes/Element.ts b/src/compiler/compile/nodes/Element.ts index 7e6aa2804b47..2981741fa06c 100644 --- a/src/compiler/compile/nodes/Element.ts +++ b/src/compiler/compile/nodes/Element.ts @@ -676,7 +676,6 @@ export default class Element extends Node { if (modifier === 'passive') { if (passive_events.has(handler.name)) { - console.log('here', handler.name, handler.can_make_passive); if (handler.can_make_passive) { component.warn(handler, { code: 'redundant-event-modifier', diff --git a/src/compiler/compile/render_dom/Block.ts b/src/compiler/compile/render_dom/Block.ts index fc501143d1d1..f73212f3ba22 100644 --- a/src/compiler/compile/render_dom/Block.ts +++ b/src/compiler/compile/render_dom/Block.ts @@ -130,7 +130,6 @@ export default class Block { const wrapper = this.wrappers[i]; if (!wrapper.var) continue; - // if (wrapper.parent && wrapper.parent.can_use_innerhtml) continue; if (seen.has(wrapper.var.name)) { dupes.add(wrapper.var.name); @@ -375,9 +374,6 @@ export default class Block { d: ${properties.destroy} }`; - // TODO should code-red do this automatically? probably - return_value.properties = return_value.properties.filter(prop => prop.value); - const body = b` ${Array.from(this.variables.values()).map(({ id, init }) => { return init @@ -447,15 +443,4 @@ export default class Block { } } } - - // 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)} - // } - // `; - // } } \ No newline at end of file diff --git a/src/compiler/compile/render_dom/index.ts b/src/compiler/compile/render_dom/index.ts index a972baf5c85a..1186f1b48322 100644 --- a/src/compiler/compile/render_dom/index.ts +++ b/src/compiler/compile/render_dom/index.ts @@ -228,13 +228,11 @@ export default function dom( return b`${`$$subscribe_${name}`}()`; } - const component_subscribe = component.helper('component_subscribe'); - const callback = x`$$value => { ${value} = $$value; $$invalidate('${value}', ${value}) }`; + const callback = x`$$value => { $$invalidate('${value}', ${value} = $$value) }`; - let insert = b`${component_subscribe}($$self, ${name}, $${callback})`; + let insert = b`@component_subscribe($$self, ${name}, $${callback})`; if (component.compile_options.dev) { - const validate_store = component.helper('validate_store'); - insert = b`${validate_store}(${name}, '${name}'); ${insert}`; + insert = b`@validate_store(${name}, '${name}'); ${insert}`; } return insert; @@ -260,7 +258,7 @@ export default function dom( .filter(v => ((v.referenced || v.export_name) && !v.hoistable)) .map(v => p`${v.name}`); - if (uses_props) filtered_declarations.push(p`$$props: $$props = ${component.helper('exclude_internal_props')}($$props)`); + if (uses_props) filtered_declarations.push(p`$$props: $$props = @exclude_internal_props($$props)`); const filtered_props = props.filter(prop => { const variable = component.var_lookup.get(prop.name); diff --git a/src/compiler/compile/render_dom/wrappers/AwaitBlock.ts b/src/compiler/compile/render_dom/wrappers/AwaitBlock.ts index 0497ca5d5630..aa3e775d729f 100644 --- a/src/compiler/compile/render_dom/wrappers/AwaitBlock.ts +++ b/src/compiler/compile/render_dom/wrappers/AwaitBlock.ts @@ -149,9 +149,6 @@ export default class AwaitBlockWrapper extends Wrapper { blocks: ${this.pending.block.has_outro_method && x`[,,,]`} }`; - // TODO move this into code-red - info_props.properties = info_props.properties.filter(prop => prop.value); - block.chunks.init.push(b` let ${info} = ${info_props}; `); diff --git a/src/compiler/compile/render_ssr/handlers/Element.ts b/src/compiler/compile/render_ssr/handlers/Element.ts index 2e24b0e471ad..762152f4d543 100644 --- a/src/compiler/compile/render_ssr/handlers/Element.ts +++ b/src/compiler/compile/render_ssr/handlers/Element.ts @@ -70,20 +70,6 @@ export default function(node: Element, renderer: Renderer, options: RenderOption renderer.add_string(`<${node.name}`); - // if (slot && nearest_inline_component) { - // const slot = node.attributes.find((attribute) => attribute.name === 'slot'); - // const slot_name = (slot.chunks[0] as Text).data; - - // const lets = node.lets; - // const seen = new Set(lets.map(l => l.name.name)); - - // nearest_inline_component.lets.forEach(l => { - // if (!seen.has(l.name.name)) lets.push(l); - // }); - - // options.slot_scopes.set(slot_name, get_slot_scope(node.lets)); - // } - const class_expression = node.classes.length > 0 && node.classes .map((class_directive: Class) => { const { expression, name } = class_directive; diff --git a/src/compiler/compile/render_ssr/index.ts b/src/compiler/compile/render_ssr/index.ts index e20e95dbd425..d193508a89a6 100644 --- a/src/compiler/compile/render_ssr/index.ts +++ b/src/compiler/compile/render_ssr/index.ts @@ -49,12 +49,9 @@ export default function ssr( component.rewrite_props(({ name }) => { const value = `$${name}`; - const get_store_value = component.helper('get_store_value'); - - let insert = b`${value} = ${get_store_value}(${name})`; + let insert = b`${value} = @get_store_value(${name})`; if (component.compile_options.dev) { - const validate_store = component.helper('validate_store'); - insert = b`${validate_store}(${name}, '${name}'); ${insert}`; + insert = b`@validate_store(${name}, '${name}'); ${insert}`; } return insert; @@ -135,8 +132,7 @@ export default function ssr( const store_name = name.slice(1); const store = component.var_lookup.get(store_name); if (store && store.hoistable) { - const get_store_value = component.helper('get_store_value'); - return b`let ${name} = ${get_store_value}(${store_name});`; + return b`let ${name} = @get_store_value(${store_name});`; } return b`let ${name};`; }), diff --git a/src/compiler/compile/utils/deindent.ts b/src/compiler/compile/utils/deindent.ts deleted file mode 100644 index f9fd49ca477b..000000000000 --- a/src/compiler/compile/utils/deindent.ts +++ /dev/null @@ -1,53 +0,0 @@ -const start = /\n(\t+)/; - -export default function deindent( - strings: TemplateStringsArray, - ...values: any[] -) { - const indentation = start.exec(strings[0])[1]; - const pattern = new RegExp(`^${indentation}`, 'gm'); - - let result = strings[0].replace(start, '').replace(pattern, ''); - - let current_indentation = get_current_indentation(result); - - for (let i = 1; i < strings.length; i += 1) { - let expression = values[i - 1]; - const string = strings[i].replace(pattern, ''); - - if (Array.isArray(expression)) { - expression = expression.length ? expression.join('\n') : null; - } - - // discard empty codebuilders - if (expression && expression.is_empty && expression.is_empty()) { - expression = null; - } - - if (expression || expression === '') { - const value = String(expression).replace( - /\n/g, - `\n${current_indentation}` - ); - result += value + string; - } else { - let c = result.length; - while (/\s/.test(result[c - 1])) c -= 1; - result = result.slice(0, c) + string; - } - - current_indentation = get_current_indentation(result); - } - - return result.trim().replace(/\t+$/gm, '').replace(/{\n\n/gm, '{\n'); -} - -function get_current_indentation(str: string) { - let a = str.length; - while (a > 0 && str[a - 1] !== '\n') a -= 1; - - let b = a; - while (b < str.length && /\s/.test(str[b])) b += 1; - - return str.slice(a, b); -} diff --git a/test/helpers.js b/test/helpers.js index 480b28948b40..6ac20eed8be3 100644 --- a/test/helpers.js +++ b/test/helpers.js @@ -199,47 +199,6 @@ export function showOutput(cwd, options = {}, compile = svelte.compile) { }); } -const start = /\n(\t+)/; -export function deindent(strings, ...values) { - const indentation = start.exec(strings[0])[1]; - const pattern = new RegExp(`^${indentation}`, 'gm'); - - let result = strings[0].replace(start, '').replace(pattern, ''); - - let trailingIndentation = getTrailingIndentation(result); - - for (let i = 1; i < strings.length; i += 1) { - let expression = values[i - 1]; - const string = strings[i].replace(pattern, ''); - - if (Array.isArray(expression)) { - expression = expression.length ? expression.join('\n') : null; - } - - if (expression || expression === '') { - const value = String(expression).replace( - /\n/g, - `\n${trailingIndentation}` - ); - result += value + string; - } else { - let c = result.length; - while (/\s/.test(result[c - 1])) c -= 1; - result = result.slice(0, c) + string; - } - - trailingIndentation = getTrailingIndentation(result); - } - - return result.trim().replace(/\t+$/gm, ''); -} - -function getTrailingIndentation(str) { - let i = str.length; - while (str[i - 1] === ' ' || str[i - 1] === '\t') i -= 1; - return str.slice(i, str.length); -} - export function spaces(i) { let result = ''; while (i--) result += ' '; From cbc97795e59563355bed63f5f0ad2fc4e4ddbe2a Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Mon, 14 Oct 2019 09:15:00 -0400 Subject: [PATCH 93/93] remove obsolete estree-walker typing stuff --- rollup.config.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/rollup.config.js b/rollup.config.js index 25cc58104485..4444494a5f9b 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -20,8 +20,6 @@ const ts_plugin = is_publish const external = id => id.startsWith('svelte/'); -// const inlined_estree = fs.readFileSync('./node_modules/estree-walker/index.d.ts', 'utf-8').replace(/declare.*\{((.|[\n\r])+)\}/m, '$1'); -// fs.writeFileSync(`./compiler.d.ts`, `export { compile, parse, preprocess, VERSION } from './types/compiler/index';\n${inlined_estree}`); fs.writeFileSync(`./compiler.d.ts`, `export { compile, parse, preprocess, VERSION } from './types/compiler/index';`); export default [