diff --git a/CHANGELOG.md b/CHANGELOG.md index b77fd46d40..b12a89cf82 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Svelte changelog +## 1.39.4 + +* Extract shared init logic ([#855](https://github.com/sveltejs/svelte/pull/855)) +* Allow `console.*` calls in event handlers ([#782](https://github.com/sveltejs/svelte/issues/782)) +* Marker comments in output ([#823](https://github.com/sveltejs/svelte/issues/823)) +* Use `textContent` and `innerHTML` where appropriate ([#23](https://github.com/sveltejs/svelte/issues/23)) +* Various improvements to generated code + ## 1.39.3 * Allow `slot='...'` inside custom elements ([#827](https://github.com/sveltejs/svelte/issues/827)) diff --git a/package.json b/package.json index b06cacc724..a3ff6bc5f7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "svelte", - "version": "1.39.3", + "version": "1.39.4", "description": "The magical disappearing UI framework", "main": "compiler/svelte.js", "files": [ diff --git a/src/generators/Generator.ts b/src/generators/Generator.ts index 9c81546b64..d90cfaab38 100644 --- a/src/generators/Generator.ts +++ b/src/generators/Generator.ts @@ -8,8 +8,7 @@ import globalWhitelist from '../utils/globalWhitelist'; import reservedNames from '../utils/reservedNames'; import namespaces from '../utils/namespaces'; import { removeNode, removeObjectKey } from '../utils/removeNode'; -import getIntro from './shared/utils/getIntro'; -import getOutro from './shared/utils/getOutro'; +import wrapModule from './shared/utils/wrapModule'; import annotateWithScopes from '../utils/annotateWithScopes'; import clone from '../utils/clone'; import DomBlock from './dom/Block'; @@ -303,55 +302,12 @@ export default class Generator { return (expression._dependencies = dependencies); } - generate(result: string, options: CompileOptions, { name, format }: GenerateOptions ) { - if (this.imports.length) { - const statements: string[] = []; - - this.imports.forEach((declaration, i) => { - if (format === 'es') { - statements.push( - this.source.slice(declaration.start, declaration.end) - ); - return; - } - - const defaultImport = declaration.specifiers.find( - (x: Node) => - x.type === 'ImportDefaultSpecifier' || - (x.type === 'ImportSpecifier' && x.imported.name === 'default') - ); - const namespaceImport = declaration.specifiers.find( - (x: Node) => x.type === 'ImportNamespaceSpecifier' - ); - const namedImports = declaration.specifiers.filter( - (x: Node) => - x.type === 'ImportSpecifier' && x.imported.name !== 'default' - ); - - const name = defaultImport || namespaceImport - ? (defaultImport || namespaceImport).local.name - : `__import${i}`; - declaration.name = name; // hacky but makes life a bit easier later - - namedImports.forEach((specifier: Node) => { - statements.push( - `var ${specifier.local.name} = ${name}.${specifier.imported.name}` - ); - }); - - if (defaultImport) { - statements.push( - `${name} = (${name} && ${name}.__esModule) ? ${name}['default'] : ${name};` - ); - } - }); - - result = `${statements.join('\n')}\n\n${result}`; - } - + generate(result: string, options: CompileOptions, { banner = '', sharedPath, helpers, name, format }: GenerateOptions ) { const pattern = /\[✂(\d+)-(\d+)$/; - const parts = result.split('✂]'); + const module = wrapModule(result, format, name, options, banner, sharedPath, helpers, this.imports, this.source); + + const parts = module.split('✂]'); const finalChunk = parts.pop(); const compiled = new Bundle({ separator: '' }); @@ -362,9 +318,6 @@ export default class Generator { }); } - const intro = getIntro(format, options, this.imports); - if (intro) addString(intro); - const { filename } = options; // special case — the source file doesn't actually get used anywhere. we need @@ -391,7 +344,6 @@ export default class Generator { }); addString(finalChunk); - addString('\n\n' + getOutro(format, name, options, this.imports)); const { css, cssMap } = this.customElement ? { css: null, cssMap: null } : diff --git a/src/generators/dom/index.ts b/src/generators/dom/index.ts index 581ee0187b..33bcd0d9db 100644 --- a/src/generators/dom/index.ts +++ b/src/generators/dom/index.ts @@ -356,34 +356,20 @@ export default function dom( return generator.alias(name); }); - if (sharedPath) { - const used = Array.from(usedHelpers).sort(); - if (format === 'es') { - const names = used.map(name => { - const alias = generator.alias(name); - return name !== alias ? `${name} as ${alias}` : name; - }); - - result = - `import { ${names.join(', ')} } from ${JSON.stringify(sharedPath)};\n\n` + - result; - } - - else if (format === 'cjs') { - const SHARED = '__shared'; - let requires = `var ${SHARED} = require(${JSON.stringify(sharedPath)});`; - used.forEach(name => { - const alias = generator.alias(name); - requires += `\nvar ${alias} = ${SHARED}.${name};`; - }); + let helpers; - result = `${requires}\n\n${result}`; - } - - else { + if (sharedPath) { + if (format !== 'es' && format !== 'cjs') { throw new Error(`Components with shared helpers must be compiled with \`format: 'es'\` or \`format: 'cjs'\``); } + const used = Array.from(usedHelpers).sort(); + helpers = used.map(name => { + const alias = generator.alias(name); + return { name, alias }; + }); } else { + let inlineHelpers = ''; + usedHelpers.forEach(key => { const str = shared[key]; const code = new MagicString(str); @@ -421,20 +407,27 @@ export default function dom( // special case const global = `_svelteTransitionManager`; - result += `\n\nvar ${generator.alias('transitionManager')} = window.${global} || (window.${global} = ${code});`; + inlineHelpers += `\n\nvar ${generator.alias('transitionManager')} = window.${global} || (window.${global} = ${code});\n\n`; } else { const alias = generator.alias(expression.id.name); if (alias !== expression.id.name) code.overwrite(expression.id.start, expression.id.end, alias); - result += `\n\n${code}`; + inlineHelpers += `\n\n${code}`; } }); + + result += inlineHelpers; } - result = `/* ${options.filename ? `${options.filename} ` : ``}generated by Svelte v${version} */\n\n${result}`; + const filename = options.filename && ( + typeof process !== 'undefined' ? options.filename.replace(process.cwd(), '').replace(/^[\/\\]/, '') : options.filename + ); return generator.generate(result, options, { + banner: `/* ${filename ? `${filename} ` : ``}generated by Svelte v${version} */`, + sharedPath, + helpers, name, format, }); diff --git a/src/generators/dom/preprocess.ts b/src/generators/dom/preprocess.ts index 55d428a452..1ac7098555 100644 --- a/src/generators/dom/preprocess.ts +++ b/src/generators/dom/preprocess.ts @@ -41,6 +41,13 @@ function createDebuggingComment(node: Node, generator: DomGenerator) { return `${loc} ${source.slice(c, d)}`.replace(/\n/g, ' '); } +function cannotUseInnerHTML(node: Node) { + while (node && node.canUseInnerHTML) { + node.canUseInnerHTML = false; + node = node.parent; + } +} + // Whitespace inside one of these elements will not result in // a whitespace node being created in any circumstances. (This // list is almost certainly very incomplete) @@ -65,6 +72,7 @@ const preprocessors = { componentStack: Node[], stripWhitespace: boolean ) => { + cannotUseInnerHTML(node); node.var = block.getUniqueName('text'); const dependencies = block.findDependencies(node.expression); @@ -80,6 +88,7 @@ const preprocessors = { componentStack: Node[], stripWhitespace: boolean ) => { + cannotUseInnerHTML(node); node.var = block.getUniqueName('raw'); const dependencies = block.findDependencies(node.expression); @@ -114,6 +123,8 @@ const preprocessors = { stripWhitespace: boolean, nextSibling: Node ) => { + cannotUseInnerHTML(node); + const blocks: Block[] = []; let dynamic = false; let hasIntros = false; @@ -195,6 +206,7 @@ const preprocessors = { stripWhitespace: boolean, nextSibling: Node ) => { + cannotUseInnerHTML(node); node.var = block.getUniqueName(`each`); const dependencies = block.findDependencies(node.expression); @@ -290,10 +302,16 @@ const preprocessors = { stripWhitespace: boolean, nextSibling: Node ) => { + if (node.name === 'slot') { + cannotUseInnerHTML(node); + } + node.attributes.forEach((attribute: Node) => { if (attribute.type === 'Attribute' && attribute.value !== true) { attribute.value.forEach((chunk: Node) => { if (chunk.type !== 'Text') { + if (node.parent) cannotUseInnerHTML(node.parent); + const dependencies = block.findDependencies(chunk.expression); block.addDependencies(dependencies); @@ -311,20 +329,24 @@ const preprocessors = { } } }); - } else if (attribute.type === 'EventHandler' && attribute.expression) { - attribute.expression.arguments.forEach((arg: Node) => { - const dependencies = block.findDependencies(arg); + } else { + if (node.parent) cannotUseInnerHTML(node.parent); + + if (attribute.type === 'EventHandler' && attribute.expression) { + attribute.expression.arguments.forEach((arg: Node) => { + const dependencies = block.findDependencies(arg); + block.addDependencies(dependencies); + }); + } else if (attribute.type === 'Binding') { + const dependencies = block.findDependencies(attribute.value); block.addDependencies(dependencies); - }); - } else if (attribute.type === 'Binding') { - const dependencies = block.findDependencies(attribute.value); - block.addDependencies(dependencies); - } else if (attribute.type === 'Transition') { - if (attribute.intro) - generator.hasIntroTransitions = block.hasIntroMethod = true; - if (attribute.outro) { - generator.hasOutroTransitions = block.hasOutroMethod = true; - block.outros += 1; + } else if (attribute.type === 'Transition') { + if (attribute.intro) + generator.hasIntroTransitions = block.hasIntroMethod = true; + if (attribute.outro) { + generator.hasOutroTransitions = block.hasOutroMethod = true; + block.outros += 1; + } } } }); @@ -340,6 +362,8 @@ const preprocessors = { // so that if `foo.qux` changes, we know that we need to // mark `bar` and `baz` as dirty too if (node.name === 'select') { + cannotUseInnerHTML(node); + const value = node.attributes.find( (attribute: Node) => attribute.name === 'value' ); @@ -359,6 +383,8 @@ const preprocessors = { generator.components.has(node.name) || node.name === ':Self'; if (isComponent) { + cannotUseInnerHTML(node); + node.var = block.getUniqueName( (node.name === ':Self' ? generator.name : node.name).toLowerCase() ); @@ -369,6 +395,7 @@ const preprocessors = { } else { const slot = getStaticAttributeValue(node, 'slot'); if (slot && isChildOfComponent(node, generator)) { + cannotUseInnerHTML(node); node.slotted = true; // TODO validate slots — no nesting, no dynamic names... const component = componentStack[componentStack.length - 1]; @@ -442,6 +469,7 @@ function preprocessChildren( cleaned.forEach((child: Node, i: number) => { child.parent = node; + child.canUseInnerHTML = !generator.hydratable; const preprocessor = preprocessors[child.type]; if (preprocessor) preprocessor(generator, block, state, child, inEachBlock, elementStack, componentStack, stripWhitespace, cleaned[i + 1] || nextSibling); diff --git a/src/generators/dom/visitors/Element/Element.ts b/src/generators/dom/visitors/Element/Element.ts index 70e8ff280e..8b42d40a18 100644 --- a/src/generators/dom/visitors/Element/Element.ts +++ b/src/generators/dom/visitors/Element/Element.ts @@ -9,6 +9,7 @@ import visitBinding from './Binding'; import visitRef from './Ref'; import * as namespaces from '../../../../utils/namespaces'; import getStaticAttributeValue from '../../../../utils/getStaticAttributeValue'; +import isVoidElementName from '../../../../utils/isVoidElementName'; import addTransitions from './addTransitions'; import { DomGenerator } from '../../index'; import Block from '../../Block'; @@ -94,7 +95,6 @@ export default function visitElement( } // add CSS encapsulation attribute - // TODO add a helper for this, rather than repeating it if (node._needsCssAttribute && !generator.customElement) { generator.needsEncapsulateHelper = true; block.builders.hydrate.addLine( @@ -202,9 +202,21 @@ export default function visitElement( node.initialUpdate = node.lateUpdate = statement; } - node.children.forEach((child: Node) => { - visit(generator, block, childState, child, elementStack.concat(node), componentStack); - }); + if (!childState.namespace && node.canUseInnerHTML && node.children.length > 0) { + if (node.children.length === 1 && node.children[0].type === 'Text') { + block.builders.create.addLine( + `${name}.textContent = ${JSON.stringify(node.children[0].data)};` + ); + } else { + block.builders.create.addLine( + `${name}.innerHTML = ${JSON.stringify(node.children.map(toHTML).join(''))};` + ); + } + } else { + node.children.forEach((child: Node) => { + visit(generator, block, childState, child, elementStack.concat(node), componentStack); + }); + } if (node.lateUpdate) { block.builders.update.addLine(node.lateUpdate); @@ -221,6 +233,29 @@ export default function visitElement( block.builders.claim.addLine( `${childState.parentNodes}.forEach(@detachNode);` ); + + function toHTML(node: Node) { + if (node.type === 'Text') return node.data; + + let open = `<${node.name}`; + + if (node._needsCssAttribute) { + open += ` ${generator.stylesheet.id}`; + } + + if (node._cssRefAttribute) { + open += ` svelte-ref-${node._cssRefAttribute}`; + } + + node.attributes.forEach((attr: Node) => { + open += ` ${attr.name}${stringifyAttributeValue(attr.value)}` + }); + + if (isVoidElementName(node.name)) return open + '>'; + if (node.children.length === 0) return open + '/>'; + + return `${open}>${node.children.map(toHTML).join('')}`; + } } function getRenderStatement( @@ -263,3 +298,11 @@ function quoteProp(name: string, legacy: boolean) { if (/[^a-zA-Z_$0-9]/.test(name) || isLegacyPropName) return `"${name}"`; return name; } + +function stringifyAttributeValue(value: Node | true) { + if (value === true) return ''; + if (value.length === 0) return `=""`; + + const data = value[0].data; + return `=${JSON.stringify(data)}`; +} \ No newline at end of file diff --git a/src/generators/shared/utils/getGlobals.ts b/src/generators/shared/utils/getGlobals.ts deleted file mode 100644 index eb0db21276..0000000000 --- a/src/generators/shared/utils/getGlobals.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { CompileOptions, Node } from '../../../interfaces'; - - -export default function getGlobals(imports: Node[], options: CompileOptions) { - const { globals, onerror, onwarn } = options; - const globalFn = getGlobalFn(globals); - - return imports.map(x => { - let name = globalFn(x.source.value); - - if (!name) { - if (x.name.startsWith('__import')) { - const error = new Error( - `Could not determine name for imported module '${x.source.value}' – use options.globals` - ); - if (onerror) { - onerror(error); - } else { - throw error; - } - } else { - const warning = { - message: `No name was supplied for imported module '${x.source.value}'. Guessing '${x.name}', but you should use options.globals`, - }; - - if (onwarn) { - onwarn(warning); - } else { - console.warn(warning); // eslint-disable-line no-console - } - } - - name = x.name; - } - - return name; - }); -} - -function getGlobalFn(globals: any): (id: string) => string { - if (typeof globals === 'function') return globals; - if (typeof globals === 'object') { - return id => globals[id]; - } - - return () => undefined; -} diff --git a/src/generators/shared/utils/getIntro.ts b/src/generators/shared/utils/getIntro.ts deleted file mode 100644 index 599bc5f7b3..0000000000 --- a/src/generators/shared/utils/getIntro.ts +++ /dev/null @@ -1,95 +0,0 @@ -import deindent from '../../../utils/deindent'; -import getGlobals from './getGlobals'; -import { CompileOptions, ModuleFormat, Node } from '../../../interfaces'; - -export default function getIntro( - format: ModuleFormat, - options: CompileOptions, - imports: Node[] -) { - if (format === 'es') return ''; - if (format === 'amd') return getAmdIntro(options, imports); - if (format === 'cjs') return getCjsIntro(options, imports); - if (format === 'iife') return getIifeIntro(options, imports); - if (format === 'umd') return getUmdIntro(options, imports); - if (format === 'eval') return getEvalIntro(options, imports); - - throw new Error(`Not implemented: ${format}`); -} - -function getAmdIntro(options: CompileOptions, imports: Node[]) { - const sourceString = imports.length - ? `[${imports - .map(declaration => `'${removeExtension(declaration.source.value)}'`) - .join(', ')}], ` - : ''; - - const id = options.amd && options.amd.id; - - return `define(${id - ? `"${id}", ` - : ''}${sourceString}function(${paramString(imports)}) { 'use strict';\n\n`; -} - -function getCjsIntro(options: CompileOptions, imports: Node[]) { - const requireBlock = imports - .map( - declaration => - `var ${declaration.name} = require('${declaration.source.value}');` - ) - .join('\n\n'); - - if (requireBlock) { - return `'use strict';\n\n${requireBlock}\n\n`; - } - - return `'use strict';\n\n`; -} - -function getIifeIntro(options: CompileOptions, imports: Node[]) { - if (!options.name) { - throw new Error(`Missing required 'name' option for IIFE export`); - } - - return `var ${options.name} = (function(${paramString(imports)}) { 'use strict';\n\n`; -} - -function getUmdIntro(options: CompileOptions, imports: Node[]) { - if (!options.name) { - throw new Error(`Missing required 'name' option for UMD export`); - } - - const amdId = options.amd && options.amd.id ? `'${options.amd.id}', ` : ''; - - const amdDeps = imports.length - ? `[${imports - .map(declaration => `'${removeExtension(declaration.source.value)}'`) - .join(', ')}], ` - : ''; - const cjsDeps = imports - .map(declaration => `require('${declaration.source.value}')`) - .join(', '); - const globalDeps = getGlobals(imports, options); - - return ( - deindent` - (function(global, factory) { - typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(${cjsDeps}) : - typeof define === 'function' && define.amd ? define(${amdId}${amdDeps}factory) : - (global.${options.name} = factory(${globalDeps})); - }(this, (function (${paramString(imports)}) { 'use strict';` + '\n\n' - ); -} - -function getEvalIntro(options: CompileOptions, imports: Node[]) { - return `(function (${paramString(imports)}) { 'use strict';\n\n`; -} - -function paramString(imports: Node[]) { - return imports.map(dep => dep.name).join(', '); -} - -function removeExtension(file: string) { - const index = file.lastIndexOf('.'); - return ~index ? file.slice(0, index) : file; -} diff --git a/src/generators/shared/utils/getOutro.ts b/src/generators/shared/utils/getOutro.ts deleted file mode 100644 index 682a3cc870..0000000000 --- a/src/generators/shared/utils/getOutro.ts +++ /dev/null @@ -1,37 +0,0 @@ -import getGlobals from './getGlobals'; -import { CompileOptions, Node } from '../../../interfaces'; - -export default function getOutro( - format: string, - name: string, - options: CompileOptions, - imports: Node[] -) { - if (format === 'es') { - return `export default ${name};`; - } - - if (format === 'amd') { - return `return ${name};\n\n});`; - } - - if (format === 'cjs') { - return `module.exports = ${name};`; - } - - if (format === 'iife') { - const globals = getGlobals(imports, options); - return `return ${name};\n\n}(${globals.join(', ')}));`; - } - - if (format === 'eval') { - const globals = getGlobals(imports, options); - return `return ${name};\n\n}(${globals.join(', ')}));`; - } - - if (format === 'umd') { - return `return ${name};\n\n})));`; - } - - throw new Error(`Not implemented: ${format}`); -} diff --git a/src/generators/shared/utils/wrapModule.ts b/src/generators/shared/utils/wrapModule.ts new file mode 100644 index 0000000000..77fea53446 --- /dev/null +++ b/src/generators/shared/utils/wrapModule.ts @@ -0,0 +1,306 @@ +import deindent from '../../../utils/deindent'; +import { CompileOptions, ModuleFormat, Node } from '../../../interfaces'; + +interface Dependency { + name: string; + statements: string[]; + source: string; +} + +const wrappers = { es, amd, cjs, iife, umd, eval: expr }; + +export default function wrapModule( + code: string, + format: ModuleFormat, + name: string, + options: CompileOptions, + banner: string, + sharedPath: string, + helpers: { name: string, alias: string }[], + imports: Node[], + source: string +): string { + if (format === 'es') return es(code, name, options, banner, sharedPath, helpers, imports, source); + + const dependencies = imports.map((declaration, i) => { + const defaultImport = declaration.specifiers.find( + (x: Node) => + x.type === 'ImportDefaultSpecifier' || + (x.type === 'ImportSpecifier' && x.imported.name === 'default') + ); + + const namespaceImport = declaration.specifiers.find( + (x: Node) => x.type === 'ImportNamespaceSpecifier' + ); + + const namedImports = declaration.specifiers.filter( + (x: Node) => + x.type === 'ImportSpecifier' && x.imported.name !== 'default' + ); + + const name = defaultImport || namespaceImport + ? (defaultImport || namespaceImport).local.name + : `__import${i}`; + + const statements: string[] = []; + + namedImports.forEach((specifier: Node) => { + statements.push( + `var ${specifier.local.name} = ${name}.${specifier.imported.name};` + ); + }); + + if (defaultImport) { + statements.push( + `${name} = (${name} && ${name}.__esModule) ? ${name}["default"] : ${name};` + ); + } + + return { name, statements, source: declaration.source.value }; + }); + + if (format === 'amd') return amd(code, name, options, banner, dependencies); + if (format === 'cjs') return cjs(code, name, options, banner, sharedPath, helpers, dependencies); + if (format === 'iife') return iife(code, name, options, banner, dependencies); + if (format === 'umd') return umd(code, name, options, banner, dependencies); + if (format === 'eval') return expr(code, name, options, banner, dependencies); + + throw new Error(`Not implemented: ${format}`); +} + +function es( + code: string, + name: string, + options: CompileOptions, + banner: string, + sharedPath: string, + helpers: { name: string, alias: string }[], + imports: Node[], + source: string +) { + const importHelpers = helpers && ( + `import { ${helpers.map(h => h.name === h.alias ? h.name : `${h.name} as ${h.alias}`).join(', ')} } from ${JSON.stringify(sharedPath)};` + ); + + const importBlock = imports.length > 0 && ( + imports + .map((declaration: Node) => source.slice(declaration.start, declaration.end)) + .join('\n') + ); + + return deindent` + ${banner} + ${importHelpers} + ${importBlock} + + ${code} + export default ${name};`; +} + +function amd( + code: string, + name: string, + options: CompileOptions, + banner: string, + dependencies: Dependency[] +) { + const sourceString = dependencies.length + ? `[${dependencies.map(d => `"${removeExtension(d.source)}"`).join(', ')}], ` + : ''; + + const id = options.amd && options.amd.id; + + return deindent` + define(${id ? `"${id}", ` : ''}${sourceString}function(${paramString(dependencies)}) { "use strict"; + ${getCompatibilityStatements(dependencies)} + + ${code} + return ${name}; + });`; +} + +function cjs( + code: string, + name: string, + options: CompileOptions, + banner: string, + sharedPath: string, + helpers: { name: string, alias: string }[], + dependencies: Dependency[] +) { + const SHARED = '__shared'; + const helperBlock = helpers && ( + `var ${SHARED} = require(${JSON.stringify(sharedPath)});\n` + + helpers.map(helper => { + return `var ${helper.alias} = ${SHARED}.${helper.name};`; + }).join('\n') + ); + + const requireBlock = dependencies.length > 0 && ( + dependencies + .map(d => `var ${d.name} = require("${d.source}");`) + .join('\n\n') + ); + + return deindent` + ${banner} + "use strict"; + + ${helperBlock} + ${requireBlock} + ${getCompatibilityStatements(dependencies)} + + ${code} + + module.exports = ${name};` +} + +function iife( + code: string, + name: string, + options: CompileOptions, + banner: string, + dependencies: Dependency[] +) { + if (!options.name) { + throw new Error(`Missing required 'name' option for IIFE export`); + } + + const globals = getGlobals(dependencies, options); + + return deindent` + ${banner} + var ${options.name} = (function(${paramString(dependencies)}) { "use strict"; + ${getCompatibilityStatements(dependencies)} + + ${code} + return ${name}; + }(${globals.join(', ')}));`; +} + +function umd( + code: string, + name: string, + options: CompileOptions, + banner: string, + dependencies: Dependency[] +) { + if (!options.name) { + throw new Error(`Missing required 'name' option for UMD export`); + } + + const amdId = options.amd && options.amd.id ? `'${options.amd.id}', ` : ''; + + const amdDeps = dependencies.length + ? `[${dependencies.map(d => `"${removeExtension(d.source)}"`).join(', ')}], ` + : ''; + + const cjsDeps = dependencies + .map(d => `require("${d.source}")`) + .join(', '); + + const globals = getGlobals(dependencies, options); + + return deindent` + ${banner} + (function(global, factory) { + typeof exports === "object" && typeof module !== "undefined" ? module.exports = factory(${cjsDeps}) : + typeof define === "function" && define.amd ? define(${amdId}${amdDeps}factory) : + (global.${options.name} = factory(${globals})); + }(this, (function (${paramString(dependencies)}) { "use strict"; + + ${getCompatibilityStatements(dependencies)} + + ${code} + + return ${name}; + + })));`; +} + +function expr( + code: string, + name: string, + options: CompileOptions, + banner: string, + dependencies: Dependency[] +) { + const globals = getGlobals(dependencies, options); + + return deindent` + (function (${paramString(dependencies)}) { "use strict"; + ${banner} + + ${getCompatibilityStatements(dependencies)} + + ${code} + + return ${name}; + }(${globals.join(', ')}))`; +} + +function paramString(dependencies: Dependency[]) { + return dependencies.map(dep => dep.name).join(', '); +} + +function removeExtension(file: string) { + const index = file.lastIndexOf('.'); + return ~index ? file.slice(0, index) : file; +} + +function getCompatibilityStatements(dependencies: Dependency[]) { + if (!dependencies.length) return null; + + const statements: string[] = []; + + dependencies.forEach(dependency => { + statements.push(...dependency.statements); + }); + + return statements.join('\n'); +} + +function getGlobals(dependencies: Dependency[], options: CompileOptions) { + const { globals, onerror, onwarn } = options; + const globalFn = getGlobalFn(globals); + + return dependencies.map(d => { + let name = globalFn(d.source); + + if (!name) { + if (d.name.startsWith('__import')) { + const error = new Error( + `Could not determine name for imported module '${d.source}' – use options.globals` + ); + if (onerror) { + onerror(error); + } else { + throw error; + } + } else { + const warning = { + message: `No name was supplied for imported module '${d.source}'. Guessing '${d.name}', but you should use options.globals`, + }; + + if (onwarn) { + onwarn(warning); + } else { + console.warn(warning); // eslint-disable-line no-console + } + } + + name = d.name; + } + + return name; + }); +} + +function getGlobalFn(globals: any): (id: string) => string { + if (typeof globals === 'function') return globals; + if (typeof globals === 'object') { + return id => globals[id]; + } + + return () => undefined; +} \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index f2a2af1483..475cfcaceb 100644 --- a/src/index.ts +++ b/src/index.ts @@ -61,7 +61,7 @@ export function create(source: string, _options: CompileOptions = {}) { } try { - return new Function('return ' + compiled.code)(); + return (0,eval)(compiled.code); } catch (err) { if (_options.onerror) { _options.onerror(err); diff --git a/src/interfaces.ts b/src/interfaces.ts index 93d1b608f2..2d876c6a9a 100644 --- a/src/interfaces.ts +++ b/src/interfaces.ts @@ -64,6 +64,9 @@ export interface CompileOptions { export interface GenerateOptions { name: string; format: ModuleFormat; + banner?: string; + sharedPath?: string | boolean; + helpers?: { name: string, alias: string }[]; } export interface Visitor { 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 5918040b0c..402045ae74 100644 --- a/test/js/samples/collapses-text-around-comments/expected-bundle.js +++ b/test/js/samples/collapses-text-around-comments/expected-bundle.js @@ -190,7 +190,6 @@ var proto = { }; /* generated by Svelte vX.Y.Z */ - var template = (function() { return { data: function () { diff --git a/test/js/samples/collapses-text-around-comments/expected.js b/test/js/samples/collapses-text-around-comments/expected.js index 2dc66cfeea..b4ba5f9c54 100644 --- a/test/js/samples/collapses-text-around-comments/expected.js +++ b/test/js/samples/collapses-text-around-comments/expected.js @@ -1,5 +1,4 @@ /* generated by Svelte vX.Y.Z */ - import { appendNode, assign, createElement, createText, detachNode, init, insertNode, noop, proto, setAttribute } from "svelte/shared.js"; var template = (function() { @@ -69,5 +68,4 @@ function SvelteComponent(options) { } assign(SvelteComponent.prototype, proto); - export default SvelteComponent; \ No newline at end of file diff --git a/test/js/samples/component-static/expected-bundle.js b/test/js/samples/component-static/expected-bundle.js index 901e40935d..888c437806 100644 --- a/test/js/samples/component-static/expected-bundle.js +++ b/test/js/samples/component-static/expected-bundle.js @@ -166,7 +166,6 @@ var proto = { }; /* generated by Svelte vX.Y.Z */ - var template = (function() { return { components: { diff --git a/test/js/samples/component-static/expected.js b/test/js/samples/component-static/expected.js index e7eef6355f..7ca873cc5f 100644 --- a/test/js/samples/component-static/expected.js +++ b/test/js/samples/component-static/expected.js @@ -1,5 +1,4 @@ /* generated by Svelte vX.Y.Z */ - import { assign, callAll, init, noop, proto } from "svelte/shared.js"; var template = (function() { @@ -63,5 +62,4 @@ function SvelteComponent(options) { } assign(SvelteComponent.prototype, proto); - export default SvelteComponent; \ No newline at end of file diff --git a/test/js/samples/computed-collapsed-if/expected-bundle.js b/test/js/samples/computed-collapsed-if/expected-bundle.js index 8863885909..949b0e8e26 100644 --- a/test/js/samples/computed-collapsed-if/expected-bundle.js +++ b/test/js/samples/computed-collapsed-if/expected-bundle.js @@ -166,7 +166,6 @@ var proto = { }; /* generated by Svelte vX.Y.Z */ - var template = (function() { return { computed: { diff --git a/test/js/samples/computed-collapsed-if/expected.js b/test/js/samples/computed-collapsed-if/expected.js index 8ebcd4fa86..1ad70b617d 100644 --- a/test/js/samples/computed-collapsed-if/expected.js +++ b/test/js/samples/computed-collapsed-if/expected.js @@ -1,5 +1,4 @@ /* generated by Svelte vX.Y.Z */ - import { assign, differs, init, noop, proto } from "svelte/shared.js"; var template = (function() { @@ -47,5 +46,4 @@ SvelteComponent.prototype._recompute = function _recompute(changed, state) { if (differs(state.b, (state.b = template.computed.b(state.x)))) changed.b = true; } } - export default SvelteComponent; \ No newline at end of file diff --git a/test/js/samples/css-media-query/expected-bundle.js b/test/js/samples/css-media-query/expected-bundle.js index 77b9610644..862f721ebc 100644 --- a/test/js/samples/css-media-query/expected-bundle.js +++ b/test/js/samples/css-media-query/expected-bundle.js @@ -186,7 +186,6 @@ var proto = { }; /* generated by Svelte vX.Y.Z */ - function encapsulateStyles(node) { setAttribute(node, "svelte-2363328337", ""); } diff --git a/test/js/samples/css-media-query/expected.js b/test/js/samples/css-media-query/expected.js index 5a33892097..5b77893900 100644 --- a/test/js/samples/css-media-query/expected.js +++ b/test/js/samples/css-media-query/expected.js @@ -1,5 +1,4 @@ /* generated by Svelte vX.Y.Z */ - import { appendNode, assign, createElement, detachNode, init, insertNode, noop, proto, setAttribute } from "svelte/shared.js"; function encapsulateStyles(node) { @@ -55,5 +54,4 @@ function SvelteComponent(options) { } assign(SvelteComponent.prototype, proto); - export default SvelteComponent; \ No newline at end of file diff --git a/test/js/samples/css-shadow-dom-keyframes/expected-bundle.js b/test/js/samples/css-shadow-dom-keyframes/expected-bundle.js index b0b88edeeb..4c8fad71f7 100644 --- a/test/js/samples/css-shadow-dom-keyframes/expected-bundle.js +++ b/test/js/samples/css-shadow-dom-keyframes/expected-bundle.js @@ -13,10 +13,6 @@ function assign(target) { return target; } -function appendNode(node, target) { - target.appendChild(node); -} - function insertNode(node, target, anchor) { target.insertBefore(node, anchor); } @@ -29,10 +25,6 @@ function createElement(name) { return document.createElement(name); } -function createText(data) { - return document.createTextNode(data); -} - function blankObject() { return Object.create(null); } @@ -186,19 +178,17 @@ var proto = { }; /* generated by Svelte vX.Y.Z */ - function create_main_fragment(state, component) { - var div, text; + var div; return { c: function create() { div = createElement("div"); - text = createText("fades in"); + div.textContent = "fades in"; }, m: function mount(target, anchor) { insertNode(div, target, anchor); - appendNode(text, div); }, p: noop, diff --git a/test/js/samples/css-shadow-dom-keyframes/expected.js b/test/js/samples/css-shadow-dom-keyframes/expected.js index 8ad2ca1cc1..c004ec7df6 100644 --- a/test/js/samples/css-shadow-dom-keyframes/expected.js +++ b/test/js/samples/css-shadow-dom-keyframes/expected.js @@ -1,19 +1,17 @@ /* generated by Svelte vX.Y.Z */ - -import { appendNode, assign, createElement, createText, detachNode, init, insertNode, noop, proto } from "svelte/shared.js"; +import { assign, createElement, detachNode, init, insertNode, noop, proto } from "svelte/shared.js"; function create_main_fragment(state, component) { - var div, text; + var div; return { c: function create() { div = createElement("div"); - text = createText("fades in"); + div.textContent = "fades in"; }, m: function mount(target, anchor) { insertNode(div, target, anchor); - appendNode(text, div); }, p: noop, @@ -62,5 +60,4 @@ assign(SvelteComponent.prototype, proto, { this.parentNode.removeChild(this); } }); - export default SvelteComponent; \ No newline at end of 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 2bbbba75d2..33bd98ba74 100644 --- a/test/js/samples/each-block-changed-check/expected-bundle.js +++ b/test/js/samples/each-block-changed-check/expected-bundle.js @@ -198,7 +198,6 @@ var proto = { }; /* generated by Svelte vX.Y.Z */ - function create_main_fragment(state, component) { var text, p, text_1; diff --git a/test/js/samples/each-block-changed-check/expected.js b/test/js/samples/each-block-changed-check/expected.js index 578b25a17d..37c12c1acd 100644 --- a/test/js/samples/each-block-changed-check/expected.js +++ b/test/js/samples/each-block-changed-check/expected.js @@ -1,5 +1,4 @@ /* generated by Svelte vX.Y.Z */ - import { appendNode, assign, createElement, createText, destroyEach, detachAfter, detachNode, init, insertNode, noop, proto } from "svelte/shared.js"; function create_main_fragment(state, component) { @@ -153,5 +152,4 @@ function SvelteComponent(options) { } assign(SvelteComponent.prototype, proto); - export default SvelteComponent; \ No newline at end of file diff --git a/test/js/samples/event-handlers-custom/expected-bundle.js b/test/js/samples/event-handlers-custom/expected-bundle.js index 4a0eba647a..b94a6a848a 100644 --- a/test/js/samples/event-handlers-custom/expected-bundle.js +++ b/test/js/samples/event-handlers-custom/expected-bundle.js @@ -13,10 +13,6 @@ function assign(target) { return target; } -function appendNode(node, target) { - target.appendChild(node); -} - function insertNode(node, target, anchor) { target.insertBefore(node, anchor); } @@ -29,10 +25,6 @@ function createElement(name) { return document.createElement(name); } -function createText(data) { - return document.createTextNode(data); -} - function blankObject() { return Object.create(null); } @@ -186,7 +178,6 @@ var proto = { }; /* generated by Svelte vX.Y.Z */ - var template = (function() { return { methods: { @@ -203,12 +194,12 @@ var template = (function() { }()); function create_main_fragment(state, component) { - var button, foo_handler, text; + var button, foo_handler; return { c: function create() { button = createElement("button"); - text = createText("foo"); + button.textContent = "foo"; this.h(); }, @@ -221,7 +212,6 @@ function create_main_fragment(state, component) { m: function mount(target, anchor) { insertNode(button, target, anchor); - appendNode(text, button); }, p: noop, diff --git a/test/js/samples/event-handlers-custom/expected.js b/test/js/samples/event-handlers-custom/expected.js index 2dcd28dd80..5164130066 100644 --- a/test/js/samples/event-handlers-custom/expected.js +++ b/test/js/samples/event-handlers-custom/expected.js @@ -1,6 +1,5 @@ /* generated by Svelte vX.Y.Z */ - -import { appendNode, assign, createElement, createText, detachNode, init, insertNode, noop, proto } from "svelte/shared.js"; +import { assign, createElement, detachNode, init, insertNode, noop, proto } from "svelte/shared.js"; var template = (function() { return { @@ -18,12 +17,12 @@ var template = (function() { }()); function create_main_fragment(state, component) { - var button, foo_handler, text; + var button, foo_handler; return { c: function create() { button = createElement("button"); - text = createText("foo"); + button.textContent = "foo"; this.h(); }, @@ -36,7 +35,6 @@ function create_main_fragment(state, component) { m: function mount(target, anchor) { insertNode(button, target, anchor); - appendNode(text, button); }, p: noop, @@ -64,5 +62,4 @@ function SvelteComponent(options) { } assign(SvelteComponent.prototype, template.methods, proto); - export default SvelteComponent; \ No newline at end of file diff --git a/test/js/samples/if-block-no-update/expected-bundle.js b/test/js/samples/if-block-no-update/expected-bundle.js index fa03b2cd89..f68dbd24e3 100644 --- a/test/js/samples/if-block-no-update/expected-bundle.js +++ b/test/js/samples/if-block-no-update/expected-bundle.js @@ -13,10 +13,6 @@ function assign(target) { return target; } -function appendNode(node, target) { - target.appendChild(node); -} - function insertNode(node, target, anchor) { target.insertBefore(node, anchor); } @@ -29,10 +25,6 @@ function createElement(name) { return document.createElement(name); } -function createText(data) { - return document.createTextNode(data); -} - function createComment() { return document.createComment(''); } @@ -190,7 +182,6 @@ var proto = { }; /* generated by Svelte vX.Y.Z */ - function create_main_fragment(state, component) { var if_block_anchor; @@ -231,17 +222,16 @@ function create_main_fragment(state, component) { // (1:0) {{#if foo}} function create_if_block(state, component) { - var p, text; + var p; return { c: function create() { p = createElement("p"); - text = createText("foo!"); + p.textContent = "foo!"; }, m: function mount(target, anchor) { insertNode(p, target, anchor); - appendNode(text, p); }, u: function unmount() { @@ -254,17 +244,16 @@ function create_if_block(state, component) { // (3:0) {{else}} function create_if_block_1(state, component) { - var p, text; + var p; return { c: function create() { p = createElement("p"); - text = createText("not foo!"); + p.textContent = "not foo!"; }, m: function mount(target, anchor) { insertNode(p, target, anchor); - appendNode(text, p); }, u: function unmount() { diff --git a/test/js/samples/if-block-no-update/expected.js b/test/js/samples/if-block-no-update/expected.js index 8095cb6a03..6a0a4456c5 100644 --- a/test/js/samples/if-block-no-update/expected.js +++ b/test/js/samples/if-block-no-update/expected.js @@ -1,6 +1,5 @@ /* generated by Svelte vX.Y.Z */ - -import { appendNode, assign, createComment, createElement, createText, detachNode, init, insertNode, noop, proto } from "svelte/shared.js"; +import { assign, createComment, createElement, detachNode, init, insertNode, noop, proto } from "svelte/shared.js"; function create_main_fragment(state, component) { var if_block_anchor; @@ -42,17 +41,16 @@ function create_main_fragment(state, component) { // (1:0) {{#if foo}} function create_if_block(state, component) { - var p, text; + var p; return { c: function create() { p = createElement("p"); - text = createText("foo!"); + p.textContent = "foo!"; }, m: function mount(target, anchor) { insertNode(p, target, anchor); - appendNode(text, p); }, u: function unmount() { @@ -65,17 +63,16 @@ function create_if_block(state, component) { // (3:0) {{else}} function create_if_block_1(state, component) { - var p, text; + var p; return { c: function create() { p = createElement("p"); - text = createText("not foo!"); + p.textContent = "not foo!"; }, m: function mount(target, anchor) { insertNode(p, target, anchor); - appendNode(text, p); }, u: function unmount() { @@ -104,5 +101,4 @@ function SvelteComponent(options) { } assign(SvelteComponent.prototype, proto); - export default SvelteComponent; \ No newline at end of file diff --git a/test/js/samples/if-block-simple/expected-bundle.js b/test/js/samples/if-block-simple/expected-bundle.js index b5244296d6..9c99dd0275 100644 --- a/test/js/samples/if-block-simple/expected-bundle.js +++ b/test/js/samples/if-block-simple/expected-bundle.js @@ -13,10 +13,6 @@ function assign(target) { return target; } -function appendNode(node, target) { - target.appendChild(node); -} - function insertNode(node, target, anchor) { target.insertBefore(node, anchor); } @@ -29,10 +25,6 @@ function createElement(name) { return document.createElement(name); } -function createText(data) { - return document.createTextNode(data); -} - function createComment() { return document.createComment(''); } @@ -190,7 +182,6 @@ var proto = { }; /* generated by Svelte vX.Y.Z */ - function create_main_fragment(state, component) { var if_block_anchor; @@ -234,17 +225,16 @@ function create_main_fragment(state, component) { // (1:0) {{#if foo}} function create_if_block(state, component) { - var p, text; + var p; return { c: function create() { p = createElement("p"); - text = createText("foo!"); + p.textContent = "foo!"; }, m: function mount(target, anchor) { insertNode(p, target, anchor); - appendNode(text, p); }, u: function unmount() { diff --git a/test/js/samples/if-block-simple/expected.js b/test/js/samples/if-block-simple/expected.js index 12071722c0..9bfd8e211d 100644 --- a/test/js/samples/if-block-simple/expected.js +++ b/test/js/samples/if-block-simple/expected.js @@ -1,6 +1,5 @@ /* generated by Svelte vX.Y.Z */ - -import { appendNode, assign, createComment, createElement, createText, detachNode, init, insertNode, noop, proto } from "svelte/shared.js"; +import { assign, createComment, createElement, detachNode, init, insertNode, noop, proto } from "svelte/shared.js"; function create_main_fragment(state, component) { var if_block_anchor; @@ -45,17 +44,16 @@ function create_main_fragment(state, component) { // (1:0) {{#if foo}} function create_if_block(state, component) { - var p, text; + var p; return { c: function create() { p = createElement("p"); - text = createText("foo!"); + p.textContent = "foo!"; }, m: function mount(target, anchor) { insertNode(p, target, anchor); - appendNode(text, p); }, u: function unmount() { @@ -79,5 +77,4 @@ function SvelteComponent(options) { } assign(SvelteComponent.prototype, proto); - export default SvelteComponent; \ No newline at end of file diff --git a/test/js/samples/inline-style-optimized-multiple/expected-bundle.js b/test/js/samples/inline-style-optimized-multiple/expected-bundle.js index 07e0c3b741..80998f97b2 100644 --- a/test/js/samples/inline-style-optimized-multiple/expected-bundle.js +++ b/test/js/samples/inline-style-optimized-multiple/expected-bundle.js @@ -182,7 +182,6 @@ var proto = { }; /* generated by Svelte vX.Y.Z */ - function create_main_fragment(state, component) { var div; diff --git a/test/js/samples/inline-style-optimized-multiple/expected.js b/test/js/samples/inline-style-optimized-multiple/expected.js index 87531b7dd4..a92f5d3053 100644 --- a/test/js/samples/inline-style-optimized-multiple/expected.js +++ b/test/js/samples/inline-style-optimized-multiple/expected.js @@ -1,5 +1,4 @@ /* generated by Svelte vX.Y.Z */ - import { assign, createElement, detachNode, init, insertNode, noop, proto, setStyle } from "svelte/shared.js"; function create_main_fragment(state, component) { @@ -51,5 +50,4 @@ function SvelteComponent(options) { } assign(SvelteComponent.prototype, proto); - export default SvelteComponent; \ No newline at end of file diff --git a/test/js/samples/inline-style-optimized-url/expected-bundle.js b/test/js/samples/inline-style-optimized-url/expected-bundle.js index a8a483f6c0..236aaee071 100644 --- a/test/js/samples/inline-style-optimized-url/expected-bundle.js +++ b/test/js/samples/inline-style-optimized-url/expected-bundle.js @@ -182,7 +182,6 @@ var proto = { }; /* generated by Svelte vX.Y.Z */ - function create_main_fragment(state, component) { var div; diff --git a/test/js/samples/inline-style-optimized-url/expected.js b/test/js/samples/inline-style-optimized-url/expected.js index 0a264248ea..e10acd8dd8 100644 --- a/test/js/samples/inline-style-optimized-url/expected.js +++ b/test/js/samples/inline-style-optimized-url/expected.js @@ -1,5 +1,4 @@ /* generated by Svelte vX.Y.Z */ - import { assign, createElement, detachNode, init, insertNode, noop, proto, setStyle } from "svelte/shared.js"; function create_main_fragment(state, component) { @@ -46,5 +45,4 @@ function SvelteComponent(options) { } assign(SvelteComponent.prototype, proto); - export default SvelteComponent; \ No newline at end of file diff --git a/test/js/samples/inline-style-optimized/expected-bundle.js b/test/js/samples/inline-style-optimized/expected-bundle.js index 832561c261..f8084094be 100644 --- a/test/js/samples/inline-style-optimized/expected-bundle.js +++ b/test/js/samples/inline-style-optimized/expected-bundle.js @@ -182,7 +182,6 @@ var proto = { }; /* generated by Svelte vX.Y.Z */ - function create_main_fragment(state, component) { var div; diff --git a/test/js/samples/inline-style-optimized/expected.js b/test/js/samples/inline-style-optimized/expected.js index 0ad51ae48a..e9d42fec07 100644 --- a/test/js/samples/inline-style-optimized/expected.js +++ b/test/js/samples/inline-style-optimized/expected.js @@ -1,5 +1,4 @@ /* generated by Svelte vX.Y.Z */ - import { assign, createElement, detachNode, init, insertNode, noop, proto, setStyle } from "svelte/shared.js"; function create_main_fragment(state, component) { @@ -46,5 +45,4 @@ function SvelteComponent(options) { } assign(SvelteComponent.prototype, proto); - export default SvelteComponent; \ No newline at end of file diff --git a/test/js/samples/inline-style-unoptimized/expected-bundle.js b/test/js/samples/inline-style-unoptimized/expected-bundle.js index 8f1d93878e..d0b2a2dcfe 100644 --- a/test/js/samples/inline-style-unoptimized/expected-bundle.js +++ b/test/js/samples/inline-style-unoptimized/expected-bundle.js @@ -182,7 +182,6 @@ var proto = { }; /* generated by Svelte vX.Y.Z */ - function create_main_fragment(state, component) { var div, text, div_1, div_1_style_value; diff --git a/test/js/samples/inline-style-unoptimized/expected.js b/test/js/samples/inline-style-unoptimized/expected.js index 9eb67a0109..b2b4f5ad53 100644 --- a/test/js/samples/inline-style-unoptimized/expected.js +++ b/test/js/samples/inline-style-unoptimized/expected.js @@ -1,5 +1,4 @@ /* generated by Svelte vX.Y.Z */ - import { assign, createElement, createText, detachNode, init, insertNode, noop, proto } from "svelte/shared.js"; function create_main_fragment(state, component) { @@ -57,5 +56,4 @@ function SvelteComponent(options) { } assign(SvelteComponent.prototype, proto); - export default SvelteComponent; \ No newline at end of file diff --git a/test/js/samples/input-without-blowback-guard/expected-bundle.js b/test/js/samples/input-without-blowback-guard/expected-bundle.js index e5810909a4..792342604d 100644 --- a/test/js/samples/input-without-blowback-guard/expected-bundle.js +++ b/test/js/samples/input-without-blowback-guard/expected-bundle.js @@ -186,7 +186,6 @@ var proto = { }; /* generated by Svelte vX.Y.Z */ - function create_main_fragment(state, component) { var input; diff --git a/test/js/samples/input-without-blowback-guard/expected.js b/test/js/samples/input-without-blowback-guard/expected.js index 66aecd3c7e..f9ae72b1bd 100644 --- a/test/js/samples/input-without-blowback-guard/expected.js +++ b/test/js/samples/input-without-blowback-guard/expected.js @@ -1,5 +1,4 @@ /* generated by Svelte vX.Y.Z */ - import { addListener, assign, createElement, detachNode, init, insertNode, proto, removeListener } from "svelte/shared.js"; function create_main_fragment(state, component) { @@ -53,5 +52,4 @@ function SvelteComponent(options) { } assign(SvelteComponent.prototype, proto); - export default SvelteComponent; \ No newline at end of file diff --git a/test/js/samples/legacy-input-type/expected-bundle.js b/test/js/samples/legacy-input-type/expected-bundle.js index 23fe88c6a5..26f30cf194 100644 --- a/test/js/samples/legacy-input-type/expected-bundle.js +++ b/test/js/samples/legacy-input-type/expected-bundle.js @@ -184,7 +184,6 @@ var proto = { }; /* generated by Svelte vX.Y.Z */ - function create_main_fragment(state, component) { var input; diff --git a/test/js/samples/legacy-input-type/expected.js b/test/js/samples/legacy-input-type/expected.js index a5efd4252c..5309c86cfd 100644 --- a/test/js/samples/legacy-input-type/expected.js +++ b/test/js/samples/legacy-input-type/expected.js @@ -1,5 +1,4 @@ /* generated by Svelte vX.Y.Z */ - import { assign, createElement, detachNode, init, insertNode, noop, proto, setInputType } from "svelte/shared.js"; function create_main_fragment(state, component) { @@ -42,5 +41,4 @@ function SvelteComponent(options) { } assign(SvelteComponent.prototype, proto); - export default SvelteComponent; \ No newline at end of file diff --git a/test/js/samples/legacy-quote-class/expected-bundle.js b/test/js/samples/legacy-quote-class/expected-bundle.js index cbec093bde..3be6136b4a 100644 --- a/test/js/samples/legacy-quote-class/expected-bundle.js +++ b/test/js/samples/legacy-quote-class/expected-bundle.js @@ -201,7 +201,6 @@ var proto = { }; /* generated by Svelte vX.Y.Z */ - function create_main_fragment(state, component) { var div; diff --git a/test/js/samples/legacy-quote-class/expected.js b/test/js/samples/legacy-quote-class/expected.js index 3463f8ed4f..82eebe600c 100644 --- a/test/js/samples/legacy-quote-class/expected.js +++ b/test/js/samples/legacy-quote-class/expected.js @@ -1,5 +1,4 @@ /* generated by Svelte vX.Y.Z */ - import { assign, children, claimElement, createElement, detachNode, init, insertNode, noop, proto } from "svelte/shared.js"; function create_main_fragment(state, component) { @@ -52,5 +51,4 @@ function SvelteComponent(options) { } assign(SvelteComponent.prototype, proto); - export default SvelteComponent; \ No newline at end of file diff --git a/test/js/samples/media-bindings/expected-bundle.js b/test/js/samples/media-bindings/expected-bundle.js index 9f69a1855b..820db0a4fe 100644 --- a/test/js/samples/media-bindings/expected-bundle.js +++ b/test/js/samples/media-bindings/expected-bundle.js @@ -194,7 +194,6 @@ var proto = { }; /* generated by Svelte vX.Y.Z */ - function create_main_fragment(state, component) { var audio, audio_updating = false, audio_animationframe, audio_paused_value = true; diff --git a/test/js/samples/media-bindings/expected.js b/test/js/samples/media-bindings/expected.js index dbcb25a2d6..832826ffd5 100644 --- a/test/js/samples/media-bindings/expected.js +++ b/test/js/samples/media-bindings/expected.js @@ -1,5 +1,4 @@ /* generated by Svelte vX.Y.Z */ - import { addListener, assign, callAll, createElement, detachNode, init, insertNode, proto, removeListener, timeRangesToArray } from "svelte/shared.js"; function create_main_fragment(state, component) { @@ -128,5 +127,4 @@ function SvelteComponent(options) { } assign(SvelteComponent.prototype, proto); - export default SvelteComponent; \ No newline at end of file diff --git a/test/js/samples/non-imported-component/expected-bundle.js b/test/js/samples/non-imported-component/expected-bundle.js index 35574351c3..f6cd719f54 100644 --- a/test/js/samples/non-imported-component/expected-bundle.js +++ b/test/js/samples/non-imported-component/expected-bundle.js @@ -180,7 +180,6 @@ var proto = { }; /* generated by Svelte vX.Y.Z */ - var template = (function() { return { components: { diff --git a/test/js/samples/non-imported-component/expected.js b/test/js/samples/non-imported-component/expected.js index f5bdfbf7e1..aee3a35280 100644 --- a/test/js/samples/non-imported-component/expected.js +++ b/test/js/samples/non-imported-component/expected.js @@ -1,8 +1,6 @@ -import Imported from 'Imported.html'; - /* generated by Svelte vX.Y.Z */ - import { assign, callAll, createText, detachNode, init, insertNode, noop, proto } from "svelte/shared.js"; +import Imported from 'Imported.html'; var template = (function() { return { @@ -76,5 +74,4 @@ function SvelteComponent(options) { } assign(SvelteComponent.prototype, proto); - export default SvelteComponent; \ No newline at end of file diff --git a/test/js/samples/onrender-onteardown-rewritten/expected-bundle.js b/test/js/samples/onrender-onteardown-rewritten/expected-bundle.js index d479f91775..57bbff1fc0 100644 --- a/test/js/samples/onrender-onteardown-rewritten/expected-bundle.js +++ b/test/js/samples/onrender-onteardown-rewritten/expected-bundle.js @@ -166,7 +166,6 @@ var proto = { }; /* generated by Svelte vX.Y.Z */ - var template = (function() { return { // this test should be removed in v2 diff --git a/test/js/samples/onrender-onteardown-rewritten/expected.js b/test/js/samples/onrender-onteardown-rewritten/expected.js index 72f743b20d..0464d7a0d2 100644 --- a/test/js/samples/onrender-onteardown-rewritten/expected.js +++ b/test/js/samples/onrender-onteardown-rewritten/expected.js @@ -1,5 +1,4 @@ /* generated by Svelte vX.Y.Z */ - import { assign, callAll, init, noop, proto } from "svelte/shared.js"; var template = (function() { @@ -50,5 +49,4 @@ function SvelteComponent(options) { } assign(SvelteComponent.prototype, proto); - export default SvelteComponent; \ No newline at end of file diff --git a/test/js/samples/setup-method/expected-bundle.js b/test/js/samples/setup-method/expected-bundle.js index 8710e19029..145647d7c2 100644 --- a/test/js/samples/setup-method/expected-bundle.js +++ b/test/js/samples/setup-method/expected-bundle.js @@ -166,7 +166,6 @@ var proto = { }; /* generated by Svelte vX.Y.Z */ - var template = (function() { return { methods: { diff --git a/test/js/samples/setup-method/expected.js b/test/js/samples/setup-method/expected.js index 62a98aa8f6..e7cd138aa3 100644 --- a/test/js/samples/setup-method/expected.js +++ b/test/js/samples/setup-method/expected.js @@ -1,5 +1,4 @@ /* generated by Svelte vX.Y.Z */ - import { assign, init, noop, proto } from "svelte/shared.js"; var template = (function() { @@ -51,5 +50,4 @@ function SvelteComponent(options) { assign(SvelteComponent.prototype, template.methods, proto); template.setup(SvelteComponent); - export default SvelteComponent; \ No newline at end of file diff --git a/test/js/samples/use-elements-as-anchors/expected-bundle.js b/test/js/samples/use-elements-as-anchors/expected-bundle.js index 4defea8de9..92e3f9bbd3 100644 --- a/test/js/samples/use-elements-as-anchors/expected-bundle.js +++ b/test/js/samples/use-elements-as-anchors/expected-bundle.js @@ -190,9 +190,8 @@ var proto = { }; /* generated by Svelte vX.Y.Z */ - function create_main_fragment(state, component) { - var div, text, p, text_1, text_2, text_3, text_4, p_1, text_5, text_6, text_8, if_block_4_anchor; + var div, text, p, text_2, text_3, text_4, p_1, text_6, text_8, if_block_4_anchor; var if_block = (state.a) && create_if_block(state, component); @@ -210,14 +209,14 @@ function create_main_fragment(state, component) { if (if_block) if_block.c(); text = createText("\n\n\t"); p = createElement("p"); - text_1 = createText("this can be used as an anchor"); + p.textContent = "this can be used as an anchor"; text_2 = createText("\n\n\t"); if (if_block_1) if_block_1.c(); text_3 = createText("\n\n\t"); if (if_block_2) if_block_2.c(); text_4 = createText("\n\n\t"); p_1 = createElement("p"); - text_5 = createText("so can this"); + p_1.textContent = "so can this"; text_6 = createText("\n\n\t"); if (if_block_3) if_block_3.c(); text_8 = createText("\n\n"); @@ -230,14 +229,12 @@ function create_main_fragment(state, component) { if (if_block) if_block.m(div, null); appendNode(text, div); appendNode(p, div); - appendNode(text_1, p); appendNode(text_2, div); if (if_block_1) if_block_1.m(div, null); appendNode(text_3, div); if (if_block_2) if_block_2.m(div, null); appendNode(text_4, div); appendNode(p_1, div); - appendNode(text_5, p_1); appendNode(text_6, div); if (if_block_3) if_block_3.m(div, null); insertNode(text_8, target, anchor); @@ -330,17 +327,16 @@ function create_main_fragment(state, component) { // (2:1) {{#if a}} function create_if_block(state, component) { - var p, text; + var p; return { c: function create() { p = createElement("p"); - text = createText("a"); + p.textContent = "a"; }, m: function mount(target, anchor) { insertNode(p, target, anchor); - appendNode(text, p); }, u: function unmount() { @@ -353,17 +349,16 @@ function create_if_block(state, component) { // (8:1) {{#if b}} function create_if_block_1(state, component) { - var p, text; + var p; return { c: function create() { p = createElement("p"); - text = createText("b"); + p.textContent = "b"; }, m: function mount(target, anchor) { insertNode(p, target, anchor); - appendNode(text, p); }, u: function unmount() { @@ -376,17 +371,16 @@ function create_if_block_1(state, component) { // (12:1) {{#if c}} function create_if_block_2(state, component) { - var p, text; + var p; return { c: function create() { p = createElement("p"); - text = createText("c"); + p.textContent = "c"; }, m: function mount(target, anchor) { insertNode(p, target, anchor); - appendNode(text, p); }, u: function unmount() { @@ -399,17 +393,16 @@ function create_if_block_2(state, component) { // (18:1) {{#if d}} function create_if_block_3(state, component) { - var p, text; + var p; return { c: function create() { p = createElement("p"); - text = createText("d"); + p.textContent = "d"; }, m: function mount(target, anchor) { insertNode(p, target, anchor); - appendNode(text, p); }, u: function unmount() { @@ -422,17 +415,16 @@ function create_if_block_3(state, component) { // (25:0) {{#if e}} function create_if_block_4(state, component) { - var p, text; + var p; return { c: function create() { p = createElement("p"); - text = createText("e"); + p.textContent = "e"; }, m: function mount(target, anchor) { insertNode(p, target, anchor); - appendNode(text, p); }, u: function unmount() { diff --git a/test/js/samples/use-elements-as-anchors/expected.js b/test/js/samples/use-elements-as-anchors/expected.js index c60d8f9ce1..f23b9ec205 100644 --- a/test/js/samples/use-elements-as-anchors/expected.js +++ b/test/js/samples/use-elements-as-anchors/expected.js @@ -1,9 +1,8 @@ /* generated by Svelte vX.Y.Z */ - import { appendNode, assign, createComment, createElement, createText, detachNode, init, insertNode, noop, proto } from "svelte/shared.js"; function create_main_fragment(state, component) { - var div, text, p, text_1, text_2, text_3, text_4, p_1, text_5, text_6, text_8, if_block_4_anchor; + var div, text, p, text_2, text_3, text_4, p_1, text_6, text_8, if_block_4_anchor; var if_block = (state.a) && create_if_block(state, component); @@ -21,14 +20,14 @@ function create_main_fragment(state, component) { if (if_block) if_block.c(); text = createText("\n\n\t"); p = createElement("p"); - text_1 = createText("this can be used as an anchor"); + p.textContent = "this can be used as an anchor"; text_2 = createText("\n\n\t"); if (if_block_1) if_block_1.c(); text_3 = createText("\n\n\t"); if (if_block_2) if_block_2.c(); text_4 = createText("\n\n\t"); p_1 = createElement("p"); - text_5 = createText("so can this"); + p_1.textContent = "so can this"; text_6 = createText("\n\n\t"); if (if_block_3) if_block_3.c(); text_8 = createText("\n\n"); @@ -41,14 +40,12 @@ function create_main_fragment(state, component) { if (if_block) if_block.m(div, null); appendNode(text, div); appendNode(p, div); - appendNode(text_1, p); appendNode(text_2, div); if (if_block_1) if_block_1.m(div, null); appendNode(text_3, div); if (if_block_2) if_block_2.m(div, null); appendNode(text_4, div); appendNode(p_1, div); - appendNode(text_5, p_1); appendNode(text_6, div); if (if_block_3) if_block_3.m(div, null); insertNode(text_8, target, anchor); @@ -141,17 +138,16 @@ function create_main_fragment(state, component) { // (2:1) {{#if a}} function create_if_block(state, component) { - var p, text; + var p; return { c: function create() { p = createElement("p"); - text = createText("a"); + p.textContent = "a"; }, m: function mount(target, anchor) { insertNode(p, target, anchor); - appendNode(text, p); }, u: function unmount() { @@ -164,17 +160,16 @@ function create_if_block(state, component) { // (8:1) {{#if b}} function create_if_block_1(state, component) { - var p, text; + var p; return { c: function create() { p = createElement("p"); - text = createText("b"); + p.textContent = "b"; }, m: function mount(target, anchor) { insertNode(p, target, anchor); - appendNode(text, p); }, u: function unmount() { @@ -187,17 +182,16 @@ function create_if_block_1(state, component) { // (12:1) {{#if c}} function create_if_block_2(state, component) { - var p, text; + var p; return { c: function create() { p = createElement("p"); - text = createText("c"); + p.textContent = "c"; }, m: function mount(target, anchor) { insertNode(p, target, anchor); - appendNode(text, p); }, u: function unmount() { @@ -210,17 +204,16 @@ function create_if_block_2(state, component) { // (18:1) {{#if d}} function create_if_block_3(state, component) { - var p, text; + var p; return { c: function create() { p = createElement("p"); - text = createText("d"); + p.textContent = "d"; }, m: function mount(target, anchor) { insertNode(p, target, anchor); - appendNode(text, p); }, u: function unmount() { @@ -233,17 +226,16 @@ function create_if_block_3(state, component) { // (25:0) {{#if e}} function create_if_block_4(state, component) { - var p, text; + var p; return { c: function create() { p = createElement("p"); - text = createText("e"); + p.textContent = "e"; }, m: function mount(target, anchor) { insertNode(p, target, anchor); - appendNode(text, p); }, u: function unmount() { @@ -267,5 +259,4 @@ function SvelteComponent(options) { } assign(SvelteComponent.prototype, proto); - export default SvelteComponent; \ No newline at end of file diff --git a/test/runtime/index.js b/test/runtime/index.js index a31f9531f8..122fe645b6 100644 --- a/test/runtime/index.js +++ b/test/runtime/index.js @@ -73,11 +73,12 @@ describe("runtime", () => { ); const { code } = svelte.compile(source, compileOptions); const startIndex = code.indexOf("function create_main_fragment"); // may change! - if (startIndex === -1) - throw new Error("missing create_main_fragment"); + if (startIndex === -1) throw new Error("missing create_main_fragment"); + const endIndex = code.lastIndexOf("export default"); const es5 = code.slice(0, startIndex).split('\n').map(x => spaces(x.length)).join('\n') + - code.slice(startIndex).replace(/export default .+/, ""); + code.slice(startIndex, endIndex); + acorn.parse(es5, { ecmaVersion: 5 }); if (/Object\.assign/.test(es5)) { diff --git a/test/sourcemaps/samples/each-block/test.js b/test/sourcemaps/samples/each-block/test.js index add51d628b..d31c565ced 100644 --- a/test/sourcemaps/samples/each-block/test.js +++ b/test/sourcemaps/samples/each-block/test.js @@ -1,7 +1,8 @@ -export function test ({ assert, smc, locateInSource, locateInGenerated }) { - const expected = locateInSource( 'each' ); +export function test({ assert, code, smc, locateInSource, locateInGenerated }) { + const startIndex = code.indexOf('create_main_fragment'); - const loc = locateInGenerated( 'length' ); + const expected = locateInSource('each'); + const loc = locateInGenerated('length', startIndex ); const actual = smc.originalPositionFor({ line: loc.line + 1,