diff --git a/.eslintignore b/.eslintignore index effb19af45..bc31435419 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,5 +1,6 @@ src/shared shared.js test/test.js +test/setup.js **/_actual.js **/expected.js \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index 9eb0f07397..862286e395 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,5 @@ language: node_js node_js: - - "4" - "6" - "node" env: diff --git a/mocha.coverage.opts b/mocha.coverage.opts index 1513d44a4b..9c3738a2df 100644 --- a/mocha.coverage.opts +++ b/mocha.coverage.opts @@ -1,5 +1,4 @@ --require babel-register ---require reify --recursive ./**/__test__.js test/*/index.js diff --git a/package.json b/package.json index 6241b9e2f3..ece5b03b8b 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ "build": "node src/shared/_build.js && rollup -c", "dev": "node src/shared/_build.js && rollup -c -w", "pretest": "npm run build", - "prepublish": "npm run build && npm run lint", + "prepublishOnly": "npm run build && npm run lint", "prettier": "prettier --use-tabs --single-quote --trailing-comma es5 --write \"src/**/*.ts\"" }, "repository": { @@ -40,44 +40,31 @@ "homepage": "https://github.com/sveltejs/svelte#README", "devDependencies": { "@types/mocha": "^2.2.41", - "@types/node": "^7.0.22", - "acorn": "^4.0.4", - "babel": "^6.23.0", - "babel-core": "^6.23.1", - "babel-plugin-istanbul": "^3.0.0", - "babel-plugin-transform-es2015-arrow-functions": "^6.22.0", - "babel-plugin-transform-es2015-block-scoping": "^6.23.0", - "babel-plugin-transform-es2015-destructuring": "^6.23.0", - "babel-plugin-transform-es2015-modules-commonjs": "^6.23.0", - "babel-plugin-transform-es2015-parameters": "^6.23.0", - "babel-plugin-transform-es2015-spread": "^6.22.0", - "babel-preset-env": "^1.2.1", - "babel-register": "^6.23.0", - "chalk": "^1.1.3", - "codecov": "^1.0.1", + "@types/node": "^8.0.17", + "acorn": "^5.1.1", + "chalk": "^2.0.1", + "codecov": "^2.2.0", "console-group": "^0.3.2", "css-tree": "1.0.0-alpha16", - "eslint": "^3.12.2", + "eslint": "^4.3.0", "eslint-plugin-html": "^3.0.0", "eslint-plugin-import": "^2.2.0", "estree-walker": "^0.5.0", - "fuzzyset.js": "0.0.1", "glob": "^7.1.1", - "jsdom": "^9.9.1", + "jsdom": "^11.1.0", "locate-character": "^2.0.0", "magic-string": "^0.22.3", "mocha": "^3.2.0", "node-resolve": "^1.3.3", - "nyc": "^10.0.0", + "nyc": "^11.1.0", "prettier": "^1.4.1", - "reify": "^0.4.4", - "rollup": "^0.43.0", + "rollup": "^0.45.2", "rollup-plugin-buble": "^0.15.0", - "rollup-plugin-commonjs": "^7.0.0", + "rollup-plugin-commonjs": "^8.0.2", "rollup-plugin-json": "^2.1.0", - "rollup-plugin-node-resolve": "^2.0.0", + "rollup-plugin-node-resolve": "^3.0.0", "rollup-plugin-typescript": "^0.8.1", - "rollup-watch": "^3.2.2", + "rollup-watch": "^4.3.1", "source-map": "^0.5.6", "source-map-support": "^0.4.8", "typescript": "^2.3.2" @@ -91,15 +78,5 @@ "src/**/__test__.js", "src/shared/**" ] - }, - "babel": { - "plugins": [ - "transform-es2015-arrow-functions", - "transform-es2015-block-scoping", - "transform-es2015-spread", - "transform-es2015-parameters", - "transform-es2015-destructuring", - "transform-es2015-modules-commonjs" - ] } } diff --git a/src/generators/dom/index.ts b/src/generators/dom/index.ts index b93603be55..950b9a3712 100644 --- a/src/generators/dom/index.ts +++ b/src/generators/dom/index.ts @@ -294,21 +294,32 @@ export default function dom( }); if (sharedPath) { - if (format !== 'es') { - throw new Error( - `Components with shared helpers must be compiled to ES2015 modules (format: 'es')` - ); + 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 ${stringify(sharedPath)};\n\n` + + result; } - const names = Array.from(usedHelpers).sort().map(name => { - return name !== generator.alias(name) - ? `${name} as ${generator.alias(name)}` - : name; - }); + else if (format === 'cjs') { + const SHARED = '__shared'; + let requires = `var ${SHARED} = require( ${stringify(sharedPath)} );`; + used.forEach(name => { + const alias = generator.alias(name); + requires += `\nvar ${alias} = ${SHARED}.${name};`; + }); - result = - `import { ${names.join(', ')} } from ${stringify(sharedPath)};\n\n` + - result; + result = `${requires}\n\n${result}`; + } + + else { + throw new Error(`Components with shared helpers must be compiled with \`format: 'es'\` or \`format: 'cjs'\``); + } } else { usedHelpers.forEach(key => { const str = shared[key]; diff --git a/test/css/index.js b/test/css/index.js index 0d0b0e1b4a..0ce676d6ce 100644 --- a/test/css/index.js +++ b/test/css/index.js @@ -73,29 +73,29 @@ describe("css", () => { // verify that the right elements have scoping selectors if (expected.html !== null) { - return env().then(window => { - const Component = eval(`(function () { ${dom.code}; return SvelteComponent; }())`); - const target = window.document.querySelector("main"); + const window = env(); - new Component({ target, data: config.data }); - const html = target.innerHTML; + const Component = eval(`(function () { ${dom.code}; return SvelteComponent; }())`); + const target = window.document.querySelector("main"); - fs.writeFileSync(`test/css/samples/${dir}/_actual.html`, html); + new Component({ target, data: config.data }); + const html = target.innerHTML; - // dom - assert.equal( - normalizeHtml(window, html).replace(/svelte-\d+/g, 'svelte-xyz'), - normalizeHtml(window, expected.html) - ); + fs.writeFileSync(`test/css/samples/${dir}/_actual.html`, html); - // ssr - const component = eval(`(function () { ${ssr.code}; return SvelteComponent; }())`); + // dom + assert.equal( + normalizeHtml(window, html).replace(/svelte-\d+/g, 'svelte-xyz'), + normalizeHtml(window, expected.html) + ); - assert.equal( - normalizeHtml(window, component.render(config.data)).replace(/svelte-\d+/g, 'svelte-xyz'), - normalizeHtml(window, expected.html) - ); - }); + // ssr + const component = eval(`(function () { ${ssr.code}; return SvelteComponent; }())`); + + assert.equal( + normalizeHtml(window, component.render(config.data)).replace(/svelte-\d+/g, 'svelte-xyz'), + normalizeHtml(window, expected.html) + ); } }); }); diff --git a/test/formats/index.js b/test/formats/index.js index 9d62bb712f..b69bde817a 100644 --- a/test/formats/index.js +++ b/test/formats/index.js @@ -3,84 +3,80 @@ import { svelte, deindent, env, setupHtmlEqual } from "../helpers.js"; function testAmd(code, expectedId, dependencies, html) { const fn = new Function("define", code); + const window = env(); - return env().then(window => { - function define(id, deps, factory) { - assert.equal(id, expectedId); - assert.deepEqual(deps, Object.keys(dependencies)); + function define(id, deps, factory) { + assert.equal(id, expectedId); + assert.deepEqual(deps, Object.keys(dependencies)); - const SvelteComponent = factory( - ...Object.keys(dependencies).map(key => dependencies[key]) - ); + const SvelteComponent = factory( + ...Object.keys(dependencies).map(key => dependencies[key]) + ); - const main = window.document.body.querySelector("main"); - const component = new SvelteComponent({ target: main }); + const main = window.document.body.querySelector("main"); + const component = new SvelteComponent({ target: main }); - assert.htmlEqual(main.innerHTML, html); + assert.htmlEqual(main.innerHTML, html); - component.destroy(); - } + component.destroy(); + } - define.amd = true; + define.amd = true; - fn(define); - }); + fn(define); } function testCjs(code, dependencyById, html) { const fn = new Function("module", "exports", "require", code); + const window = env(); - return env().then(window => { - const module = { exports: {} }; - const require = id => { - return dependencyById[id]; - }; + const module = { exports: {} }; + const require = id => { + return dependencyById[id]; + }; - fn(module, module.exports, require); + fn(module, module.exports, require); - const SvelteComponent = module.exports; + const SvelteComponent = module.exports; - const main = window.document.body.querySelector("main"); - const component = new SvelteComponent({ target: main }); + const main = window.document.body.querySelector("main"); + const component = new SvelteComponent({ target: main }); - assert.htmlEqual(main.innerHTML, html); + assert.htmlEqual(main.innerHTML, html); - component.destroy(); - }); + component.destroy(); } function testIife(code, name, globals, html) { const fn = new Function(Object.keys(globals), `${code}\n\nreturn ${name};`); + const window = env(); - return env().then(window => { - const SvelteComponent = fn( - ...Object.keys(globals).map(key => globals[key]) - ); + const SvelteComponent = fn( + ...Object.keys(globals).map(key => globals[key]) + ); - const main = window.document.body.querySelector("main"); - const component = new SvelteComponent({ target: main }); + const main = window.document.body.querySelector("main"); + const component = new SvelteComponent({ target: main }); - assert.htmlEqual(main.innerHTML, html); + assert.htmlEqual(main.innerHTML, html); - component.destroy(); - }); + component.destroy(); } function testEval(code, name, globals, html) { const fn = new Function(Object.keys(globals), `return ${code};`); + const window = env(); - return env().then(window => { - const SvelteComponent = fn( - ...Object.keys(globals).map(key => globals[key]) - ); + const SvelteComponent = fn( + ...Object.keys(globals).map(key => globals[key]) + ); - const main = window.document.body.querySelector("main"); - const component = new SvelteComponent({ target: main }); + const main = window.document.body.querySelector("main"); + const component = new SvelteComponent({ target: main }); - assert.htmlEqual(main.innerHTML, html); + assert.htmlEqual(main.innerHTML, html); - component.destroy(); - }); + component.destroy(); } describe("formats", () => { @@ -190,9 +186,9 @@ describe("formats", () => { } }); - return testAmd(code, "foo", { answer: 42 }, `
42
`) - .then(() => testCjs(code, { answer: 42 }, `
42
`)) - .then(() => testIife(code, "Foo", { answer: 42 }, `
42
`)); + testAmd(code, "foo", { answer: 42 }, `
42
`); + testCjs(code, { answer: 42 }, `
42
`); + testIife(code, "Foo", { answer: 42 }, `
42
`); }); }); diff --git a/test/helpers.js b/test/helpers.js index 0dfa43fa54..f4be292ef4 100644 --- a/test/helpers.js +++ b/test/helpers.js @@ -1,16 +1,10 @@ -import jsdom from 'jsdom'; +import { JSDOM } from 'jsdom'; import assert from 'assert'; import glob from 'glob'; import fs from 'fs'; import path from 'path'; import chalk from 'chalk'; -import * as consoleGroup from 'console-group'; -consoleGroup.install(); - -import * as sourceMapSupport from 'source-map-support'; -sourceMapSupport.install(); - // for coverage purposes, we need to test source files, // but for sanity purposes, we need to test dist files export function loadSvelte(test) { @@ -53,17 +47,14 @@ export function tryToReadFile(file) { } } +const { window } = new JSDOM('
'); +global.document = window.document; + export function env() { - return new Promise((fulfil, reject) => { - jsdom.env('
', (err, window) => { - if (err) { - reject(err); - } else { - global.document = window.document; - fulfil(window); - } - }); - }); + window._svelteTransitionManager = null; + window.document.body.innerHTML = '
'; + + return window; } function cleanChildren(node) { @@ -138,22 +129,24 @@ export function normalizeHtml(window, html) { } export function setupHtmlEqual() { - return env().then(window => { - assert.htmlEqual = (actual, expected, message) => { - assert.deepEqual( - normalizeHtml(window, actual), - normalizeHtml(window, expected), - message - ); - }; - }); + const window = env(); + + assert.htmlEqual = (actual, expected, message) => { + assert.deepEqual( + normalizeHtml(window, actual), + normalizeHtml(window, expected), + message + ); + }; } export function loadConfig(file) { try { const resolved = require.resolve(file); delete require.cache[resolved]; - return require(resolved).default; + + const config = require(resolved); + return config.default || config; } catch (err) { if (err.code === 'MODULE_NOT_FOUND') { return {}; diff --git a/test/hydration/index.js b/test/hydration/index.js index 1e291ed6b1..922ff23de8 100644 --- a/test/hydration/index.js +++ b/test/hydration/index.js @@ -17,22 +17,17 @@ function getName(filename) { return base[0].toUpperCase() + base.slice(1); } -const nodeVersionMatch = /^v(\d)/.exec(process.version); -const legacy = +nodeVersionMatch[1] < 6; -const babelrc = require('../../package.json').babel; - describe('hydration', () => { before(() => { const svelte = loadSvelte(); require.extensions['.html'] = function(module, filename) { const options = Object.assign( - { filename, name: getName(filename), hydratable: true }, + { filename, name: getName(filename), hydratable: true, format: 'cjs' }, compileOptions ); - let { code } = svelte.compile(fs.readFileSync(filename, 'utf-8'), options); - if (legacy) code = require('babel-core').transform(code, babelrc).code; + const { code } = svelte.compile(fs.readFileSync(filename, 'utf-8'), options); return module._compile(code, filename); }; @@ -57,45 +52,44 @@ describe('hydration', () => { compileOptions.dev = config.dev; compileOptions.hydrate = true; - return env() - .then(window => { - global.window = window; - - let SvelteComponent; + const window = env(); - try { - SvelteComponent = require(`${cwd}/main.html`).default; - } catch (err) { - throw err; - } + try { + global.window = window; - const target = window.document.body; - target.innerHTML = fs.readFileSync(`${cwd}/_before.html`, 'utf-8'); + let SvelteComponent; - const snapshot = config.snapshot ? config.snapshot(target) : {}; + try { + SvelteComponent = require(`${cwd}/main.html`); + } catch (err) { + throw err; + } - const component = new SvelteComponent({ - target, - hydrate: true, - data: config.data - }); + const target = window.document.body; + target.innerHTML = fs.readFileSync(`${cwd}/_before.html`, 'utf-8'); - assert.htmlEqual(target.innerHTML, fs.readFileSync(`${cwd}/_after.html`, 'utf-8')); + const snapshot = config.snapshot ? config.snapshot(target) : {}; - if (config.test) { - config.test(assert, target, snapshot, component, window); - } else { - component.destroy(); - assert.equal(target.innerHTML, ''); - } - }) - .catch(err => { - showOutput(cwd, { shared: 'svelte/shared.js' }); // eslint-disable-line no-console - throw err; - }) - .then(() => { - if (config.show) showOutput(cwd, { shared: 'svelte/shared.js' }); + const component = new SvelteComponent({ + target, + hydrate: true, + data: config.data }); + + assert.htmlEqual(target.innerHTML, fs.readFileSync(`${cwd}/_after.html`, 'utf-8')); + + if (config.test) { + config.test(assert, target, snapshot, component, window); + } else { + component.destroy(); + assert.equal(target.innerHTML, ''); + } + } catch (err) { + showOutput(cwd, { shared: 'svelte/shared.js' }); // eslint-disable-line no-console + throw err; + } + + if (config.show) showOutput(cwd, { shared: 'svelte/shared.js' }); }); } diff --git a/test/js/index.js b/test/js/index.js index 512cba41fa..d6497b6b75 100644 --- a/test/js/index.js +++ b/test/js/index.js @@ -52,8 +52,9 @@ describe("js", () => { } ] }).then(bundle => { - const actualBundle = bundle.generate({ format: "es" }).code; - fs.writeFileSync(`${dir}/_actual-bundle.js`, actualBundle); + return bundle.generate({ format: "es" }) + }).then(({ code }) => { + fs.writeFileSync(`${dir}/_actual-bundle.js`, code); assert.equal( actual.trim().replace(/^\s+$/gm, ""), @@ -61,7 +62,7 @@ describe("js", () => { ); assert.equal( - actualBundle.trim().replace(/^\s+$/gm, ""), + code.trim().replace(/^\s+$/gm, ""), expectedBundle.trim().replace(/^\s+$/gm, "") ); }); diff --git a/test/runtime/index.js b/test/runtime/index.js index dea60082a3..ce30be761b 100644 --- a/test/runtime/index.js +++ b/test/runtime/index.js @@ -22,10 +22,6 @@ function getName(filename) { return base[0].toUpperCase() + base.slice(1); } -const nodeVersionMatch = /^v(\d)/.exec(process.version); -const legacy = +nodeVersionMatch[1] < 6; -const babelrc = require("../../package.json").babel; - const Object_assign = Object.assign; describe("runtime", () => { @@ -34,12 +30,11 @@ describe("runtime", () => { require.extensions[".html"] = function(module, filename) { const options = Object.assign( - { filename, name: getName(filename) }, + { filename, name: getName(filename), format: 'cjs' }, compileOptions ); - let { code } = svelte.compile(fs.readFileSync(filename, "utf-8"), options); - if (legacy) code = require('babel-core').transform(code, babelrc).code; + const { code } = svelte.compile(fs.readFileSync(filename, "utf-8"), options); return module._compile(code, filename); }; @@ -103,111 +98,110 @@ describe("runtime", () => { let unintendedError = null; - return env() - .then(window => { - // set of hacks to support transition tests - transitionManager.running = false; - transitionManager.transitions = []; - - const raf = { - time: 0, - callback: null, - tick: now => { - raf.time = now; - if (raf.callback) raf.callback(); + const window = env(); + + try { + // set of hacks to support transition tests + transitionManager.running = false; + transitionManager.transitions = []; + + const raf = { + time: 0, + callback: null, + tick: now => { + raf.time = now; + if (raf.callback) raf.callback(); + } + }; + window.performance = { now: () => raf.time }; + global.requestAnimationFrame = cb => { + let called = false; + raf.callback = () => { + if (!called) { + called = true; + cb(); } }; - window.performance = { now: () => raf.time }; - global.requestAnimationFrame = cb => { - let called = false; - raf.callback = () => { - if (!called) { - called = true; - cb(); - } - }; - }; + }; - global.window = window; + global.window = window; - try { - SvelteComponent = require(`./samples/${dir}/main.html`).default; - } catch (err) { - showOutput(cwd, { shared }); // eslint-disable-line no-console - throw err; - } + try { + SvelteComponent = require(`./samples/${dir}/main.html`); + } catch (err) { + showOutput(cwd, { shared }); // eslint-disable-line no-console + throw err; + } - let usedObjectAssign = false; - Object.assign = () => { - usedObjectAssign = true; - }; + let usedObjectAssign = false; + Object.assign = () => { + usedObjectAssign = true; + }; - global.window = window; + global.window = window; - // Put the constructor on window for testing - window.SvelteComponent = SvelteComponent; + // Put the constructor on window for testing + window.SvelteComponent = SvelteComponent; - const target = window.document.querySelector("main"); + const target = window.document.querySelector("main"); - const warnings = []; - const warn = console.warn; - console.warn = warning => { - warnings.push(warning); - }; + const warnings = []; + const warn = console.warn; + console.warn = warning => { + warnings.push(warning); + }; - const component = new SvelteComponent({ - target, - hydrate, - data: config.data - }); + const component = new SvelteComponent({ + target, + hydrate, + data: config.data + }); - Object.assign = Object_assign; + Object.assign = Object_assign; - console.warn = warn; + console.warn = warn; - if (config.error) { - unintendedError = true; - throw new Error("Expected a runtime error"); - } + if (config.error) { + unintendedError = true; + throw new Error("Expected a runtime error"); + } - if (config.warnings) { - assert.deepEqual(warnings, config.warnings); - } else if (warnings.length) { - unintendedError = true; - throw new Error("Received unexpected warnings"); - } + if (config.warnings) { + assert.deepEqual(warnings, config.warnings); + } else if (warnings.length) { + unintendedError = true; + throw new Error("Received unexpected warnings"); + } - if (config.html) { - assert.htmlEqual(target.innerHTML, config.html); - } + if (config.html) { + assert.htmlEqual(target.innerHTML, config.html); + } - if (config.test) { - config.test(assert, component, target, window, raf); - } else { - component.destroy(); - assert.equal(target.innerHTML, ""); - } + if (config.test) { + config.test(assert, component, target, window, raf); + } else { + component.destroy(); + assert.equal(target.innerHTML, ""); + } - if (usedObjectAssign) { - throw new Error( - "cannot use Object.assign in generated code, as it is not supported everywhere" - ); - } - }) - .catch(err => { - Object.assign = Object_assign; - - if (config.error && !unintendedError) { - config.error(assert, err); - } else { - failed.add(dir); - showOutput(cwd, { shared }); // eslint-disable-line no-console - throw err; - } - }) - .then(() => { - if (config.show) showOutput(cwd, { shared }); - }); + if (usedObjectAssign) { + throw new Error( + "cannot use Object.assign in generated code, as it is not supported everywhere" + ); + } + } catch (err) { + Object.assign = Object_assign; + + if (config.error && !unintendedError) { + config.error(assert, err); + } else { + failed.add(dir); + showOutput(cwd, { shared }); // eslint-disable-line no-console + throw err; + } + } + + if (config.show) showOutput(cwd, { shared }); }); } diff --git a/test/runtime/samples/deconflict-builtins/get.js b/test/runtime/samples/deconflict-builtins/get.js index 865e2b1c43..cd846d9be9 100644 --- a/test/runtime/samples/deconflict-builtins/get.js +++ b/test/runtime/samples/deconflict-builtins/get.js @@ -1,3 +1,3 @@ -export default function get () { +export function get () { return 'got'; } \ No newline at end of file diff --git a/test/runtime/samples/deconflict-builtins/main.html b/test/runtime/samples/deconflict-builtins/main.html index eb9de7d15f..db26b1ed70 100644 --- a/test/runtime/samples/deconflict-builtins/main.html +++ b/test/runtime/samples/deconflict-builtins/main.html @@ -1,7 +1,7 @@ {{foo}}