diff --git a/.eslintignore b/.eslintignore index 4a113378ce..97a855e951 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,7 +1,3 @@ -src/shared -shared.js -store.js -test/test.js -test/setup.js **/_actual.js -**/expected.js \ No newline at end of file +**/expected.js +test/*/samples/*/output.js diff --git a/.eslintrc.json b/.eslintrc.json index 3d2c0f6869..c821993c40 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,43 +1,76 @@ { - "root": true, - "rules": { - "indent": [2, "tab", { "SwitchCase": 1 }], - "semi": [2, "always"], - "keyword-spacing": [2, { "before": true, "after": true }], - "space-before-blocks": [2, "always"], - "no-mixed-spaces-and-tabs": [2, "smart-tabs"], - "no-cond-assign": 0, - "no-unused-vars": 2, - "object-shorthand": [2, "always"], - "no-const-assign": 2, - "no-class-assign": 2, - "no-this-before-super": 2, - "no-var": 2, - "no-unreachable": 2, - "valid-typeof": 2, - "quote-props": [2, "as-needed"], - "one-var": [2, "never"], - "prefer-arrow-callback": 2, - "prefer-const": [2, { "destructuring": "all" }], - "arrow-spacing": 2, - "no-inner-declarations": 0 - }, - "env": { - "es6": true, - "browser": true, - "node": true, - "mocha": true - }, - "extends": [ - "eslint:recommended", - "plugin:import/errors", - "plugin:import/warnings" - ], - "parserOptions": { - "ecmaVersion": 9, - "sourceType": "module" - }, - "settings": { - "import/core-modules": ["svelte"] - } + "root": true, + "rules": { + "indent": "off", + "no-unused-vars": "off", + "semi": [2, "always"], + "keyword-spacing": [2, { "before": true, "after": true }], + "space-before-blocks": [2, "always"], + "no-mixed-spaces-and-tabs": [2, "smart-tabs"], + "no-cond-assign": 0, + "object-shorthand": [2, "always"], + "no-const-assign": 2, + "no-class-assign": 2, + "no-this-before-super": 2, + "no-var": 2, + "no-unreachable": 2, + "valid-typeof": 2, + "quote-props": [2, "as-needed"], + "one-var": [2, "never"], + "prefer-arrow-callback": 2, + "prefer-const": [2, { "destructuring": "all" }], + "arrow-spacing": 2, + "no-inner-declarations": 0, + "@typescript-eslint/indent": ["error", "tab", { + "SwitchCase": 1, + "ignoredNodes": ["TemplateLiteral"] + }], + "@typescript-eslint/camelcase": "off", + "@typescript-eslint/no-use-before-define": "off", + "@typescript-eslint/array-type": ["error", "array-simple"], + "@typescript-eslint/explicit-function-return-type": "off", + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/explicit-member-accessibility": "off", + "@typescript-eslint/no-unused-vars": ["error", { + "argsIgnorePattern": "^_" + }], + "@typescript-eslint/no-object-literal-type-assertion": ["error", { + "allowAsParameter": true + }], + "@typescript-eslint/no-unused-vars": "off" + }, + "env": { + "es6": true, + "browser": true, + "node": true, + "mocha": true + }, + "extends": [ + "eslint:recommended", + "plugin:import/errors", + "plugin:import/warnings", + "plugin:import/typescript", + "plugin:@typescript-eslint/recommended" + ], + "parserOptions": { + "ecmaVersion": 9, + "sourceType": "module" + }, + "settings": { + "import/core-modules": [ + "svelte", + "svelte/internal", + "svelte/store", + "svelte/easing", + "estree" + ] + }, + "overrides": [ + { + "files": ["*.js"], + "rules": { + "@typescript-eslint/no-var-requires": "off" + } + } + ] } diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index eb49e78156..0000000000 --- a/.gitattributes +++ /dev/null @@ -1 +0,0 @@ -*.svelte linguist-language=HTML diff --git a/.travis.yml b/.travis.yml index aeadd48f8d..a4603a26e2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,8 @@ language: node_js node_js: - - "node" - + - "8" + - "10" + - "12" env: global: - BUILD_TIMEOUT=20000 diff --git a/CHANGELOG.md b/CHANGELOG.md index 766a1634e4..c1adaf0b76 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,22 @@ # Svelte changelog +## 3.5.1 + +* Accommodate webpack idiosyncracies + +## 3.5.0 + +* Update package folder structure ([#2887](https://github.com/sveltejs/svelte/pull/2887)) +* Support `once` modifier on component events ([#2654](https://github.com/sveltejs/svelte/issues/2654)) +* Allow empty `
hello world
+ `, + + ssrHtml: ` +hello world
+ `, + + async test({ assert, component, target, window }) { + const el = target.querySelector('editor'); + assert.equal(el.innerHTML, 'world'); + + el.innerHTML = 'everybody'; + + // No updates to data yet + assert.htmlEqual(target.innerHTML, ` +hello world
+ `); + + // Handle user input + const event = new window.Event('input'); + await el.dispatchEvent(event); + assert.htmlEqual(target.innerHTML, ` +hello everybody
+ `); + + component.name = 'goodbye'; + assert.equal(el.innerHTML, 'goodbye'); + assert.htmlEqual(target.innerHTML, ` +hello goodbye
+ `); + }, +}; diff --git a/test/runtime/samples/contenteditable-html/main.svelte b/test/runtime/samples/contenteditable-html/main.svelte new file mode 100644 index 0000000000..53b4e81c88 --- /dev/null +++ b/test/runtime/samples/contenteditable-html/main.svelte @@ -0,0 +1,6 @@ + + +hello {@html name}
\ No newline at end of file diff --git a/test/runtime/samples/contenteditable-text/_config.js b/test/runtime/samples/contenteditable-text/_config.js new file mode 100644 index 0000000000..4935a3a9a7 --- /dev/null +++ b/test/runtime/samples/contenteditable-text/_config.js @@ -0,0 +1,37 @@ +export default { + props: { + name: 'world', + }, + + html: ` +hello world
+ `, + + ssrHtml: ` +hello world
+ `, + + async test({ assert, component, target, window }) { + const el = target.querySelector('editor'); + assert.equal(el.textContent, 'world'); + + const event = new window.Event('input'); + + el.textContent = 'everybody'; + await el.dispatchEvent(event); + + assert.htmlEqual(target.innerHTML, ` +hello everybody
+ `); + + component.name = 'goodbye'; + assert.equal(el.textContent, 'goodbye'); + assert.htmlEqual(target.innerHTML, ` +hello goodbye
+ `); + }, +}; diff --git a/test/runtime/samples/contenteditable-text/main.svelte b/test/runtime/samples/contenteditable-text/main.svelte new file mode 100644 index 0000000000..a71d9f0c5b --- /dev/null +++ b/test/runtime/samples/contenteditable-text/main.svelte @@ -0,0 +1,6 @@ + + +hello {name}
\ No newline at end of file diff --git a/test/runtime/samples/element-invalid-name/_config.js b/test/runtime/samples/element-invalid-name/_config.js index af6e4933ce..d70c920a19 100644 --- a/test/runtime/samples/element-invalid-name/_config.js +++ b/test/runtime/samples/element-invalid-name/_config.js @@ -2,4 +2,4 @@ export default { html: `internal: 1
- - `, + html: ` +internal: 1
+ + `, - async test({ assert, target, window }) { - const button = target.querySelector('button'); - const click = new window.MouseEvent('click'); + async test({ assert, target, window }) { + const button = target.querySelector('button'); + const click = new window.MouseEvent('click'); - await button.dispatchEvent(click); + await button.dispatchEvent(click); - assert.htmlEqual(target.innerHTML, ` -internal: 1
- - `); - } -}; \ No newline at end of file + assert.htmlEqual(target.innerHTML, ` +internal: 1
+ + `); + } +}; diff --git a/test/runtime/samples/mixed-let-export/_config.js b/test/runtime/samples/mixed-let-export/_config.js index 5ac8585742..f3da4215d9 100644 --- a/test/runtime/samples/mixed-let-export/_config.js +++ b/test/runtime/samples/mixed-let-export/_config.js @@ -1,9 +1,9 @@ export default { - props: { - a: 42 - }, + props: { + a: 42 + }, - html: ` - 42 - ` -} + html: ` + 42 + ` +}; diff --git a/test/runtime/samples/prop-exports/_config.js b/test/runtime/samples/prop-exports/_config.js index 631c9eb0ad..e1620c015f 100644 --- a/test/runtime/samples/prop-exports/_config.js +++ b/test/runtime/samples/prop-exports/_config.js @@ -2,29 +2,29 @@ import { writable } from '../../../../store'; export default { props: { - s1: writable(42), - s2: writable(43), - p1: 2, - p3: 3, - a1: writable(1), - a2: 4, - a6: writable(29), - for: 'loop', - continue: '...', + s1: writable(42), + s2: writable(43), + p1: 2, + p3: 3, + a1: writable(1), + a2: 4, + a6: writable(29), + for: 'loop', + continue: '...', }, html: ` - $s1=42 - $s2=43 - p1=2 - p3=3 - $v1=1 - v2=4 - vi1=4 - $vs1=1 - vl0=hello - vl1=test - $s3=29 - loop... - ` -} + $s1=42 + $s2=43 + p1=2 + p3=3 + $v1=1 + v2=4 + vi1=4 + $vs1=1 + vl0=hello + vl1=test + $s3=29 + loop... + ` +}; diff --git a/test/runtime/samples/spring/_config.js b/test/runtime/samples/spring/_config.js index 79399b777a..49367ce08b 100644 --- a/test/runtime/samples/spring/_config.js +++ b/test/runtime/samples/spring/_config.js @@ -1,3 +1,3 @@ export default { html: `0
` -} \ No newline at end of file +}; diff --git a/test/runtime/samples/transition-js-await-block/_config.js b/test/runtime/samples/transition-js-await-block/_config.js index 2e01dd7f76..80546ae6b8 100644 --- a/test/runtime/samples/transition-js-await-block/_config.js +++ b/test/runtime/samples/transition-js-await-block/_config.js @@ -1,7 +1,7 @@ let fulfil; let reject; -let promise = new Promise((f, r) => { +const promise = new Promise((f, r) => { fulfil = f; reject = r; }); @@ -14,7 +14,7 @@ export default { intro: true, test({ assert, target, raf }) { - let p = target.querySelector('p'); + const p = target.querySelector('p'); assert.equal(p.className, 'pending'); assert.equal(p.foo, 0); @@ -26,7 +26,7 @@ export default { return promise.then(() => { raf.tick(80); - let ps = document.querySelectorAll('p'); + const ps = document.querySelectorAll('p'); assert.equal(ps[1].className, 'pending'); assert.equal(ps[0].className, 'then'); assert.equal(ps[1].foo, 0.2); diff --git a/test/server-side-rendering/index.js b/test/server-side-rendering/index.js index 4b648c0591..cf6e5ad964 100644 --- a/test/server-side-rendering/index.js +++ b/test/server-side-rendering/index.js @@ -1,7 +1,6 @@ import * as assert from "assert"; import * as fs from "fs"; import * as path from "path"; -import * as glob from 'tiny-glob/sync.js'; import { showOutput, diff --git a/test/server-side-rendering/samples/text-area-bind/_expected.html b/test/server-side-rendering/samples/text-area-bind/_expected.html new file mode 100644 index 0000000000..c3c8441f56 --- /dev/null +++ b/test/server-side-rendering/samples/text-area-bind/_expected.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/test/server-side-rendering/samples/text-area-bind/main.svelte b/test/server-side-rendering/samples/text-area-bind/main.svelte new file mode 100644 index 0000000000..7126e09375 --- /dev/null +++ b/test/server-side-rendering/samples/text-area-bind/main.svelte @@ -0,0 +1,5 @@ + + + \ No newline at end of file diff --git a/test/setup.js b/test/setup.js index 8bb73d81d0..7406a07dd9 100644 --- a/test/setup.js +++ b/test/setup.js @@ -7,7 +7,7 @@ process.env.TEST = true; require.extensions['.js'] = function(module, filename) { const exports = []; - var code = fs.readFileSync(filename, 'utf-8') + let code = fs.readFileSync(filename, 'utf-8') .replace(/^import \* as (\w+) from ['"]([^'"]+)['"];?/gm, 'var $1 = require("$2");') .replace(/^import (\w+) from ['"]([^'"]+)['"];?/gm, 'var {default: $1} = require("$2");') .replace(/^import {([^}]+)} from ['"](.+)['"];?/gm, 'var {$1} = require("$2");') @@ -35,4 +35,4 @@ require.extensions['.js'] = function(module, filename) { console.log(code); // eslint-disable-line no-console throw err; } -}; \ No newline at end of file +}; diff --git a/test/sourcemaps/index.js b/test/sourcemaps/index.js index 79028719b9..ee169ebe1b 100644 --- a/test/sourcemaps/index.js +++ b/test/sourcemaps/index.js @@ -1,7 +1,7 @@ import * as fs from "fs"; import * as path from "path"; import * as assert from "assert"; -import { loadConfig, svelte } from "../helpers.js"; +import { svelte } from "../helpers.js"; import { SourceMapConsumer } from "source-map"; import { getLocator } from "locate-character"; @@ -18,8 +18,6 @@ describe("sourcemaps", () => { } (solo ? it.only : skip ? it.skip : it)(dir, () => { - const config = loadConfig(`./sourcemaps/samples/${dir}/_config.js`); - const filename = path.resolve( `test/sourcemaps/samples/${dir}/input.svelte` ); diff --git a/test/store/index.ts b/test/store/index.ts index 77ef9f9549..bb999f1220 100644 --- a/test/store/index.ts +++ b/test/store/index.ts @@ -49,7 +49,7 @@ describe('store', () => { const store = writable(obj); - store.subscribe(value => { + store.subscribe(() => { called += 1; }); diff --git a/test/test.js b/test/test.js index 380bbee304..7759941dbb 100644 --- a/test/test.js +++ b/test/test.js @@ -2,6 +2,6 @@ const glob = require("tiny-glob/sync.js"); require("./setup"); -glob("*/index.{js,ts}", { cwd: "test" }).forEach(function(file) { +glob("*/index.{js,ts}", { cwd: "test" }).forEach((file) => { require("./" + file); -}); \ No newline at end of file +}); diff --git a/test/validator/index.js b/test/validator/index.js index b26b087bb3..1e54cc20db 100644 --- a/test/validator/index.js +++ b/test/validator/index.js @@ -24,7 +24,7 @@ describe("validate", () => { let error; try { - let { warnings } = svelte.compile(input, { + const { warnings } = svelte.compile(input, { dev: config.dev, legacy: config.legacy, generate: false @@ -59,7 +59,7 @@ describe("validate", () => { assert.deepEqual(error.end, expected.end); assert.equal(error.pos, expected.pos); } catch (e) { - console.error(error) + console.error(error); // eslint-disable-line no-console throw e; } } diff --git a/test/validator/samples/component-event-modifiers-invalid/errors.json b/test/validator/samples/component-event-modifiers-invalid/errors.json new file mode 100644 index 0000000000..da608063fe --- /dev/null +++ b/test/validator/samples/component-event-modifiers-invalid/errors.json @@ -0,0 +1,15 @@ +[{ + "message": "Event modifiers other than 'once' can only be used on DOM elements", + "code": "invalid-event-modifier", + "start": { + "line": 6, + "column": 8, + "character": 93 + }, + "end": { + "line": 6, + "column": 40, + "character": 125 + }, + "pos": 93 +}] diff --git a/test/validator/samples/component-event-modifiers-invalid/input.svelte b/test/validator/samples/component-event-modifiers-invalid/input.svelte new file mode 100644 index 0000000000..8f7ce54d7a --- /dev/null +++ b/test/validator/samples/component-event-modifiers-invalid/input.svelte @@ -0,0 +1,6 @@ + + + \ No newline at end of file diff --git a/test/validator/samples/contenteditable-dynamic/errors.json b/test/validator/samples/contenteditable-dynamic/errors.json new file mode 100644 index 0000000000..0c4c5585a6 --- /dev/null +++ b/test/validator/samples/contenteditable-dynamic/errors.json @@ -0,0 +1,15 @@ +[{ + "code": "dynamic-contenteditable-attribute", + "message": "'contenteditable' attribute cannot be dynamic if element uses two-way binding", + "start": { + "line": 6, + "column": 8, + "character": 73 + }, + "end": { + "line": 6, + "column": 32, + "character": 97 + }, + "pos": 73 +}] \ No newline at end of file diff --git a/test/validator/samples/contenteditable-dynamic/input.svelte b/test/validator/samples/contenteditable-dynamic/input.svelte new file mode 100644 index 0000000000..97d2c9228c --- /dev/null +++ b/test/validator/samples/contenteditable-dynamic/input.svelte @@ -0,0 +1,6 @@ + +