diff --git a/src/generators/Generator.ts b/src/generators/Generator.ts index 91b73b6162..9c81546b64 100644 --- a/src/generators/Generator.ts +++ b/src/generators/Generator.ts @@ -425,13 +425,19 @@ export default class Generator { getUniqueNameMaker(params: string[]) { const localUsedNames = new Set(params); + + function add(name: string) { + localUsedNames.add(name); + } + + reservedNames.forEach(add); + this.importedNames.forEach(add); + return (name: string) => { if (test) name = `${name}$`; let alias = name; for ( let i = 1; - reservedNames.has(alias) || - this.importedNames.has(alias) || this.usedNames.has(alias) || localUsedNames.has(alias); alias = `${name}_${i++}` diff --git a/src/generators/dom/index.ts b/src/generators/dom/index.ts index 3aa44d8f93..9633eb34a2 100644 --- a/src/generators/dom/index.ts +++ b/src/generators/dom/index.ts @@ -6,6 +6,7 @@ import { walk } from 'estree-walker'; import deindent from '../../utils/deindent'; import { stringify, escape } from '../../utils/stringify'; import CodeBuilder from '../../utils/CodeBuilder'; +import reservedNames from '../../utils/reservedNames'; import visit from './visit'; import shared from './shared'; import Generator from '../Generator'; @@ -15,6 +16,8 @@ import Block from './Block'; import { version } from '../../../package.json'; import { Parsed, CompileOptions, Node } from '../../interfaces'; +const test = typeof global !== 'undefined' && global.__svelte_test; + export class DomGenerator extends Generator { blocks: (Block|string)[]; readonly: Set; @@ -48,6 +51,33 @@ export class DomGenerator extends Generator { // initial values for e.g. window.innerWidth, if there's a <:Window> meta tag this.metaBindings = []; } + + getUniqueNameMaker(params: string[]) { + const localUsedNames = new Set(params); + + function add(name: string) { + localUsedNames.add(name); + } + + reservedNames.forEach(add); + this.importedNames.forEach(add); + for (const name in shared) { + localUsedNames.add(test ? `${name}$` : name); + } + + return (name: string) => { + if (test) name = `${name}$`; + let alias = name; + for ( + let i = 1; + this.usedNames.has(alias) || + localUsedNames.has(alias); + alias = `${name}_${i++}` + ); + localUsedNames.add(alias); + return alias; + }; + } } export default function dom( diff --git a/src/generators/dom/preprocess.ts b/src/generators/dom/preprocess.ts index b993dcb43f..55d428a452 100644 --- a/src/generators/dom/preprocess.ts +++ b/src/generators/dom/preprocess.ts @@ -195,7 +195,7 @@ const preprocessors = { stripWhitespace: boolean, nextSibling: Node ) => { - node.var = block.getUniqueName(`each_block`); + node.var = block.getUniqueName(`each`); const dependencies = block.findDependencies(node.expression); block.addDependencies(dependencies); @@ -206,7 +206,11 @@ const preprocessors = { indexNames.set(node.context, indexName); const listNames = new Map(block.listNames); - const listName = block.getUniqueName(`each_block_value`); + const listName = block.getUniqueName( + (node.expression.type === 'MemberExpression' && !node.expression.computed) ? node.expression.property.name : + node.expression.type === 'Identifier' ? node.expression.name : + `each_value` + ); listNames.set(node.context, listName); const context = generator.getUniqueName(node.context); diff --git a/src/generators/dom/visitors/EachBlock.ts b/src/generators/dom/visitors/EachBlock.ts index 03c0918ce0..330dba6b81 100644 --- a/src/generators/dom/visitors/EachBlock.ts +++ b/src/generators/dom/visitors/EachBlock.ts @@ -14,16 +14,16 @@ export default function visitEachBlock( elementStack: Node[], componentStack: Node[] ) { - const each_block = node.var; + const each = node.var; const create_each_block = node._block.name; const each_block_value = node._block.listName; - const iterations = block.getUniqueName(`${each_block}_iterations`); + const iterations = block.getUniqueName(`${each}_blocks`); const params = block.params.join(', '); const needsAnchor = node.next ? !isDomNode(node.next, generator) : !state.parentNode; const anchor = needsAnchor - ? block.getUniqueName(`${each_block}_anchor`) + ? block.getUniqueName(`${each}_anchor`) : (node.next && node.next.var) || 'null'; // hack the sourcemap, so that if data is missing the bug @@ -35,7 +35,7 @@ export default function visitEachBlock( const mountOrIntro = node._block.hasIntroMethod ? 'intro' : 'mount'; const vars = { - each_block, + each, create_each_block, each_block_value, length, @@ -67,7 +67,7 @@ export default function visitEachBlock( } if (node.else) { - const each_block_else = generator.getUniqueName(`${each_block}_else`); + const each_block_else = generator.getUniqueName(`${each}_else`); block.builders.init.addLine(`var ${each_block_else} = null;`); @@ -144,7 +144,7 @@ function keyed( node: Node, snippet: string, { - each_block, + each, create_each_block, each_block_value, length, @@ -154,11 +154,11 @@ function keyed( } ) { const key = block.getUniqueName('key'); - const lookup = block.getUniqueName(`${each_block}_lookup`); - const iteration = block.getUniqueName(`${each_block}_iteration`); - const head = block.getUniqueName(`${each_block}_head`); - const last = block.getUniqueName(`${each_block}_last`); - const expected = block.getUniqueName(`${each_block}_expected`); + const lookup = block.getUniqueName(`${each}_lookup`); + const iteration = block.getUniqueName(`${each}_iteration`); + const head = block.getUniqueName(`${each}_head`); + const last = block.getUniqueName(`${each}_last`); + const expected = block.getUniqueName(`${each}_expected`); block.addVariable(lookup, `@blankObject()`); block.addVariable(head); @@ -222,7 +222,7 @@ function keyed( let destroy; if (node._block.hasOutroMethod) { - const fn = block.getUniqueName(`${each_block}_outro`); + const fn = block.getUniqueName(`${each}_outro`); block.builders.init.addBlock(deindent` function ${fn}(iteration) { iteration.outro(function() { @@ -246,7 +246,7 @@ function keyed( } `; } else { - const fn = block.getUniqueName(`${each_block}_destroy`); + const fn = block.getUniqueName(`${each}_destroy`); block.builders.init.addBlock(deindent` function ${fn}(iteration) { iteration.unmount(); diff --git a/test/helpers.js b/test/helpers.js index 8958235cda..620e359096 100644 --- a/test/helpers.js +++ b/test/helpers.js @@ -174,10 +174,10 @@ function capitalise(str) { return str[0].toUpperCase() + str.slice(1); } -export function showOutput(cwd, options = {}) { +export function showOutput(cwd, options = {}, s = svelte) { glob.sync('**/*.html', { cwd }).forEach(file => { if (file[0] === '_') return; - const { code } = svelte.compile( + const { code } = s.compile( fs.readFileSync(`${cwd}/${file}`, 'utf-8'), Object.assign(options, { filename: file, diff --git a/test/js/samples/each-block-changed-check/expected-bundle.js b/test/js/samples/each-block-changed-check/expected-bundle.js index 1604c03c6a..e26de86305 100644 --- a/test/js/samples/each-block-changed-check/expected-bundle.js +++ b/test/js/samples/each-block-changed-check/expected-bundle.js @@ -203,18 +203,18 @@ var proto = { function create_main_fragment(state, component) { var text, p, text_1; - var each_block_value = state.comments; + var comments = state.comments; - var each_block_iterations = []; + var each_blocks = []; - for (var i = 0; i < each_block_value.length; i += 1) { - each_block_iterations[i] = create_each_block(state, each_block_value, each_block_value[i], i, component); + for (var i = 0; i < comments.length; i += 1) { + each_blocks[i] = create_each_block(state, comments, comments[i], i, component); } return { create: function() { - for (var i = 0; i < each_block_iterations.length; i += 1) { - each_block_iterations[i].create(); + for (var i = 0; i < each_blocks.length; i += 1) { + each_blocks[i].create(); } text = createText("\n\n"); @@ -223,8 +223,8 @@ function create_main_fragment(state, component) { }, mount: function(target, anchor) { - for (var i = 0; i < each_block_iterations.length; i += 1) { - each_block_iterations[i].mount(target, anchor); + for (var i = 0; i < each_blocks.length; i += 1) { + each_blocks[i].mount(target, anchor); } insertNode(text, target, anchor); @@ -233,24 +233,24 @@ function create_main_fragment(state, component) { }, update: function(changed, state) { - var each_block_value = state.comments; + var comments = state.comments; if (changed.comments || changed.elapsed || changed.time) { - for (var i = 0; i < each_block_value.length; i += 1) { - if (each_block_iterations[i]) { - each_block_iterations[i].update(changed, state, each_block_value, each_block_value[i], i); + for (var i = 0; i < comments.length; i += 1) { + if (each_blocks[i]) { + each_blocks[i].update(changed, state, comments, comments[i], i); } else { - each_block_iterations[i] = create_each_block(state, each_block_value, each_block_value[i], i, component); - each_block_iterations[i].create(); - each_block_iterations[i].mount(text.parentNode, text); + each_blocks[i] = create_each_block(state, comments, comments[i], i, component); + each_blocks[i].create(); + each_blocks[i].mount(text.parentNode, text); } } - for (; i < each_block_iterations.length; i += 1) { - each_block_iterations[i].unmount(); - each_block_iterations[i].destroy(); + for (; i < each_blocks.length; i += 1) { + each_blocks[i].unmount(); + each_blocks[i].destroy(); } - each_block_iterations.length = each_block_value.length; + each_blocks.length = comments.length; } if (changed.foo) { @@ -259,8 +259,8 @@ function create_main_fragment(state, component) { }, unmount: function() { - for (var i = 0; i < each_block_iterations.length; i += 1) { - each_block_iterations[i].unmount(); + for (var i = 0; i < each_blocks.length; i += 1) { + each_blocks[i].unmount(); } detachNode(text); @@ -268,13 +268,13 @@ function create_main_fragment(state, component) { }, destroy: function() { - destroyEach(each_block_iterations, false, 0); + destroyEach(each_blocks, false, 0); } }; } // (1:0) {{#each comments as comment, i}} -function create_each_block(state, each_block_value, comment, i, component) { +function create_each_block(state, comments, comment, i, component) { var div, strong, text, text_1, span, text_2_value = comment.author, text_2, text_3, text_4_value = state.elapsed(comment.time, state.time), text_4, text_5, text_6, raw_value = comment.html, raw_before; return { @@ -313,7 +313,7 @@ function create_each_block(state, each_block_value, comment, i, component) { raw_before.insertAdjacentHTML("afterend", raw_value); }, - update: function(changed, state, each_block_value, comment, i) { + update: function(changed, state, comments, comment, i) { if ((changed.comments) && text_2_value !== (text_2_value = comment.author)) { text_2.data = text_2_value; } diff --git a/test/js/samples/each-block-changed-check/expected.js b/test/js/samples/each-block-changed-check/expected.js index e494471a5f..efc1bfd1dd 100644 --- a/test/js/samples/each-block-changed-check/expected.js +++ b/test/js/samples/each-block-changed-check/expected.js @@ -5,18 +5,18 @@ import { appendNode, assign, createElement, createText, destroyEach, detachAfter function create_main_fragment(state, component) { var text, p, text_1; - var each_block_value = state.comments; + var comments = state.comments; - var each_block_iterations = []; + var each_blocks = []; - for (var i = 0; i < each_block_value.length; i += 1) { - each_block_iterations[i] = create_each_block(state, each_block_value, each_block_value[i], i, component); + for (var i = 0; i < comments.length; i += 1) { + each_blocks[i] = create_each_block(state, comments, comments[i], i, component); } return { create: function() { - for (var i = 0; i < each_block_iterations.length; i += 1) { - each_block_iterations[i].create(); + for (var i = 0; i < each_blocks.length; i += 1) { + each_blocks[i].create(); } text = createText("\n\n"); @@ -25,8 +25,8 @@ function create_main_fragment(state, component) { }, mount: function(target, anchor) { - for (var i = 0; i < each_block_iterations.length; i += 1) { - each_block_iterations[i].mount(target, anchor); + for (var i = 0; i < each_blocks.length; i += 1) { + each_blocks[i].mount(target, anchor); } insertNode(text, target, anchor); @@ -35,24 +35,24 @@ function create_main_fragment(state, component) { }, update: function(changed, state) { - var each_block_value = state.comments; + var comments = state.comments; if (changed.comments || changed.elapsed || changed.time) { - for (var i = 0; i < each_block_value.length; i += 1) { - if (each_block_iterations[i]) { - each_block_iterations[i].update(changed, state, each_block_value, each_block_value[i], i); + for (var i = 0; i < comments.length; i += 1) { + if (each_blocks[i]) { + each_blocks[i].update(changed, state, comments, comments[i], i); } else { - each_block_iterations[i] = create_each_block(state, each_block_value, each_block_value[i], i, component); - each_block_iterations[i].create(); - each_block_iterations[i].mount(text.parentNode, text); + each_blocks[i] = create_each_block(state, comments, comments[i], i, component); + each_blocks[i].create(); + each_blocks[i].mount(text.parentNode, text); } } - for (; i < each_block_iterations.length; i += 1) { - each_block_iterations[i].unmount(); - each_block_iterations[i].destroy(); + for (; i < each_blocks.length; i += 1) { + each_blocks[i].unmount(); + each_blocks[i].destroy(); } - each_block_iterations.length = each_block_value.length; + each_blocks.length = comments.length; } if (changed.foo) { @@ -61,8 +61,8 @@ function create_main_fragment(state, component) { }, unmount: function() { - for (var i = 0; i < each_block_iterations.length; i += 1) { - each_block_iterations[i].unmount(); + for (var i = 0; i < each_blocks.length; i += 1) { + each_blocks[i].unmount(); } detachNode(text); @@ -70,13 +70,13 @@ function create_main_fragment(state, component) { }, destroy: function() { - destroyEach(each_block_iterations, false, 0); + destroyEach(each_blocks, false, 0); } }; } // (1:0) {{#each comments as comment, i}} -function create_each_block(state, each_block_value, comment, i, component) { +function create_each_block(state, comments, comment, i, component) { var div, strong, text, text_1, span, text_2_value = comment.author, text_2, text_3, text_4_value = state.elapsed(comment.time, state.time), text_4, text_5, text_6, raw_value = comment.html, raw_before; return { @@ -115,7 +115,7 @@ function create_each_block(state, each_block_value, comment, i, component) { raw_before.insertAdjacentHTML("afterend", raw_value); }, - update: function(changed, state, each_block_value, comment, i) { + update: function(changed, state, comments, comment, i) { if ((changed.comments) && text_2_value !== (text_2_value = comment.author)) { text_2.data = text_2_value; } diff --git a/test/runtime/index.js b/test/runtime/index.js index 95950b6668..a31f9531f8 100644 --- a/test/runtime/index.js +++ b/test/runtime/index.js @@ -87,7 +87,7 @@ describe("runtime", () => { } } catch (err) { failed.add(dir); - showOutput(cwd, { shared }); // eslint-disable-line no-console + showOutput(cwd, { shared }, svelte); // eslint-disable-line no-console throw err; } } @@ -133,7 +133,7 @@ describe("runtime", () => { try { SvelteComponent = require(`./samples/${dir}/main.html`); } catch (err) { - showOutput(cwd, { shared, hydratable: hydrate }); // eslint-disable-line no-console + showOutput(cwd, { shared, hydratable: hydrate }, svelte); // eslint-disable-line no-console throw err; } @@ -187,12 +187,12 @@ describe("runtime", () => { config.error(assert, err); } else { failed.add(dir); - showOutput(cwd, { shared, hydratable: hydrate }); // eslint-disable-line no-console + showOutput(cwd, { shared, hydratable: hydrate }, svelte); // eslint-disable-line no-console throw err; } } - if (config.show) showOutput(cwd, { shared, hydratable: hydrate }); + if (config.show) showOutput(cwd, { shared, hydratable: hydrate }, svelte); }); }