diff --git a/src/generators/shared/utils/getIntro.js b/src/generators/shared/utils/getIntro.js index 3a11c1d237..c0fa4b4a69 100644 --- a/src/generators/shared/utils/getIntro.js +++ b/src/generators/shared/utils/getIntro.js @@ -7,6 +7,7 @@ export default function getIntro ( format, 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}` ); } @@ -60,6 +61,10 @@ function getUmdIntro ( options, imports ) { }(this, (function (${paramString( imports )}) { 'use strict';` + '\n\n'; } +function getEvalIntro ( options, imports ) { + return `(function (${paramString( imports )}) { 'use strict';\n\n`; +} + function paramString ( imports ) { return imports.length ? ` ${imports.map( dep => dep.name ).join( ', ' )} ` : ''; } diff --git a/src/generators/shared/utils/getOutro.js b/src/generators/shared/utils/getOutro.js index 283151267b..7f7c9354cf 100644 --- a/src/generators/shared/utils/getOutro.js +++ b/src/generators/shared/utils/getOutro.js @@ -18,6 +18,11 @@ export default function getOutro ( format, name, options, imports ) { 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})));`; } diff --git a/src/index.js b/src/index.js index b3d85116e3..ceb94442f4 100644 --- a/src/index.js +++ b/src/index.js @@ -46,4 +46,28 @@ export function compile ( source, _options ) { return compiler( parsed, source, options, names ); } +export function create ( source, _options = {} ) { + _options.format = 'eval'; + + const compiled = compile( source, _options ); + + if ( !compiled || !compiled.code ) { + return; + } + + let result; + try { + result = ( 1, eval )( compiled.code ); + } catch ( err ) { + if ( _options.onerror ) { + _options.onerror( err ); + } else { + throw err; + } + return; + } + + return result; +} + export { parse, validate, version as VERSION }; diff --git a/test/create.js b/test/create.js new file mode 100644 index 0000000000..153192de27 --- /dev/null +++ b/test/create.js @@ -0,0 +1,40 @@ +import deindent from '../src/utils/deindent.js'; +import assert from 'assert'; +import { svelte } from './helpers.js'; + +describe( 'create', () => { + it( 'should return a component constructor', () => { + const source = deindent` +
{{prop}}
+ `; + + const component = svelte.create( source ); + assert( component instanceof Function ); + }); + + it( 'should throw error when source is invalid ', done => { + const source = deindent` +
{{prop}
+ `; + + const component = svelte.create( source, { + onerror: () => { + done(); + } + }); + + assert.equal( component, undefined ); + }); + + it( 'should return undefined when source is invalid ', () => { + const source = deindent` +
{{prop}
+ `; + + const component = svelte.create( source, { + onerror: () => {} + }); + + assert.equal( component, undefined ); + }); +}); diff --git a/test/formats.js b/test/formats.js index 9b803cadcc..16ad77ce55 100644 --- a/test/formats.js +++ b/test/formats.js @@ -63,6 +63,21 @@ function testIife ( code, name, globals, html ) { }); } +function testEval ( code, name, globals, html ) { + const fn = new Function( Object.keys( globals ), `return ${code};` ); + + return env().then( window => { + const SvelteComponent = fn( ...Object.keys( globals ).map( key => globals[ key ] ) ); + + const main = window.document.body.querySelector( 'main' ); + const component = new SvelteComponent({ target: main }); + + assert.htmlEqual( main.innerHTML, html ); + + component.destroy(); + }); +} + describe( 'formats', () => { before( setupHtmlEqual ); @@ -175,4 +190,31 @@ describe( 'formats', () => { .then( () => testIife( code, 'Foo', { answer: 42 }, `
42
` ) ); }); }); + + describe( 'eval', () => { + it( 'generates a self-executing script that returns the component on eval', () => { + const source = deindent` +
{{answer}}
+ + + `; + + const { code } = svelte.compile( source, { + format: 'eval', + globals: { + answer: 'answer' + } + }); + + return testEval( code, 'Foo', { answer: 42 }, `
42
` ); + }); + }); });