diff --git a/src/generators/dom/Block.ts b/src/generators/dom/Block.ts index f706a48807..47cf59e0ce 100644 --- a/src/generators/dom/Block.ts +++ b/src/generators/dom/Block.ts @@ -367,6 +367,8 @@ export default class Block { ${properties} }; } - `; + `.replace(/(\\)?#(\w*)/g, (match, escaped, name) => { + return escaped ? match.slice(1) : this.alias(name); + }); } } diff --git a/src/generators/dom/index.ts b/src/generators/dom/index.ts index 7dd1e04656..6916e3b3e9 100644 --- a/src/generators/dom/index.ts +++ b/src/generators/dom/index.ts @@ -4,6 +4,7 @@ import annotateWithScopes from '../../utils/annotateWithScopes'; import isReference from '../../utils/isReference'; import { walk } from 'estree-walker'; import deindent from '../../utils/deindent'; +import stringify from '../../utils/stringify'; import CodeBuilder from '../../utils/CodeBuilder'; import visit from './visit'; import shared from './shared'; @@ -135,7 +136,7 @@ export default function dom( function @add_css () { var style = @createElement( 'style' ); style.id = '${generator.cssId}-style'; - style.textContent = ${JSON.stringify(generator.css)}; + style.textContent = ${stringify(generator.css)}; @appendNode( style, document.head ); } `); @@ -199,9 +200,7 @@ export default function dom( this._torndown = false; ${generator.css && options.css !== false && - `if ( !document.getElementById( ${JSON.stringify( - generator.cssId + '-style' - )} ) ) @add_css();`} + `if ( !document.getElementById( '${generator.cssId}-style' ) ) @add_css();`} ${(generator.hasComponents || generator.hasIntroTransitions) && `this._renderHooks = [];`} ${generator.hasComplexBindings && `this._bindings = [];`} @@ -280,7 +279,7 @@ export default function dom( : name; }); - result = `import { ${names.join(', ')} } from ${JSON.stringify(sharedPath)};\n\n` + result; + result = `import { ${names.join(', ')} } from ${stringify(sharedPath)};\n\n` + result; } else { usedHelpers.forEach(key => { const str = shared[key]; diff --git a/src/generators/dom/visitors/Component/Attribute.ts b/src/generators/dom/visitors/Component/Attribute.ts index 5549931864..35cabec66a 100644 --- a/src/generators/dom/visitors/Component/Attribute.ts +++ b/src/generators/dom/visitors/Component/Attribute.ts @@ -2,6 +2,7 @@ import { DomGenerator } from '../../index'; import Block from '../../Block'; import { Node } from '../../../../interfaces'; import { State } from '../../interfaces'; +import stringify from '../../../../utils/stringify'; export default function visitAttribute( generator: DomGenerator, @@ -28,7 +29,7 @@ export default function visitAttribute( if (value.type === 'Text') { // static attributes const result = isNaN(value.data) - ? JSON.stringify(value.data) + ? stringify(value.data) : value.data; local.staticAttributes.push({ name: attribute.name, @@ -54,7 +55,7 @@ export default function visitAttribute( attribute.value .map(chunk => { if (chunk.type === 'Text') { - return JSON.stringify(chunk.data); + return stringify(chunk.data); } else { const { dependencies, snippet } = block.contextualise( chunk.expression diff --git a/src/generators/dom/visitors/EachBlock.ts b/src/generators/dom/visitors/EachBlock.ts index aab9372725..ef4e52ce3d 100644 --- a/src/generators/dom/visitors/EachBlock.ts +++ b/src/generators/dom/visitors/EachBlock.ts @@ -15,7 +15,6 @@ export default function visitEachBlock( const create_each_block = node._block.name; const each_block_value = node._block.listName; const iterations = block.getUniqueName(`${each_block}_iterations`); - const i = block.alias(`i`); const params = block.params.join(', '); const anchor = node.needsAnchor ? block.getUniqueName(`${each_block}_anchor`) @@ -27,7 +26,6 @@ export default function visitEachBlock( create_each_block, each_block_value, iterations, - i, params, anchor, mountOrIntro, @@ -138,7 +136,6 @@ function keyed( each_block, create_each_block, each_block_value, - i, params, anchor, mountOrIntro, @@ -170,15 +167,15 @@ function keyed( } block.builders.init.addBlock(deindent` - for ( var ${i} = 0; ${i} < ${each_block_value}.length; ${i} += 1 ) { - var ${key} = ${each_block_value}[${i}].${node.key}; - var ${iteration} = ${lookup}[${key}] = ${create_each_block}( ${params}, ${each_block_value}, ${each_block_value}[${i}], ${i}, ${block.component}, ${key} ); + for ( var #i = 0; #i < ${each_block_value}.length; #i += 1 ) { + var ${key} = ${each_block_value}[#i].${node.key}; + var ${iteration} = ${lookup}[${key}] = ${create_each_block}( ${params}, ${each_block_value}, ${each_block_value}[#i], #i, ${block.component}, ${key} ); if ( ${last} ) ${last}.next = ${iteration}; ${iteration}.last = ${last}; ${last} = ${iteration}; - if ( ${i} === 0 ) ${head} = ${iteration}; + if ( #i === 0 ) ${head} = ${iteration}; } `); @@ -231,9 +228,9 @@ function keyed( ${expected} = ${expected}.next; } - for ( ${i} = 0; ${i} < discard_pile.length; ${i} += 1 ) { - if ( discard_pile[${i}].discard ) { - ${fn}( discard_pile[${i}] ); + for ( #i = 0; #i < discard_pile.length; #i += 1 ) { + if ( discard_pile[#i].discard ) { + ${fn}( discard_pile[#i] ); } } `; @@ -253,8 +250,8 @@ function keyed( ${expected} = ${expected}.next; } - for ( ${i} = 0; ${i} < discard_pile.length; ${i} += 1 ) { - var ${iteration} = discard_pile[${i}]; + for ( #i = 0; #i < discard_pile.length; #i += 1 ) { + var ${iteration} = discard_pile[#i]; if ( ${iteration}.discard ) { ${fn}( ${iteration} ); } @@ -270,12 +267,12 @@ function keyed( var discard_pile = []; - for ( ${i} = 0; ${i} < ${each_block_value}.length; ${i} += 1 ) { - var ${key} = ${each_block_value}[${i}].${node.key}; + for ( #i = 0; #i < ${each_block_value}.length; #i += 1 ) { + var ${key} = ${each_block_value}[#i].${node.key}; var ${iteration} = ${lookup}[${key}]; ${dynamic && - `if ( ${iteration} ) ${iteration}.update( changed, ${params}, ${each_block_value}, ${each_block_value}[${i}], ${i} );`} + `if ( ${iteration} ) ${iteration}.update( changed, ${params}, ${each_block_value}, ${each_block_value}[#i], #i );`} if ( ${expected} ) { if ( ${key} === ${expected}.key ) { @@ -296,7 +293,7 @@ function keyed( if (!${expected}) ${iteration}.mount( ${parentNode}, ${anchor} ); } else { // key is being inserted - ${iteration} = ${lookup}[${key}] = ${create_each_block}( ${params}, ${each_block_value}, ${each_block_value}[${i}], ${i}, ${block.component}, ${key} ); + ${iteration} = ${lookup}[${key}] = ${create_each_block}( ${params}, ${each_block_value}, ${each_block_value}[#i], #i, ${block.component}, ${key} ); ${iteration}.create(); ${iteration}.${mountOrIntro}( ${parentNode}, ${expected}.first ); @@ -311,7 +308,7 @@ function keyed( ${iteration}.next = null; ${iteration}.mount( ${parentNode}, ${anchor} ); } else { - ${iteration} = ${lookup}[${key}] = ${create_each_block}( ${params}, ${each_block_value}, ${each_block_value}[${i}], ${i}, ${block.component}, ${key} ); + ${iteration} = ${lookup}[${key}] = ${create_each_block}( ${params}, ${each_block_value}, ${each_block_value}[#i], #i, ${block.component}, ${key} ); ${iteration}.create(); ${iteration}.${mountOrIntro}( ${parentNode}, ${anchor} ); } @@ -360,7 +357,6 @@ function unkeyed( create_each_block, each_block_value, iterations, - i, params, anchor, mountOrIntro, @@ -369,8 +365,8 @@ function unkeyed( block.builders.init.addBlock(deindent` var ${iterations} = []; - for ( var ${i} = 0; ${i} < ${each_block_value}.length; ${i} += 1 ) { - ${iterations}[${i}] = ${create_each_block}( ${params}, ${each_block_value}, ${each_block_value}[${i}], ${i}, ${block.component} ); + for ( var #i = 0; #i < ${each_block_value}.length; #i += 1 ) { + ${iterations}[#i] = ${create_each_block}( ${params}, ${each_block_value}, ${each_block_value}[#i], #i, ${block.component} ); } `); @@ -378,20 +374,20 @@ function unkeyed( const anchorNode = state.parentNode ? 'null' : 'anchor'; block.builders.create.addBlock(deindent` - for ( var ${i} = 0; ${i} < ${iterations}.length; ${i} += 1 ) { - ${iterations}[${i}].create(); + for ( var #i = 0; #i < ${iterations}.length; #i += 1 ) { + ${iterations}[#i].create(); } `); block.builders.claim.addBlock(deindent` - for ( var ${i} = 0; ${i} < ${iterations}.length; ${i} += 1 ) { - ${iterations}[${i}].claim( ${state.parentNodes} ); + for ( var #i = 0; #i < ${iterations}.length; #i += 1 ) { + ${iterations}[#i].claim( ${state.parentNodes} ); } `); block.builders.mount.addBlock(deindent` - for ( var ${i} = 0; ${i} < ${iterations}.length; ${i} += 1 ) { - ${iterations}[${i}].${mountOrIntro}( ${targetNode}, ${anchorNode} ); + for ( var #i = 0; #i < ${iterations}.length; #i += 1 ) { + ${iterations}[#i].${mountOrIntro}( ${targetNode}, ${anchorNode} ); } `); @@ -412,26 +408,26 @@ function unkeyed( const forLoopBody = node._block.hasUpdateMethod ? node._block.hasIntroMethod ? deindent` - if ( ${iterations}[${i}] ) { - ${iterations}[${i}].update( changed, ${params}, ${each_block_value}, ${each_block_value}[${i}], ${i} ); + if ( ${iterations}[#i] ) { + ${iterations}[#i].update( changed, ${params}, ${each_block_value}, ${each_block_value}[#i], #i ); } else { - ${iterations}[${i}] = ${create_each_block}( ${params}, ${each_block_value}, ${each_block_value}[${i}], ${i}, ${block.component} ); - ${iterations}[${i}].create(); + ${iterations}[#i] = ${create_each_block}( ${params}, ${each_block_value}, ${each_block_value}[#i], #i, ${block.component} ); + ${iterations}[#i].create(); } - ${iterations}[${i}].intro( ${parentNode}, ${anchor} ); + ${iterations}[#i].intro( ${parentNode}, ${anchor} ); ` : deindent` - if ( ${iterations}[${i}] ) { - ${iterations}[${i}].update( changed, ${params}, ${each_block_value}, ${each_block_value}[${i}], ${i} ); + if ( ${iterations}[#i] ) { + ${iterations}[#i].update( changed, ${params}, ${each_block_value}, ${each_block_value}[#i], #i ); } else { - ${iterations}[${i}] = ${create_each_block}( ${params}, ${each_block_value}, ${each_block_value}[${i}], ${i}, ${block.component} ); - ${iterations}[${i}].create(); - ${iterations}[${i}].mount( ${parentNode}, ${anchor} ); + ${iterations}[#i] = ${create_each_block}( ${params}, ${each_block_value}, ${each_block_value}[#i], #i, ${block.component} ); + ${iterations}[#i].create(); + ${iterations}[#i].mount( ${parentNode}, ${anchor} ); } ` : deindent` - ${iterations}[${i}] = ${create_each_block}( ${params}, ${each_block_value}, ${each_block_value}[${i}], ${i}, ${block.component} ); - ${iterations}[${i}].${mountOrIntro}( ${parentNode}, ${anchor} ); + ${iterations}[#i] = ${create_each_block}( ${params}, ${each_block_value}, ${each_block_value}[#i], #i, ${block.component} ); + ${iterations}[#i].${mountOrIntro}( ${parentNode}, ${anchor} ); `; const start = node._block.hasUpdateMethod ? '0' : `${iterations}.length`; @@ -449,12 +445,12 @@ function unkeyed( } } - for ( ; ${i} < ${iterations}.length; ${i} += 1 ) ${outro}( ${i} ); + for ( ; #i < ${iterations}.length; #i += 1 ) ${outro}( #i ); ` : deindent` - for ( ; ${i} < ${iterations}.length; ${i} += 1 ) { - ${iterations}[${i}].unmount(); - ${iterations}[${i}].destroy(); + for ( ; #i < ${iterations}.length; #i += 1 ) { + ${iterations}[#i].unmount(); + ${iterations}[#i].destroy(); } ${iterations}.length = ${each_block_value}.length; `; @@ -463,7 +459,7 @@ function unkeyed( var ${each_block_value} = ${snippet}; if ( ${condition} ) { - for ( var ${i} = ${start}; ${i} < ${each_block_value}.length; ${i} += 1 ) { + for ( var #i = ${start}; #i < ${each_block_value}.length; #i += 1 ) { ${forLoopBody} } @@ -473,8 +469,8 @@ function unkeyed( } block.builders.unmount.addBlock(deindent` - for ( var ${i} = 0; ${i} < ${iterations}.length; ${i} += 1 ) { - ${iterations}[${i}].unmount(); + for ( var #i = 0; #i < ${iterations}.length; #i += 1 ) { + ${iterations}[#i].unmount(); } `); diff --git a/src/generators/dom/visitors/Element/Attribute.ts b/src/generators/dom/visitors/Element/Attribute.ts index a3e21953d7..f2951cb750 100644 --- a/src/generators/dom/visitors/Element/Attribute.ts +++ b/src/generators/dom/visitors/Element/Attribute.ts @@ -1,5 +1,6 @@ import attributeLookup from './lookup'; import deindent from '../../../../utils/deindent'; +import stringify from '../../../../utils/stringify'; import getStaticAttributeValue from './getStaticAttributeValue'; import { DomGenerator } from '../../index'; import Block from '../../Block'; @@ -57,7 +58,7 @@ export default function visitAttribute( attribute.value .map((chunk: Node) => { if (chunk.type === 'Text') { - return JSON.stringify(chunk.data); + return stringify(chunk.data); } else { const { snippet } = block.contextualise(chunk.expression); return `( ${snippet} )`; @@ -127,7 +128,7 @@ export default function visitAttribute( ? 'true' : attribute.value.length === 0 ? `''` - : JSON.stringify(attribute.value[0].data); + : stringify(attribute.value[0].data); const statement = propertyName ? `${state.parentNode}.${propertyName} = ${value};` diff --git a/src/generators/dom/visitors/Element/Binding.ts b/src/generators/dom/visitors/Element/Binding.ts index 185996b898..d13b7ffdb0 100644 --- a/src/generators/dom/visitors/Element/Binding.ts +++ b/src/generators/dom/visitors/Element/Binding.ts @@ -57,7 +57,7 @@ export default function visitBinding( value, }); let updateElement = `${state.parentNode}.${attribute.name} = ${snippet};`; - const lock = block.alias(`${state.parentNode}_updating`); + const lock = `#${state.parentNode}_updating`; let updateCondition = `!${lock}`; block.addVariable(lock, 'false'); @@ -69,7 +69,6 @@ export default function visitBinding( } const value = block.getUniqueName('value'); - const i = block.alias('i'); const option = block.getUniqueName('option'); const ifStatement = isMultipleSelect @@ -83,8 +82,8 @@ export default function visitBinding( updateElement = deindent` var ${value} = ${snippet}; - for ( var ${i} = 0; ${i} < ${state.parentNode}.options.length; ${i} += 1 ) { - var ${option} = ${state.parentNode}.options[${i}]; + for ( var #i = 0; #i < ${state.parentNode}.options.length; #i += 1 ) { + var ${option} = ${state.parentNode}.options[#i]; ${ifStatement} } diff --git a/src/generators/dom/visitors/Element/addTransitions.ts b/src/generators/dom/visitors/Element/addTransitions.ts index 238831c04b..0681fcc154 100644 --- a/src/generators/dom/visitors/Element/addTransitions.ts +++ b/src/generators/dom/visitors/Element/addTransitions.ts @@ -34,7 +34,7 @@ export default function addTransitions( block.builders.outro.addBlock(deindent` ${name}.run( false, function () { ${block.component}.fire( 'outro.end', { node: ${state.name} }); - if ( --${block.alias('outros')} === 0 ) ${block.alias('outrocallback')}(); + if ( --#outros === 0 ) #outrocallback(); ${name} = null; }); `); @@ -81,7 +81,7 @@ export default function addTransitions( ${outroName} = @wrapTransition( ${state.name}, ${fn}, ${snippet}, false, null ); ${outroName}.run( false, function () { ${block.component}.fire( 'outro.end', { node: ${state.name} }); - if ( --${block.alias('outros')} === 0 ) ${block.alias('outrocallback')}(); + if ( --#outros === 0 ) #outrocallback(); }); `); } diff --git a/src/generators/dom/visitors/Text.ts b/src/generators/dom/visitors/Text.ts index 7d4eaba770..9231073167 100644 --- a/src/generators/dom/visitors/Text.ts +++ b/src/generators/dom/visitors/Text.ts @@ -2,6 +2,7 @@ import { DomGenerator } from '../index'; import Block from '../Block'; import { Node } from '../../../interfaces'; import { State } from '../interfaces'; +import stringify from '../../../utils/stringify'; export default function visitText( generator: DomGenerator, @@ -12,8 +13,8 @@ export default function visitText( if (!node._state.shouldCreate) return; block.addElement( node._state.name, - `@createText( ${JSON.stringify(node.data)} )`, - generator.hydratable ? `@claimText( ${state.parentNodes}, ${JSON.stringify(node.data)} )` : '', + `@createText( ${stringify(node.data)} )`, + generator.hydratable ? `@claimText( ${state.parentNodes}, ${stringify(node.data)} )` : '', state.parentNode, node.usedAsAnchor ); diff --git a/src/generators/dom/visitors/shared/binding/getSetter.ts b/src/generators/dom/visitors/shared/binding/getSetter.ts index 679d9005f6..e6a75dfeec 100644 --- a/src/generators/dom/visitors/shared/binding/getSetter.ts +++ b/src/generators/dom/visitors/shared/binding/getSetter.ts @@ -33,8 +33,6 @@ export default function getSetter({ } if (attribute.value.type === 'MemberExpression') { - const alias = block.alias(name); - return deindent` var state = ${block.component}.get(); ${snippet} = ${value}; diff --git a/src/generators/server-side-rendering/index.ts b/src/generators/server-side-rendering/index.ts index fe065c2260..c27a278d0b 100644 --- a/src/generators/server-side-rendering/index.ts +++ b/src/generators/server-side-rendering/index.ts @@ -2,6 +2,7 @@ import deindent from '../../utils/deindent'; import Generator from '../Generator'; import Block from './Block'; import visit from './visit'; +import stringify from '../../utils/stringify'; import { Parsed, Node, CompileOptions } from '../../interfaces'; export class SsrGenerator extends Generator { @@ -55,7 +56,7 @@ export default function ssr( var ${name} = {}; - ${name}.filename = ${JSON.stringify(options.filename)}; + ${name}.filename = ${stringify(options.filename)}; ${name}.data = function () { return ${templateProperties.data @@ -95,7 +96,7 @@ export default function ssr( deindent` components.push({ filename: ${name}.filename, - css: ${JSON.stringify(generator.css)}, + css: ${stringify(generator.css)}, map: null // TODO }); `} diff --git a/src/generators/server-side-rendering/visitors/Component.ts b/src/generators/server-side-rendering/visitors/Component.ts index fb34b188f4..c6280ca67e 100644 --- a/src/generators/server-side-rendering/visitors/Component.ts +++ b/src/generators/server-side-rendering/visitors/Component.ts @@ -4,6 +4,7 @@ import { SsrGenerator } from '../index'; import Block from '../Block'; import { Node } from '../../../interfaces'; import getObject from '../../../utils/getObject'; +import stringify from '../../../utils/stringify'; import getTailSnippet from '../../../utils/getTailSnippet'; export default function visitComponent( @@ -11,7 +12,7 @@ export default function visitComponent( block: Block, node: Node ) { - function stringify(chunk: Node) { + function stringifyAttribute(chunk: Node) { if (chunk.type === 'Text') return chunk.data; if (chunk.type === 'MustacheTag') { const { snippet } = block.contextualise(chunk.expression); @@ -41,13 +42,13 @@ export default function visitComponent( } else if (attribute.value.length === 1) { const chunk = attribute.value[0]; if (chunk.type === 'Text') { - value = isNaN(chunk.data) ? JSON.stringify(chunk.data) : chunk.data; + value = isNaN(chunk.data) ? stringify(chunk.data) : chunk.data; } else { const { snippet } = block.contextualise(chunk.expression); value = snippet; } } else { - value = '`' + attribute.value.map(stringify).join('') + '`'; + value = '`' + attribute.value.map(stringifyAttribute).join('') + '`'; } return `${attribute.name}: ${value}`; diff --git a/src/utils/stringify.ts b/src/utils/stringify.ts new file mode 100644 index 0000000000..fdb0410710 --- /dev/null +++ b/src/utils/stringify.ts @@ -0,0 +1,3 @@ +export default function stringify(data: string) { + return JSON.stringify(data.replace(/([^\\])?([@#])/g, '$1\\$2')); +} \ No newline at end of file diff --git a/test/js/samples/collapses-text-around-comments/expected-bundle.js b/test/js/samples/collapses-text-around-comments/expected-bundle.js index 0f9374f360..b2ded1b0e0 100644 --- a/test/js/samples/collapses-text-around-comments/expected-bundle.js +++ b/test/js/samples/collapses-text-around-comments/expected-bundle.js @@ -198,7 +198,7 @@ function SvelteComponent ( options ) { this._yield = options._yield; this._torndown = false; - if ( !document.getElementById( "svelte-3842350206-style" ) ) add_css(); + if ( !document.getElementById( 'svelte-3842350206-style' ) ) add_css(); this._fragment = create_main_fragment( this._state, this ); diff --git a/test/js/samples/collapses-text-around-comments/expected.js b/test/js/samples/collapses-text-around-comments/expected.js index 07b8b893ac..6c44f150e2 100644 --- a/test/js/samples/collapses-text-around-comments/expected.js +++ b/test/js/samples/collapses-text-around-comments/expected.js @@ -63,7 +63,7 @@ function SvelteComponent ( options ) { this._yield = options._yield; this._torndown = false; - if ( !document.getElementById( "svelte-3842350206-style" ) ) add_css(); + if ( !document.getElementById( 'svelte-3842350206-style' ) ) add_css(); this._fragment = create_main_fragment( this._state, this ); diff --git a/test/server-side-rendering/index.js b/test/server-side-rendering/index.js index e70bb13e73..4250dcce85 100644 --- a/test/server-side-rendering/index.js +++ b/test/server-side-rendering/index.js @@ -65,11 +65,16 @@ describe("ssr", () => { fs.writeFileSync(`${dir}/_actual.html`, html); if (css) fs.writeFileSync(`${dir}/_actual.css`, css); - assert.htmlEqual(html, expectedHtml); - assert.equal( - css.replace(/^\s+/gm, ""), - expectedCss.replace(/^\s+/gm, "") - ); + try { + assert.htmlEqual(html, expectedHtml); + assert.equal( + css.replace(/^\s+/gm, ""), + expectedCss.replace(/^\s+/gm, "") + ); + } catch (err) { + showOutput(dir, { generate: 'ssr' }); + throw err; + } }); });