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/.flowconfig b/.flowconfig deleted file mode 100644 index c1961b7a6b..0000000000 --- a/.flowconfig +++ /dev/null @@ -1,9 +0,0 @@ -[ignore] -/types/.* - -[include] - -[libs] - -[options] -strip_root=true 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/.gitignore b/.gitignore index 4d7bbc7ac3..923dd5901e 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ node_modules *.map /src/compiler/compile/internal-exports.ts +/compiler.d.ts /compiler.*js /index.*js /internal 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 `` tags ([#2980](https://github.com/sveltejs/svelte/issues/2980)) +* Render textarea binding values inside element ([#2975](https://github.com/sveltejs/svelte/pull/2975)) +* Fix delayed animation glitch ([#2871](https://github.com/sveltejs/svelte/issues/2871)) +* Solve diamond dependencies problem with stores ([#2660](https://github.com/sveltejs/svelte/issues/2660)) +* Fix missing outros inside each blocks ([#2689](https://github.com/sveltejs/svelte/issues/2689)) +* Support animations without transitions ([#2908](https://github.com/sveltejs/svelte/issues/2908)) +* Add missing transition events ([#2912](https://github.com/sveltejs/svelte/pull/2912)) + + ## 3.4.4 * Publish type declaration files ([#2874](https://github.com/sveltejs/svelte/issues/2874)) diff --git a/appveyor.yml b/appveyor.yml index 249f61abf4..23a3ac3505 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -9,12 +9,13 @@ init: environment: matrix: - # node.js + - nodejs_version: 8 - nodejs_version: 10 + - nodejs_version: 12 install: - - ps: Install-Product node $env:nodejs_version - - npm install + - ps: Update-NodeJsInstallation (Get-NodeJsLatestBuild $env:nodejs_version) + - npm ci || npm install build: off diff --git a/compiler.d.ts b/compiler.d.ts deleted file mode 100644 index e2a3820bc5..0000000000 --- a/compiler.d.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './types/compiler'; diff --git a/package-lock.json b/package-lock.json index 1c6ced1a92..aea08689b1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,25 +1,35 @@ { "name": "svelte", - "version": "3.4.4", + "version": "3.5.1", "lockfileVersion": 1, "requires": true, "dependencies": { + "@babel/code-frame": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz", + "integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==", + "dev": true, + "requires": { + "@babel/highlight": "^7.0.0" + } + }, + "@babel/highlight": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0.tgz", + "integrity": "sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw==", + "dev": true, + "requires": { + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^4.0.0" + } + }, "@bcoe/v8-coverage": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.1.0.tgz", "integrity": "sha512-UdVB1rSL7H8TS8674fH02p5lRbhfIqQ18YKLxLKEnHFztHUH6bhMqjebMxgSTmWVrs5raS5JSLJIKKHFT4WfPg==", "dev": true }, - "@sveltejs/svelte-repl": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/@sveltejs/svelte-repl/-/svelte-repl-0.0.5.tgz", - "integrity": "sha512-SKSX4xkqwH0XcUHQozwTNm3OCqatk66CXYZnqOW9Jf4E1B6opyQUb9f96KwAxh7ghZMbeePRv51oOWsw6n0Yww==", - "dev": true, - "requires": { - "codemirror": "^5.45.0", - "yootils": "0.0.15" - } - }, "@types/estree": { "version": "0.0.39", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", @@ -39,11 +49,65 @@ "dev": true }, "@types/node": { - "version": "10.12.18", - "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.18.tgz", - "integrity": "sha512-fh+pAqt4xRzPfqA6eh3Z2y6fyZavRIumvjhaCL753+TVkGKGhpPeyrJG2JftD0T9q4GF00KjefsQ+PQNDdWQaQ==", + "version": "8.10.49", + "resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.49.tgz", + "integrity": "sha512-YX30JVx0PvSmJ3Eqr74fYLGeBxD+C7vIL20ek+GGGLJeUbVYRUW3EzyAXpIRA0K8c8o0UWqR/GwEFYiFoz1T8w==", "dev": true }, + "@typescript-eslint/eslint-plugin": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-1.9.0.tgz", + "integrity": "sha512-FOgfBorxjlBGpDIw+0LaZIXRX6GEEUfzj8LXwaQIUCp+gDOvkI+1WgugJ7SmWiISqK9Vj5r8S7NDKO/LB+6X9A==", + "dev": true, + "requires": { + "@typescript-eslint/experimental-utils": "1.9.0", + "@typescript-eslint/parser": "1.9.0", + "eslint-utils": "^1.3.1", + "functional-red-black-tree": "^1.0.1", + "regexpp": "^2.0.1", + "requireindex": "^1.2.0", + "tsutils": "^3.7.0" + } + }, + "@typescript-eslint/experimental-utils": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-1.9.0.tgz", + "integrity": "sha512-1s2dY9XxBwtS9IlSnRIlzqILPyeMly5tz1bfAmQ84Ul687xBBve5YsH5A5EKeIcGurYYqY2w6RkHETXIwnwV0A==", + "dev": true, + "requires": { + "@typescript-eslint/typescript-estree": "1.9.0" + } + }, + "@typescript-eslint/parser": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-1.9.0.tgz", + "integrity": "sha512-CWgC1XrQ34H/+LwAU7vY5xteZDkNqeAkeidEpJnJgkKu0yqQ3ZhQ7S+dI6MX4vmmM1TKRbOrKuXc6W0fIHhdbA==", + "dev": true, + "requires": { + "@typescript-eslint/experimental-utils": "1.9.0", + "@typescript-eslint/typescript-estree": "1.9.0", + "eslint-scope": "^4.0.0", + "eslint-visitor-keys": "^1.0.0" + } + }, + "@typescript-eslint/typescript-estree": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-1.9.0.tgz", + "integrity": "sha512-7Eg0TEQpCkTsEwsl1lIzd6i7L3pJLQFWesV08dS87bNz0NeSjbL78gNAP1xCKaCejkds4PhpLnZkaAjx9SU8OA==", + "dev": true, + "requires": { + "lodash.unescape": "4.0.1", + "semver": "5.5.0" + }, + "dependencies": { + "semver": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", + "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", + "dev": true + } + } + }, "abab": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.0.tgz", @@ -72,6 +136,12 @@ "acorn-walk": "^6.0.1" } }, + "acorn-jsx": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.0.1.tgz", + "integrity": "sha512-HJ7CfNHrfJLlNTzIEUTj43LNWGkqpRLxm3YjAlcD0ACydk9XynzYsCBHxut+iqt+1aBXkx9UP/w/ZqMr13XIzg==", + "dev": true + }, "acorn-walk": { "version": "6.1.1", "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.1.1.tgz", @@ -121,12 +191,27 @@ "uri-js": "^4.2.2" } }, + "ansi-escapes": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", + "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", + "dev": true + }, "ansi-regex": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", "dev": true }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, "any-promise": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", @@ -172,6 +257,16 @@ "integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=", "dev": true }, + "array-includes": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.0.3.tgz", + "integrity": "sha1-GEtI9i2S10UrsxsyMWXH+L0CJm0=", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "es-abstract": "^1.7.0" + } + }, "arrify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", @@ -199,6 +294,12 @@ "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", "dev": true }, + "astral-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "dev": true + }, "async-limiter": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", @@ -436,12 +537,35 @@ } } }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, "caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", "dev": true }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true + }, "class-utils": { "version": "0.3.6", "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", @@ -471,6 +595,21 @@ } } }, + "cli-cursor": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", + "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", + "dev": true, + "requires": { + "restore-cursor": "^2.0.0" + } + }, + "cli-width": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", + "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", + "dev": true + }, "cliui": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", @@ -501,12 +640,6 @@ "urlgrey": "^0.4.4" } }, - "codemirror": { - "version": "5.45.0", - "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.45.0.tgz", - "integrity": "sha512-c19j644usCE8gQaXa0jqn2B/HN9MnB2u6qPIrrhrMkB+QAP42y8G4QnTwuwbVSoUS1jEl7JU9HZMGhCDL0nsAw==", - "dev": true - }, "collection-visit": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", @@ -517,6 +650,21 @@ "object-visit": "^1.0.0" } }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, "combined-stream": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz", @@ -582,6 +730,12 @@ } } }, + "contains-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", + "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", + "dev": true + }, "copy-descriptor": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", @@ -687,6 +841,15 @@ "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", "dev": true }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, + "requires": { + "object-keys": "^1.0.12" + } + }, "define-property": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", @@ -752,6 +915,15 @@ "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", "dev": true }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, "domexception": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/domexception/-/domexception-1.0.1.tgz", @@ -771,6 +943,12 @@ "safer-buffer": "^2.1.0" } }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, "end-of-stream": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", @@ -789,6 +967,31 @@ "is-arrayish": "^0.2.1" } }, + "es-abstract": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.13.0.tgz", + "integrity": "sha512-vDZfg/ykNxQVwup/8E1BZhVzFfBxs9NqMzGcvIJrqg5k2/5Za2bWo40dK2J1pgLngZ7c+Shh8lwYtLGyrwPutg==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.0", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "is-callable": "^1.1.4", + "is-regex": "^1.0.4", + "object-keys": "^1.0.12" + } + }, + "es-to-primitive": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", + "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, "es6-promise": { "version": "4.2.6", "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.6.tgz", @@ -831,12 +1034,230 @@ } } }, + "eslint": { + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-5.16.0.tgz", + "integrity": "sha512-S3Rz11i7c8AA5JPv7xAH+dOyq/Cu/VXHiHXBPOU1k/JAM5dXqQPt3qcrhpHSorXmrpu2g0gkIBVXAqCpzfoZIg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "ajv": "^6.9.1", + "chalk": "^2.1.0", + "cross-spawn": "^6.0.5", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "eslint-scope": "^4.0.3", + "eslint-utils": "^1.3.1", + "eslint-visitor-keys": "^1.0.0", + "espree": "^5.0.1", + "esquery": "^1.0.1", + "esutils": "^2.0.2", + "file-entry-cache": "^5.0.1", + "functional-red-black-tree": "^1.0.1", + "glob": "^7.1.2", + "globals": "^11.7.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "inquirer": "^6.2.2", + "js-yaml": "^3.13.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.11", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "optionator": "^0.8.2", + "path-is-inside": "^1.0.2", + "progress": "^2.0.0", + "regexpp": "^2.0.1", + "semver": "^5.5.1", + "strip-ansi": "^4.0.0", + "strip-json-comments": "^2.0.1", + "table": "^5.2.3", + "text-table": "^0.2.0" + }, + "dependencies": { + "ajv": { + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.0.tgz", + "integrity": "sha512-nffhOpkymDECQyR0mnsUtoCE8RlX38G0rYP+wgLWFyZuUyuuojSSvi/+euOiQBIn63whYwYVIIH1TvE3tu4OEg==", + "dev": true, + "requires": { + "fast-deep-equal": "^2.0.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + } + } + }, + "eslint-import-resolver-node": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.2.tgz", + "integrity": "sha512-sfmTqJfPSizWu4aymbPr4Iidp5yKm8yDkHp+Ir3YiTHiiDfxh69mOUsmiqW6RZ9zRXFaF64GtYmN7e+8GHBv6Q==", + "dev": true, + "requires": { + "debug": "^2.6.9", + "resolve": "^1.5.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "eslint-module-utils": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.4.0.tgz", + "integrity": "sha512-14tltLm38Eu3zS+mt0KvILC3q8jyIAH518MlG+HO0p+yK885Lb1UHTY/UgR91eOyGdmxAPb+OLoW4znqIT6Ndw==", + "dev": true, + "requires": { + "debug": "^2.6.8", + "pkg-dir": "^2.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "eslint-plugin-import": { + "version": "2.17.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.17.3.tgz", + "integrity": "sha512-qeVf/UwXFJbeyLbxuY8RgqDyEKCkqV7YC+E5S5uOjAp4tOc8zj01JP3ucoBM8JcEqd1qRasJSg6LLlisirfy0Q==", + "dev": true, + "requires": { + "array-includes": "^3.0.3", + "contains-path": "^0.1.0", + "debug": "^2.6.9", + "doctrine": "1.5.0", + "eslint-import-resolver-node": "^0.3.2", + "eslint-module-utils": "^2.4.0", + "has": "^1.0.3", + "lodash": "^4.17.11", + "minimatch": "^3.0.4", + "read-pkg-up": "^2.0.0", + "resolve": "^1.11.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "doctrine": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", + "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "isarray": "^1.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "resolve": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.11.1.tgz", + "integrity": "sha512-vIpgF6wfuJOZI7KKKSP+HmiKggadPQAdsp5HiC1mvqnfp0gF1vdwgBWZIdrVft9pgqoMFQN+R7BSWZiBxx+BBw==", + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } + } + } + }, + "eslint-scope": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", + "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", + "dev": true, + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "eslint-utils": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.3.1.tgz", + "integrity": "sha512-Z7YjnIldX+2XMcjr7ZkgEsOj/bREONV60qYeB/bjMAqqqZ4zxKyWX+BOUkdmRmA9riiIPVvo5x86m5elviOk0Q==", + "dev": true + }, + "eslint-visitor-keys": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", + "integrity": "sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ==", + "dev": true + }, + "espree": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-5.0.1.tgz", + "integrity": "sha512-qWAZcWh4XE/RwzLJejfcofscgMc9CamR6Tn1+XRXNzrvUSSbiAjGOI/fggztjIi7y9VLPqnICMIPiGyr8JaZ0A==", + "dev": true, + "requires": { + "acorn": "^6.0.7", + "acorn-jsx": "^5.0.0", + "eslint-visitor-keys": "^1.0.0" + } + }, "esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", "dev": true }, + "esquery": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz", + "integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==", + "dev": true, + "requires": { + "estraverse": "^4.0.0" + } + }, + "esrecurse": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", + "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", + "dev": true, + "requires": { + "estraverse": "^4.1.0" + } + }, "estraverse": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", @@ -897,6 +1318,17 @@ } } }, + "external-editor": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.0.3.tgz", + "integrity": "sha512-bn71H9+qWoOQKyZDo25mOMVpSmXROAsTJVVVYzrrtol3d4y+AsKjf4Iwl2Q+IuT0kFSQ1qo166UuIwqYq7mGnA==", + "dev": true, + "requires": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + } + }, "extract-zip": { "version": "1.6.7", "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.6.7.tgz", @@ -959,6 +1391,50 @@ "pend": "~1.2.0" } }, + "figures": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", + "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "file-entry-cache": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", + "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", + "dev": true, + "requires": { + "flat-cache": "^2.0.1" + } + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "flat-cache": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", + "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", + "dev": true, + "requires": { + "flatted": "^2.0.0", + "rimraf": "2.6.3", + "write": "1.0.3" + } + }, + "flatted": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.0.tgz", + "integrity": "sha512-R+H8IZclI8AAkSBRQJLVOsxwAoHd6WC40b4QTNWIjzAa6BXOBfQcM587MXDTVPeYaopFNWHUFLx7eNmHDSxMWg==", + "dev": true + }, "for-in": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", @@ -1019,6 +1495,18 @@ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, "furi": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/furi/-/furi-1.3.0.tgz", @@ -1073,6 +1561,12 @@ "path-is-absolute": "^1.0.0" } }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + }, "globalyzer": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/globalyzer/-/globalyzer-0.1.0.tgz", @@ -1125,12 +1619,27 @@ "har-schema": "^2.0.0" } }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", "dev": true }, + "has-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", + "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=", + "dev": true + }, "has-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", @@ -1253,6 +1762,12 @@ "safer-buffer": ">= 2.1.2 < 3" } }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + }, "ignore-walk": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.1.tgz", @@ -1262,6 +1777,22 @@ "minimatch": "^3.0.4" } }, + "import-fresh": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.0.0.tgz", + "integrity": "sha512-pOnA9tfM3Uwics+SaBLCNyZZZbK+4PTu0OPZtLlMIrv17EdBoC15S9Kn8ckJ9TZTyKb3ywNE5y1yeDxxGA7nTQ==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -1278,6 +1809,44 @@ "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", "dev": true }, + "inquirer": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.3.1.tgz", + "integrity": "sha512-MmL624rfkFt4TG9y/Jvmt8vdmOo836U7Y0Hxr2aFk3RelZEGX4Igk0KabWrcaaZaTv9uzglOqWh1Vly+FAWAXA==", + "dev": true, + "requires": { + "ansi-escapes": "^3.2.0", + "chalk": "^2.4.2", + "cli-cursor": "^2.1.0", + "cli-width": "^2.0.0", + "external-editor": "^3.0.3", + "figures": "^2.0.0", + "lodash": "^4.17.11", + "mute-stream": "0.0.7", + "run-async": "^2.2.0", + "rxjs": "^6.4.0", + "string-width": "^2.1.0", + "strip-ansi": "^5.1.0", + "through": "^2.3.6" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, "invert-kv": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", @@ -1314,6 +1883,12 @@ "builtin-modules": "^1.0.0" } }, + "is-callable": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", + "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==", + "dev": true + }, "is-data-descriptor": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", @@ -1323,6 +1898,12 @@ "kind-of": "^3.0.2" } }, + "is-date-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", + "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", + "dev": true + }, "is-descriptor": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", @@ -1377,6 +1958,12 @@ } } }, + "is-promise": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", + "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", + "dev": true + }, "is-reference": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.1.1.tgz", @@ -1386,12 +1973,30 @@ "@types/estree": "0.0.39" } }, + "is-regex": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", + "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", + "dev": true, + "requires": { + "has": "^1.0.1" + } + }, "is-stream": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", "dev": true }, + "is-symbol": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", + "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", + "dev": true, + "requires": { + "has-symbols": "^1.0.0" + } + }, "is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", @@ -1448,6 +2053,12 @@ "handlebars": "^4.0.11" } }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, "js-yaml": { "version": "3.13.1", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", @@ -1515,6 +2126,12 @@ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, "json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", @@ -1573,12 +2190,34 @@ "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=", "dev": true }, + "load-json-file": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", + "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "strip-bom": "^3.0.0" + } + }, "locate-character": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/locate-character/-/locate-character-2.0.5.tgz", "integrity": "sha512-n2GmejDXtOPBAZdIiEFy5dJ5N38xBCXLNOtw2WpB9kGh6pnrEuKlwYI+Tkpofc4wDtVXHtoAOJaMRlYG/oYaxg==", "dev": true }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, "lodash": { "version": "4.17.11", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", @@ -1591,6 +2230,12 @@ "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=", "dev": true }, + "lodash.unescape": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.unescape/-/lodash.unescape-4.0.1.tgz", + "integrity": "sha1-vyJJiGzlFM2hEvrpIYzcBlIR/Jw=", + "dev": true + }, "lru-cache": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", @@ -1811,6 +2456,12 @@ "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", "dev": true }, + "mute-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", + "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", + "dev": true + }, "mz": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", @@ -1861,6 +2512,12 @@ } } }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, "neo-async": { "version": "2.6.1", "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz", @@ -1946,6 +2603,12 @@ } } }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true + }, "object-visit": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", @@ -1989,6 +2652,15 @@ "wrappy": "1" } }, + "onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "dev": true, + "requires": { + "mimic-fn": "^1.0.0" + } + }, "optimist": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", @@ -2032,6 +2704,12 @@ "mem": "^4.0.0" } }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true + }, "p-defer": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", @@ -2050,6 +2728,48 @@ "integrity": "sha1-nJRWmJ6fZYgBewQ01WCXZ1w9oF4=", "dev": true }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "dev": true, + "requires": { + "error-ex": "^1.2.0" + } + }, "parse5": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.0.tgz", @@ -2074,6 +2794,12 @@ "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "dev": true }, + "path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", + "dev": true + }, "path-key": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", @@ -2086,6 +2812,15 @@ "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", "dev": true }, + "path-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", + "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", + "dev": true, + "requires": { + "pify": "^2.0.0" + } + }, "pend": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", @@ -2098,6 +2833,12 @@ "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", "dev": true }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + }, "pirates": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.0.tgz", @@ -2107,6 +2848,15 @@ "node-modules-regexp": "^1.0.0" } }, + "pkg-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", + "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", + "dev": true, + "requires": { + "find-up": "^2.1.0" + } + }, "pn": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/pn/-/pn-1.1.0.tgz", @@ -2193,6 +2943,27 @@ "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", "dev": true }, + "read-pkg": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", + "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", + "dev": true, + "requires": { + "load-json-file": "^2.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^2.0.0" + } + }, + "read-pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", + "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", + "dev": true, + "requires": { + "find-up": "^2.0.0", + "read-pkg": "^2.0.0" + } + }, "regex-not": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", @@ -2203,6 +2974,12 @@ "safe-regex": "^1.1.0" } }, + "regexpp": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", + "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", + "dev": true + }, "repeat-element": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", @@ -2275,6 +3052,12 @@ "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", "dev": true }, + "requireindex": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/requireindex/-/requireindex-1.2.0.tgz", + "integrity": "sha512-L9jEkOi3ASd9PYit2cwRfyppc9NoABujTP8/5gFcbERmo5jUoAKovIC3fsF17pkTnGsrByysqX+Kxd2OTNI1ww==", + "dev": true + }, "resolve": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.0.tgz", @@ -2284,12 +3067,28 @@ "path-parse": "^1.0.6" } }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + }, "resolve-url": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", "dev": true }, + "restore-cursor": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", + "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", + "dev": true, + "requires": { + "onetime": "^2.0.0", + "signal-exit": "^3.0.2" + } + }, "ret": { "version": "0.1.15", "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", @@ -2702,6 +3501,24 @@ } } }, + "run-async": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", + "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", + "dev": true, + "requires": { + "is-promise": "^2.1.0" + } + }, + "rxjs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.2.tgz", + "integrity": "sha512-HUb7j3kvb7p7eCUHE3FqjoDsC1xfZQ4AHFWfTKSpZ+sAhhz5X1WX0ZuUqWbzB2QhSLp3DoLUG+hMdEDKqWo2Zg==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", @@ -2788,6 +3605,17 @@ "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", "dev": true }, + "slice-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", + "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "astral-regex": "^1.0.0", + "is-fullwidth-code-point": "^2.0.0" + } + }, "snapdragon": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", @@ -3080,6 +3908,12 @@ "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", "dev": true }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true + }, "sucrase": { "version": "3.9.5", "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.9.5.tgz", @@ -3115,6 +3949,58 @@ "integrity": "sha1-rifbOPZgp64uHDt9G8KQgZuFGeY=", "dev": true }, + "table": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/table/-/table-5.4.0.tgz", + "integrity": "sha512-nHFDrxmbrkU7JAFKqKbDJXfzrX2UBsWmrieXFTGxiI5e4ncg3VqsZeI4EzNmX0ncp4XNGVeoxIWJXfCIXwrsvw==", + "dev": true, + "requires": { + "ajv": "^6.9.1", + "lodash": "^4.17.11", + "slice-ansi": "^2.1.0", + "string-width": "^3.0.0" + }, + "dependencies": { + "ajv": { + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.0.tgz", + "integrity": "sha512-nffhOpkymDECQyR0mnsUtoCE8RlX38G0rYP+wgLWFyZuUyuuojSSvi/+euOiQBIn63whYwYVIIH1TvE3tu4OEg==", + "dev": true, + "requires": { + "fast-deep-equal": "^2.0.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, "test-exclude": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-5.0.0.tgz", @@ -3230,6 +4116,12 @@ } } }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, "thenify": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.0.tgz", @@ -3248,6 +4140,12 @@ "thenify": ">= 3.1.0 < 4" } }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "dev": true + }, "tiny-glob": { "version": "0.2.6", "resolved": "https://registry.npmjs.org/tiny-glob/-/tiny-glob-0.2.6.tgz", @@ -3258,6 +4156,15 @@ "globrex": "^0.1.1" } }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "requires": { + "os-tmpdir": "~1.0.2" + } + }, "to-object-path": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", @@ -3346,6 +4253,15 @@ "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==", "dev": true }, + "tsutils": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.14.0.tgz", + "integrity": "sha512-SmzGbB0l+8I0QwsPgjooFRaRvHLBLNYM8SeQ0k6rtNDru5sCGeLJcZdwilNndN+GysuFjF5EIYgN8GfFG6UeUw==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + } + }, "tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", @@ -3664,6 +4580,15 @@ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true }, + "write": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", + "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", + "dev": true, + "requires": { + "mkdirp": "^0.5.1" + } + }, "ws": { "version": "6.1.3", "resolved": "https://registry.npmjs.org/ws/-/ws-6.1.3.tgz", @@ -3809,12 +4734,6 @@ "resolved": "https://registry.npmjs.org/yn/-/yn-3.0.0.tgz", "integrity": "sha512-+Wo/p5VRfxUgBUGy2j/6KX2mj9AYJWOHuhMjMcbBFc3y54o9/4buK1ksBvuiK01C3kby8DH9lSmJdSxw+4G/2Q==", "dev": true - }, - "yootils": { - "version": "0.0.15", - "resolved": "https://registry.npmjs.org/yootils/-/yootils-0.0.15.tgz", - "integrity": "sha512-GvGLuJ7XHJPGEUQ52vh8fh+vPjfikuGcu7yBswfrsNsHqnAoytOVuSb69eM0j8wQIjMz0U3kY3YsfwMhJgfG9w==", - "dev": true } } } diff --git a/package.json b/package.json index 6d4bfb134e..37bd6f75e7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "svelte", - "version": "3.4.4", + "version": "3.5.1", "description": "Cybernetically enhanced web apps", "module": "index.mjs", "main": "index", @@ -18,24 +18,26 @@ "svelte", "README.md" ], - "types": "types/runtime", + "engines": { + "node": ">= 8" + }, + "types": "types/runtime/index.d.ts", "scripts": { "test": "mocha --opts mocha.opts", - "test:unit": "mocha --require sucrase/register --recursive ./**/__test__.ts", + "test:unit": "mocha --require sucrase/register --recursive src/**/__test__.ts", "quicktest": "mocha --opts mocha.opts", "precoverage": "c8 mocha --opts mocha.coverage.opts", "coverage": "c8 report --reporter=text-lcov > coverage.lcov && c8 report --reporter=html", "codecov": "codecov", "precodecov": "npm run coverage", - "build": "rollup -c", - "prepare": "npm run build && npm run tsd", + "build": "rollup -c && npm run tsd", + "prepare": "npm run build", "dev": "rollup -cw", "pretest": "npm run build", "posttest": "agadoo internal/index.mjs", - "prepublishOnly": "export PUBLISH=true && npm test && npm run create-stubs", - "create-stubs": "node scripts/create-stubs.js", - "tsd": "tsc -p . --emitDeclarationOnly", - "typecheck": "tsc -p . --noEmit" + "prepublishOnly": "PUBLISH=true npm test", + "tsd": "tsc -p src/compiler --emitDeclarationOnly && tsc -p src/runtime --emitDeclarationOnly", + "lint": "eslint \"{src,test}/**/*.{ts,js}\"" }, "repository": { "type": "git", @@ -54,15 +56,18 @@ }, "homepage": "https://github.com/sveltejs/svelte#README", "devDependencies": { - "@sveltejs/svelte-repl": "0.0.5", "@types/mocha": "^5.2.0", - "@types/node": "^10.5.5", + "@types/node": "=8", + "@typescript-eslint/eslint-plugin": "^1.9.0", + "@typescript-eslint/parser": "^1.9.0", "acorn": "^6.1.1", "acorn-dynamic-import": "^4.0.0", "agadoo": "^1.0.1", "c8": "^3.4.0", "codecov": "^3.0.0", "css-tree": "1.0.0-alpha22", + "eslint": "^5.16.0", + "eslint-plugin-import": "^2.17.3", "estree-walker": "^0.6.1", "is-reference": "^1.1.1", "jsdom": "^12.2.0", diff --git a/rollup.config.js b/rollup.config.js index 8907ae4e6c..fb329534a2 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -20,6 +20,8 @@ const ts_plugin = is_publish const external = id => id.startsWith('svelte/'); +fs.writeFileSync(`./compiler.d.ts`, `export * from './types/compiler/index';`); + export default [ /* runtime */ { @@ -59,12 +61,22 @@ export default [ external, plugins: [ ts_plugin, - dir === 'internal' && { - generateBundle(options, bundle) { - const mod = bundle['index.mjs']; - if (mod) { - fs.writeFileSync('src/compiler/compile/internal-exports.ts', `// This file is automatically generated\nexport default new Set(${JSON.stringify(mod.exports)});`); + { + writeBundle(bundle) { + if (dir === 'internal') { + const mod = bundle['index.mjs']; + if (mod) { + fs.writeFileSync('src/compiler/compile/internal-exports.ts', `// This file is automatically generated\nexport default new Set(${JSON.stringify(mod.exports)});`); + } } + + fs.writeFileSync(`${dir}/package.json`, JSON.stringify({ + main: './index', + module: './index.mjs', + types: './index.d.ts' + }, null, ' ')); + + fs.writeFileSync(`${dir}/index.d.ts`, `export * from '../types/runtime/${dir}/index';`); } } ] diff --git a/scripts/create-stubs.js b/scripts/create-stubs.js deleted file mode 100644 index 191b86cbfd..0000000000 --- a/scripts/create-stubs.js +++ /dev/null @@ -1,12 +0,0 @@ -const fs = require('fs'); - -fs.readdirSync('src/runtime') - .filter(dir => fs.statSync(`src/runtime/${dir}`).isDirectory()) - .forEach(dir => { - fs.writeFileSync(`${dir}/package.json`, JSON.stringify({ - main: './index.js', - module: './index.mjs' - }, null, ' ')); - - fs.writeFileSync(`${dir}/index.d.ts`, `export * from '../types/runtime/${dir}/index.d.ts';`); - }); \ No newline at end of file diff --git a/site/Dockerfile b/site/Dockerfile index f53e6a0c4a..c2a65122d9 100644 --- a/site/Dockerfile +++ b/site/Dockerfile @@ -1,4 +1,4 @@ -FROM mhart/alpine-node:11.14 +FROM mhart/alpine-node:12 # install dependencies WORKDIR /app @@ -9,7 +9,7 @@ RUN npm ci --production # Only copy over the Node pieces we need # ~> Saves 35MB ### -FROM mhart/alpine-node:base-11.14 +FROM mhart/alpine-node:slim-12 WORKDIR /app COPY --from=0 /app . diff --git a/site/content/examples/19-7guis/05-7guis-crud/App.svelte b/site/content/examples/19-7guis/05-7guis-crud/App.svelte index a0d6ef7f3e..f55aeb0d83 100644 --- a/site/content/examples/19-7guis/05-7guis-crud/App.svelte +++ b/site/content/examples/19-7guis/05-7guis-crud/App.svelte @@ -43,10 +43,12 @@ } function remove() { - people = [...people.slice(0, i), ...people.slice(i + 1)]; + // Remove selected person from the source array (people), not the filtered array + const index = people.indexOf(selected); + people = [...people.slice(0, index), ...people.slice(index + 1)]; first = last = ''; - i = Math.min(i, people.length - 1); + i = Math.min(i, filteredPeople.length - 2); } function reset_inputs(person) { diff --git a/site/content/examples/99-embeds/20181225-blog-svelte-css-in-js/App.svelte b/site/content/examples/99-embeds/20181225-blog-svelte-css-in-js/App.svelte index c8487abefe..ccb1ad8834 100644 --- a/site/content/examples/99-embeds/20181225-blog-svelte-css-in-js/App.svelte +++ b/site/content/examples/99-embeds/20181225-blog-svelte-css-in-js/App.svelte @@ -1,6 +1,6 @@ <script> import { comicSans, link } from './styles.js'; - import Hero from './Hero.html'; + import Hero from './Hero.svelte'; </script> <Hero/> diff --git a/site/content/examples/99-embeds/20181225-blog-svelte-css-in-js/styles.js b/site/content/examples/99-embeds/20181225-blog-svelte-css-in-js/styles.js index faf91b13d4..c7e10606c5 100644 --- a/site/content/examples/99-embeds/20181225-blog-svelte-css-in-js/styles.js +++ b/site/content/examples/99-embeds/20181225-blog-svelte-css-in-js/styles.js @@ -1,4 +1,6 @@ -import { css } from 'emotion/dist/emotion.umd.min.js'; +import emotion from 'emotion/dist/emotion.umd.min.js'; + +const { css } = emotion; const brand = '#74D900'; @@ -30,4 +32,4 @@ export const link = css` text-decoration: none; background: ${brand}; } -`; \ No newline at end of file +`; diff --git a/site/content/tutorial/01-introduction/03-dynamic-attributes/app-b/App.svelte b/site/content/tutorial/01-introduction/03-dynamic-attributes/app-b/App.svelte index 6a12752e1a..e61b4d48e0 100644 --- a/site/content/tutorial/01-introduction/03-dynamic-attributes/app-b/App.svelte +++ b/site/content/tutorial/01-introduction/03-dynamic-attributes/app-b/App.svelte @@ -3,4 +3,4 @@ let name = 'Rick Astley'; </script> -<img {src} alt="{name} dancing"> \ No newline at end of file +<img {src} alt="{name} dances."> diff --git a/site/content/tutorial/01-introduction/03-dynamic-attributes/text.md b/site/content/tutorial/01-introduction/03-dynamic-attributes/text.md index 1fd6774b8a..c503b4f548 100644 --- a/site/content/tutorial/01-introduction/03-dynamic-attributes/text.md +++ b/site/content/tutorial/01-introduction/03-dynamic-attributes/text.md @@ -19,10 +19,10 @@ When building web apps, it's important to make sure that they're *accessible* to In this case, we're missing the `alt` attribute that describes the image for people using screenreaders, or people with slow or flaky internet connections that can't download the image. Let's add one: ```html -<img src={src} alt="A man dancing"> +<img src={src} alt="A man dances."> ``` -We can use curly braces *inside* attributes. Try changing it to `"{name} dancing"` — remember to declare a `name` variable in the `<script>` block. +We can use curly braces *inside* attributes. Try changing it to `"{name} dances."` — remember to declare a `name` variable in the `<script>` block. ## Shorthand attributes @@ -30,6 +30,6 @@ We can use curly braces *inside* attributes. Try changing it to `"{name} dancing It's not uncommon to have an attribute where the name and value are the same, like `src={src}`. Svelte gives us a convenient shorthand for these cases: ```html -<img {src} alt="A man dancing"> +<img {src} alt="A man dances."> ``` diff --git a/site/content/tutorial/02-reactivity/04-updating-arrays-and-objects/text.md b/site/content/tutorial/02-reactivity/04-updating-arrays-and-objects/text.md index 0a78c7ca32..b70b09f728 100644 --- a/site/content/tutorial/02-reactivity/04-updating-arrays-and-objects/text.md +++ b/site/content/tutorial/02-reactivity/04-updating-arrays-and-objects/text.md @@ -13,7 +13,7 @@ function addNumber() { } ``` -But there's a more *idiomatic* solution: +But there's a more idiomatic solution: ```js function addNumber() { @@ -23,4 +23,10 @@ function addNumber() { You can use similar patterns to replace `pop`, `shift`, `unshift` and `splice`. -> Assignments to *properties* of arrays and objects — e.g. `obj.foo += 1` or `array[i] = x` — work the same way as assignments to the values themselves. +Assignments to *properties* of arrays and objects — e.g. `obj.foo += 1` or `array[i] = x` — work the same way as assignments to the values themselves. + +```js +function addNumber() { + numbers[numbers.length] = numbers.length + 1; +} +``` diff --git a/site/content/tutorial/03-props/02-default-values/text.md b/site/content/tutorial/03-props/02-default-values/text.md index dda6a370fe..1532407380 100644 --- a/site/content/tutorial/03-props/02-default-values/text.md +++ b/site/content/tutorial/03-props/02-default-values/text.md @@ -10,9 +10,9 @@ We can easily specify default values for props: </script> ``` -If we now instantiate the component without an `answer` prop, it will fall back to the default: +If we now add a second component *without* an `answer` prop, it will fall back to the default: ```html <Nested answer={42}/> <Nested/> -``` \ No newline at end of file +``` diff --git a/site/cypress/fixtures/example.json b/site/cypress/fixtures/example.json deleted file mode 100644 index da18d9352a..0000000000 --- a/site/cypress/fixtures/example.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "name": "Using fixtures to represent data", - "email": "hello@cypress.io", - "body": "Fixtures are a great way to mock data for responses to routes" -} \ No newline at end of file diff --git a/site/cypress/integration/spec.js b/site/cypress/integration/spec.js deleted file mode 100644 index 9a7140ddae..0000000000 --- a/site/cypress/integration/spec.js +++ /dev/null @@ -1,19 +0,0 @@ -describe('Sapper template app', () => { - beforeEach(() => { - cy.visit('/') - }); - - it('has the correct <h1>', () => { - cy.contains('h1', 'Great success!') - }); - - it('navigates to /about', () => { - cy.get('nav a').contains('about').click(); - cy.url().should('include', '/about'); - }); - - it('navigates to /blog', () => { - cy.get('nav a').contains('blog').click(); - cy.url().should('include', '/blog'); - }); -}); \ No newline at end of file diff --git a/site/cypress/plugins/index.js b/site/cypress/plugins/index.js deleted file mode 100644 index fd170fba69..0000000000 --- a/site/cypress/plugins/index.js +++ /dev/null @@ -1,17 +0,0 @@ -// *********************************************************** -// This example plugins/index.js can be used to load plugins -// -// You can change the location of this file or turn off loading -// the plugins file with the 'pluginsFile' configuration option. -// -// You can read more here: -// https://on.cypress.io/plugins-guide -// *********************************************************** - -// This function is called when a project is opened or re-opened (e.g. due to -// the project's config changing) - -module.exports = (on, config) => { - // `on` is used to hook into various events Cypress emits - // `config` is the resolved Cypress config -} diff --git a/site/cypress/support/commands.js b/site/cypress/support/commands.js deleted file mode 100644 index c1f5a772e2..0000000000 --- a/site/cypress/support/commands.js +++ /dev/null @@ -1,25 +0,0 @@ -// *********************************************** -// This example commands.js shows you how to -// create various custom commands and overwrite -// existing commands. -// -// For more comprehensive examples of custom -// commands please read more here: -// https://on.cypress.io/custom-commands -// *********************************************** -// -// -// -- This is a parent command -- -// Cypress.Commands.add("login", (email, password) => { ... }) -// -// -// -- This is a child command -- -// Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... }) -// -// -// -- This is a dual command -- -// Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... }) -// -// -// -- This is will overwrite an existing command -- -// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }) diff --git a/site/cypress/support/index.js b/site/cypress/support/index.js deleted file mode 100644 index d68db96df2..0000000000 --- a/site/cypress/support/index.js +++ /dev/null @@ -1,20 +0,0 @@ -// *********************************************************** -// This example support/index.js is processed and -// loaded automatically before your test files. -// -// This is a great place to put global configuration and -// behavior that modifies Cypress. -// -// You can change the location of this file or turn off -// automatically serving support files with the -// 'supportFile' configuration option. -// -// You can read more here: -// https://on.cypress.io/configuration -// *********************************************************** - -// Import commands.js using ES2015 syntax: -import './commands' - -// Alternatively you can use CommonJS syntax: -// require('./commands') diff --git a/site/package-lock.json b/site/package-lock.json index 819099a143..6d6f96eb21 100644 --- a/site/package-lock.json +++ b/site/package-lock.json @@ -1362,9 +1362,9 @@ } }, "@sveltejs/svelte-repl": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/@sveltejs/svelte-repl/-/svelte-repl-0.1.5.tgz", - "integrity": "sha512-gk7Ny/i19g3njob9lGGV5JzDed8eAaFphHidxquFGW5QgMCScEu+YgweBo+tRkRE0sJObFzMz3MjudH5o+KdIw==", + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/@sveltejs/svelte-repl/-/svelte-repl-0.1.8.tgz", + "integrity": "sha512-RSKsuiQE3DrdT7B7DNhd5DK+DkYGLT5m6Ugchxc8iN+5v/hfVTbeNb+KJtItXLpDxiYdbb0HIiQPEdy0M+HThw==", "dev": true, "requires": { "codemirror": "^5.45.0", @@ -4204,9 +4204,9 @@ } }, "sapper": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/sapper/-/sapper-0.27.1.tgz", - "integrity": "sha512-RH0K1uQ3zJ1IXvowxr2SuboGXV69q22KaPMhhoM5VNDv9fsUlVHtluZE8WTcGxckiO2L1xFfgM7v/aINkSZpcw==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/sapper/-/sapper-0.27.3.tgz", + "integrity": "sha512-JOSrQEw5bD3770edZ+gwdZxS/69sySl+0KuJyMiBQKRnb85cb55w/fBYg2SMhKDa/BlaXg14aL19OiBRpXGZLQ==", "dev": true, "requires": { "html-minifier": "^4.0.0", @@ -4671,9 +4671,9 @@ } }, "svelte": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/svelte/-/svelte-3.3.0.tgz", - "integrity": "sha512-iJYkIJDvAak1kizEYnE4b4eJ17D25fU0adW7GjDgO0klbjcAFlqtWEGFJa9kpJOlUtNLilcF09k4Y9TDmK/vjg==", + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/svelte/-/svelte-3.5.1.tgz", + "integrity": "sha512-iMnuyteFGQ8Yl68G/DHTHY1sLwoAMya1eS0ZOHIm/dqn2etR8WEe8hUAoluLryde4Cft4gvMhtHV3NhE60nBmQ==", "dev": true }, "tar": { @@ -4802,9 +4802,9 @@ } }, "uglify-js": { - "version": "3.5.14", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.5.14.tgz", - "integrity": "sha512-dgyjIw8KFK6AyVl5vm2tEqPewv5TKGEiiVFLI1LbF+oHua/Njd8tZk3lIbF1AWU1rNdEg7scaceADb4zqCcWXg==", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.6.0.tgz", + "integrity": "sha512-W+jrUHJr3DXKhrsS7NUVxn3zqMOFn0hL/Ei6v0anCIMoKC93TjcflTagwIHLW7SfMFfiQuktQyFVCFHGUE0+yg==", "dev": true, "requires": { "commander": "~2.20.0", diff --git a/site/package.json b/site/package.json index 01c77f62bd..28c5004189 100644 --- a/site/package.json +++ b/site/package.json @@ -7,13 +7,9 @@ "copy-workers": "rm -rf static/workers && cp -r node_modules/@sveltejs/svelte-repl/workers static", "migrate": "node-pg-migrate -r dotenv/config", "sapper": "npm run copy-workers && sapper build --legacy", - "update_shimport": "cp node_modules/shimport/index.js __sapper__/build/client/shimport@0.0.14.js", "update": "node scripts/update_template.js && node scripts/get-contributors.js", "start": "node __sapper__/build", - "cy:run": "cypress run", - "cy:open": "cypress open", - "test": "run-p --race dev cy:run", - "testsrc": "mocha -r esm test/**", + "test": "mocha -r esm test/**", "deploy": "make deploy" }, "dependencies": { @@ -39,7 +35,7 @@ "@babel/runtime": "^7.4.4", "@sindresorhus/slugify": "^0.9.1", "@sveltejs/site-kit": "^1.1.0", - "@sveltejs/svelte-repl": "^0.1.5", + "@sveltejs/svelte-repl": "^0.1.8", "degit": "^2.1.3", "dotenv": "^8.0.0", "eslint-plugin-svelte3": "^1.0.0", @@ -57,9 +53,9 @@ "rollup-plugin-replace": "^2.2.0", "rollup-plugin-svelte": "^5.0.3", "rollup-plugin-terser": "^4.0.4", - "sapper": "^0.27.1", + "sapper": "^0.27.3", "shelljs": "^0.8.3", - "svelte": "^3.0.0" + "svelte": "^3.5.1" }, "engines": { "node": ">=10.0.0" diff --git a/site/src/routes/_layout.svelte b/site/src/routes/_layout.svelte index 18c1d2a8b7..4adbb9b0dc 100644 --- a/site/src/routes/_layout.svelte +++ b/site/src/routes/_layout.svelte @@ -21,6 +21,7 @@ <NavItem segment="examples">Examples</NavItem> <NavItem segment="repl">REPL</NavItem> <NavItem segment="blog">Blog</NavItem> + <NavItem segment="faq">FAQ</NavItem> <NavItem external="https://sapper.svelte.dev">Sapper</NavItem> @@ -46,4 +47,4 @@ padding: var(--nav-h) 0 0 0; overflow-x: hidden; } -</style> \ No newline at end of file +</style> diff --git a/src/compiler/Stats.ts b/src/compiler/Stats.ts index c54f1e8ea9..200fa448e9 100644 --- a/src/compiler/Stats.ts +++ b/src/compiler/Stats.ts @@ -5,7 +5,7 @@ const now = (typeof process !== 'undefined' && process.hrtime) } : () => self.performance.now(); -type Timing = { +interface Timing { label: string; start: number; end: number; diff --git a/src/compiler/compile/Component.ts b/src/compiler/compile/Component.ts index e5f3501716..89c1e6b4f6 100644 --- a/src/compiler/compile/Component.ts +++ b/src/compiler/compile/Component.ts @@ -24,13 +24,13 @@ import unwrap_parens from './utils/unwrap_parens'; import Slot from './nodes/Slot'; import { Node as ESTreeNode } from 'estree'; -type ComponentOptions = { +interface ComponentOptions { namespace?: string; tag?: string; immutable?: boolean; accessors?: boolean; preserveWhitespace?: boolean; -}; +} // We need to tell estree-walker that it should always // look for an `else` block, otherwise it might get @@ -97,7 +97,7 @@ export default class Component { node_for_declaration: Map<string, Node> = new Map(); partly_hoisted: string[] = []; fully_hoisted: string[] = []; - reactive_declarations: Array<{ assignees: Set<string>, dependencies: Set<string>, node: Node, declaration: Node }> = []; + reactive_declarations: Array<{ assignees: Set<string>; dependencies: Set<string>; node: Node; declaration: Node }> = []; reactive_declaration_nodes: Set<Node> = new Set(); has_reactive_assignments = false; injected_reactive_declaration_vars: Set<string> = new Set(); @@ -106,12 +106,12 @@ export default class Component { indirect_dependencies: Map<string, Set<string>> = new Map(); file: string; - locate: (c: number) => { line: number, column: number }; + locate: (c: number) => { line: number; column: number }; // TODO this does the same as component.locate! remove one or the other locator: (search: number, startIndex?: number) => { - line: number, - column: number + line: number; + column: number; }; stylesheet: Stylesheet; @@ -140,6 +140,7 @@ export default class Component { this.compile_options = compile_options; this.file = compile_options.filename && ( + // eslint-disable-next-line no-useless-escape typeof process !== 'undefined' ? compile_options.filename.replace(process.cwd(), '').replace(/^[\/\\]/, '') : compile_options.filename ); this.locate = getLocator(this.source); @@ -248,7 +249,7 @@ export default class Component { result = result .replace(/__svelte:self__/g, this.name) - .replace(compile_options.generate === 'ssr' ? /(@+|#+)(\w*(?:-\w*)?)/g : /(@+)(\w*(?:-\w*)?)/g, (match: string, sigil: string, name: string) => { + .replace(compile_options.generate === 'ssr' ? /(@+|#+)(\w*(?:-\w*)?)/g : /(@+)(\w*(?:-\w*)?)/g, (_match: string, sigil: string, name: string) => { if (sigil === '@') { if (internal_exports.has(name)) { if (compile_options.dev && internal_exports.has(`${name}Dev`)) name = `${name}Dev`; @@ -379,7 +380,7 @@ export default class Component { reserved.forEach(add); internal_exports.forEach(add); - this.var_lookup.forEach((value, key) => add(key)); + this.var_lookup.forEach((_value, key) => add(key)); return (name: string) => { if (test) name = `${name}$`; @@ -398,12 +399,12 @@ export default class Component { error( pos: { - start: number, - end: number + start: number; + end: number; }, - e : { - code: string, - message: string + e: { + code: string; + message: string; } ) { error(e.message, { @@ -418,12 +419,12 @@ export default class Component { warn( pos: { - start: number, - end: number + start: number; + end: number; }, warning: { - code: string, - message: string + code: string; + message: string; } ) { if (!this.locator) { @@ -527,7 +528,7 @@ export default class Component { let result = ''; - script.content.body.forEach((node, i) => { + script.content.body.forEach((node) => { if (this.hoistable_nodes.has(node) || this.reactive_declaration_nodes.has(node)) { if (a !== b) result += `[✂${a}-${b}✂]`; a = node.end; @@ -564,7 +565,7 @@ export default class Component { this.add_sourcemap_locations(script.content); - let { scope, globals } = create_scopes(script.content); + const { scope, globals } = create_scopes(script.content); this.module_scope = scope; scope.declarations.forEach((node, name) => { @@ -588,7 +589,7 @@ export default class Component { this.error(node, { code: 'illegal-subscription', message: `Cannot reference store value inside <script context="module">` - }) + }); } else { this.add_var({ name, @@ -624,7 +625,7 @@ export default class Component { }); }); - let { scope: instance_scope, map, globals } = create_scopes(script.content); + const { scope: instance_scope, map, globals } = create_scopes(script.content); this.instance_scope = instance_scope; this.instance_scope_map = map; @@ -646,7 +647,7 @@ export default class Component { this.node_for_declaration.set(name, node); }); - globals.forEach((node, name) => { + globals.forEach((_node, name) => { if (this.var_lookup.has(name)) return; if (this.injected_reactive_declaration_vars.has(name)) { @@ -705,7 +706,7 @@ export default class Component { let scope = instance_scope; walk(this.ast.instance.content, { - enter(node, parent) { + enter(node) { if (map.has(node)) { scope = map.get(node); } @@ -738,7 +739,7 @@ export default class Component { scope = scope.parent; } } - }) + }); } extract_reactive_store_references() { @@ -786,7 +787,7 @@ export default class Component { } if (name[0] === '$' && name[1] !== '$') { - return `${name.slice(1)}.set(${name})` + return `${name.slice(1)}.set(${name})`; } if (variable && !variable.referenced && !variable.is_reactive_dependency && !variable.export_name && !name.startsWith('$$')) { @@ -888,13 +889,13 @@ export default class Component { } if (variable.writable && variable.name !== variable.export_name) { - code.prependRight(declarator.id.start, `${variable.export_name}: `) + code.prependRight(declarator.id.start, `${variable.export_name}: `); } if (next) { - const next_variable = component.var_lookup.get(next.id.name) + const next_variable = component.var_lookup.get(next.id.name); const new_declaration = !next_variable.export_name - || (current_group.insert && next_variable.subscribable) + || (current_group.insert && next_variable.subscribable); if (new_declaration) { code.overwrite(declarator.end, next.start, ` ${node.kind} `); @@ -904,7 +905,7 @@ export default class Component { current_group = null; if (variable.subscribable) { - let insert = get_insert(variable); + const insert = get_insert(variable); if (next) { code.overwrite(declarator.end, next.start, `; ${insert}; ${node.kind} `); @@ -975,9 +976,9 @@ export default class Component { if (!d.init) return false; if (d.init.type !== 'Literal') return false; - const v = this.var_lookup.get(d.id.name) - if (v.reassigned) return false - if (v.export_name) return false + const v = this.var_lookup.get(d.id.name); + if (v.reassigned) return false; + if (v.export_name) return false; if (this.var_lookup.get(d.id.name).reassigned) return false; if (this.vars.find(variable => variable.name === d.id.name && variable.module)) return false; @@ -1006,7 +1007,7 @@ export default class Component { }); const checked = new Set(); - let walking = new Set(); + const walking = new Set(); const is_hoistable = fn_declaration => { if (fn_declaration.type === 'ExportNamedDeclaration') { @@ -1015,7 +1016,7 @@ export default class Component { const instance_scope = this.instance_scope; let scope = this.instance_scope; - let map = this.instance_scope_map; + const map = this.instance_scope_map; let hoistable = true; @@ -1051,7 +1052,7 @@ export default class Component { hoistable = false; } else if (!is_hoistable(other_declaration)) { hoistable = false; - } + } } else { @@ -1103,7 +1104,7 @@ export default class Component { const dependencies = new Set(); let scope = this.instance_scope; - let map = this.instance_scope_map; + const map = this.instance_scope_map; walk(node.body, { enter(node, parent) { @@ -1320,14 +1321,16 @@ function process_component_options(component: Component, nodes) { case 'accessors': case 'immutable': case 'preserveWhitespace': + { const code = `invalid-${name}-value`; - const message = `${name} attribute must be true or false` + const message = `${name} attribute must be true or false`; const value = get_value(attribute, code, message); if (typeof value !== 'boolean') component.error(attribute, { code, message }); component_options[name] = value; break; + } default: component.error(attribute, { diff --git a/src/compiler/compile/create_module.ts b/src/compiler/compile/create_module.ts index ae5232021d..54b891d4ac 100644 --- a/src/compiler/compile/create_module.ts +++ b/src/compiler/compile/create_module.ts @@ -5,10 +5,10 @@ import { stringify_props } from './utils/stringify_props'; const wrappers = { esm, cjs }; -type Export = { +interface Export { name: string; as: string; -}; +} export default function create_module( code: string, @@ -16,7 +16,7 @@ export default function create_module( name: string, banner: string, sveltePath = 'svelte', - helpers: { name: string, alias: string }[], + helpers: Array<{ name: string; alias: string }>, imports: Node[], module_exports: Export[], source: string @@ -44,7 +44,7 @@ function esm( banner: string, sveltePath: string, internal_path: string, - helpers: { name: string, alias: string }[], + helpers: Array<{ name: string; alias: string }>, imports: Node[], module_exports: Export[], source: string @@ -84,7 +84,7 @@ function cjs( banner: string, sveltePath: string, internal_path: string, - helpers: { name: string, alias: string }[], + helpers: Array<{ name: string; alias: string }>, imports: Node[], module_exports: Export[] ) { @@ -115,7 +115,7 @@ function cjs( const source = edit_source(node.source.value, sveltePath); - return `const ${lhs} = require("${source}");` + return `const ${lhs} = require("${source}");`; }); const exports = [`exports.default = ${name};`].concat( @@ -131,5 +131,5 @@ function cjs( ${code} - ${exports}` -} \ No newline at end of file + ${exports}`; +} diff --git a/src/compiler/compile/css/Selector.ts b/src/compiler/compile/css/Selector.ts index 854acde216..bb4a29ebe3 100644 --- a/src/compiler/compile/css/Selector.ts +++ b/src/compiler/compile/css/Selector.ts @@ -73,7 +73,7 @@ export default class Selector { } } - this.blocks.forEach((block, i) => { + this.blocks.forEach((block) => { if (block.global) { const selector = block.selectors[0]; const first = selector.children[0]; @@ -238,7 +238,7 @@ function attribute_matches(node: Node, name: string, expected_value: string, ope } function class_matches(node, name: string) { - return node.classes.some(function(class_directive) { + return node.classes.some((class_directive) => { return new RegExp(`\\b${name}\\b`).test(class_directive.name); }); } @@ -287,7 +287,7 @@ function group_selectors(selector: Node) { const blocks = [block]; - selector.children.forEach((child: Node, i: number) => { + selector.children.forEach((child: Node) => { if (child.type === 'WhiteSpace' || child.type === 'Combinator') { block = new Block(child); blocks.push(block); diff --git a/src/compiler/compile/css/Stylesheet.ts b/src/compiler/compile/css/Stylesheet.ts index 3b1dedc467..2aead635b2 100644 --- a/src/compiler/compile/css/Stylesheet.ts +++ b/src/compiler/compile/css/Stylesheet.ts @@ -43,11 +43,11 @@ class Rule { return this.selectors.some(s => s.used); } - minify(code: MagicString, dev: boolean) { + minify(code: MagicString, _dev: boolean) { let c = this.node.start; let started = false; - this.selectors.forEach((selector, i) => { + this.selectors.forEach((selector) => { if (selector.used) { const separator = started ? ',' : ''; if ((selector.node.start - c) > separator.length) { @@ -140,7 +140,7 @@ class Declaration { class Atrule { node: Node; - children: (Atrule|Rule)[]; + children: Array<Atrule|Rule>; constructor(node: Node) { this.node = node; @@ -163,7 +163,7 @@ class Atrule { } } - is_used(dev: boolean) { + is_used(_dev: boolean) { return true; // TODO } @@ -253,7 +253,7 @@ export default class Stylesheet { has_styles: boolean; id: string; - children: (Rule|Atrule)[] = []; + children: Array<Rule|Atrule> = []; keyframes: Map<string, string> = new Map(); nodes_with_css_class: Set<Node> = new Set(); @@ -269,7 +269,7 @@ export default class Stylesheet { this.has_styles = true; - const stack: (Rule | Atrule)[] = []; + const stack: Array<Rule | Atrule> = []; let current_atrule: Atrule = null; walk(ast.css, { diff --git a/src/compiler/compile/index.ts b/src/compiler/compile/index.ts index 2ad091c971..63f9b5f610 100644 --- a/src/compiler/compile/index.ts +++ b/src/compiler/compile/index.ts @@ -1,11 +1,12 @@ -import { assign } from '../../runtime/internal/index'; +import { assign } from '../../runtime/internal/utils'; import Stats from '../Stats'; import parse from '../parse/index'; import render_dom from './render-dom/index'; import render_ssr from './render-ssr/index'; -import { CompileOptions, Ast, Warning } from '../interfaces'; +import { CompileOptions, Warning } from '../interfaces'; import Component from './Component'; import fuzzymatch from '../utils/fuzzymatch'; +import { get_name_from_filename } from './utils/get_name_from_filename'; const valid_options = [ 'format', @@ -55,43 +56,23 @@ function validate_options(options: CompileOptions, warnings: Warning[]) { } } -function get_name(filename: string) { - if (!filename) return null; - const parts = filename.split(/[\/\\]/); - - if (parts.length > 1 && /^index\.\w+/.test(parts[parts.length - 1])) { - parts.pop(); - } - - const base = parts.pop() - .replace(/\..+/, "") - .replace(/[^a-zA-Z_$0-9]+/g, '_') - .replace(/^_/, '') - .replace(/_$/, '') - .replace(/^(\d)/, '_$1'); - - return base[0].toUpperCase() + base.slice(1); -} - export default function compile(source: string, options: CompileOptions = {}) { options = assign({ generate: 'dom', dev: false }, options); const stats = new Stats(); const warnings = []; - let ast: Ast; - validate_options(options, warnings); stats.start('parse'); - ast = parse(source, options); + const ast = parse(source, options); stats.stop('parse'); stats.start('create component'); const component = new Component( ast, source, - options.name || get_name(options.filename) || 'Component', + options.name || get_name_from_filename(options.filename) || 'Component', options, stats, warnings diff --git a/src/compiler/compile/nodes/Attribute.ts b/src/compiler/compile/nodes/Attribute.ts index 0b2d3a3700..ef413c31a2 100644 --- a/src/compiler/compile/nodes/Attribute.ts +++ b/src/compiler/compile/nodes/Attribute.ts @@ -21,7 +21,7 @@ export default class Attribute extends Node { is_synthetic: boolean; should_cache: boolean; expression?: Expression; - chunks: (Text | Expression)[]; + chunks: Array<Text | Expression>; dependencies: Set<string>; constructor(component, parent, scope, info) { diff --git a/src/compiler/compile/nodes/EachBlock.ts b/src/compiler/compile/nodes/EachBlock.ts index 2f18373137..adaa46b8db 100644 --- a/src/compiler/compile/nodes/EachBlock.ts +++ b/src/compiler/compile/nodes/EachBlock.ts @@ -8,13 +8,13 @@ import { Node as INode } from '../../interfaces'; import { new_tail } from '../utils/tail'; import Element from './Element'; -type Context = { - key: INode, - name?: string, - tail: string -}; +interface Context { + key: INode; + name?: string; + tail: string; +} -function unpack_destructuring(contexts: Array<Context>, node: INode, tail: string) { +function unpack_destructuring(contexts: Context[], node: INode, tail: string) { if (!node) return; if (node.type === 'Identifier' || node.type === 'RestIdentifier') { @@ -25,7 +25,7 @@ function unpack_destructuring(contexts: Array<Context>, node: INode, tail: strin } else if (node.type === 'ArrayPattern') { node.elements.forEach((element, i) => { if (element && element.type === 'RestIdentifier') { - unpack_destructuring(contexts, element, `${tail}.slice(${i})`) + unpack_destructuring(contexts, element, `${tail}.slice(${i})`); } else { unpack_destructuring(contexts, element, `${tail}[${i}]`); } @@ -60,7 +60,7 @@ export default class EachBlock extends AbstractBlock { context: string; key: Expression; scope: TemplateScope; - contexts: Array<Context>; + contexts: Context[]; has_animation: boolean; has_binding = false; diff --git a/src/compiler/compile/nodes/Element.ts b/src/compiler/compile/nodes/Element.ts index 1b2d82188c..3e883200a7 100644 --- a/src/compiler/compile/nodes/Element.ts +++ b/src/compiler/compile/nodes/Element.ts @@ -54,7 +54,7 @@ const a11y_required_content = new Set([ 'h4', 'h5', 'h6' -]) +]); const invisible_elements = new Set(['meta', 'html', 'script', 'style']); @@ -180,10 +180,12 @@ export default class Element extends Node { break; case 'Transition': + { const transition = new Transition(component, this, scope, node); if (node.intro) this.intro = transition; if (node.outro) this.outro = transition; break; + } case 'Animation': this.animation = new Animation(component, this, scope, node); @@ -605,6 +607,25 @@ export default class Element extends Node { message: `'${binding.name}' is not a valid binding on void elements like <${this.name}>. Use a wrapper element instead` }); } + } else if ( + name === 'text' || + name === 'html' + ) { + const contenteditable = this.attributes.find( + (attribute: Attribute) => attribute.name === 'contenteditable' + ); + + if (!contenteditable) { + component.error(binding, { + code: `missing-contenteditable-attribute`, + message: `'contenteditable' attribute is required for text and html two-way bindings` + }); + } else if (contenteditable && !contenteditable.is_static) { + component.error(contenteditable, { + code: `dynamic-contenteditable-attribute`, + message: `'contenteditable' attribute cannot be dynamic if element uses two-way binding` + }); + } } else if (name !== 'this') { component.error(binding, { code: `invalid-binding`, @@ -687,7 +708,7 @@ export default class Element extends Node { if (class_attribute.chunks.length === 1 && class_attribute.chunks[0].type === 'Text') { (class_attribute.chunks[0] as Text).data += ` ${class_name}`; } else { - (<Node[]>class_attribute.chunks).push( + (class_attribute.chunks as Node[]).push( new Text(this.component, this, this.scope, { type: 'Text', data: ` ${class_name}` diff --git a/src/compiler/compile/nodes/InlineComponent.ts b/src/compiler/compile/nodes/InlineComponent.ts index 8b6cd77282..6db6f1b327 100644 --- a/src/compiler/compile/nodes/InlineComponent.ts +++ b/src/compiler/compile/nodes/InlineComponent.ts @@ -36,6 +36,7 @@ export default class InlineComponent extends Node { : null; info.attributes.forEach(node => { + /* eslint-disable no-fallthrough */ switch (node.type) { case 'Action': component.error(node, { @@ -82,6 +83,7 @@ export default class InlineComponent extends Node { default: throw new Error(`Not implemented: ${node.type}`); } + /* eslint-enable no-fallthrough */ }); if (this.lets.length > 0) { @@ -98,6 +100,17 @@ export default class InlineComponent extends Node { this.scope = scope; } + this.handlers.forEach(handler => { + handler.modifiers.forEach(modifier => { + if (modifier !== 'once') { + component.error(handler, { + code: 'invalid-event-modifier', + message: `Event modifiers other than 'once' can only be used on DOM elements` + }); + } + }); + }); + this.children = map_children(component, this, this.scope, info.children); } } diff --git a/src/compiler/compile/nodes/PendingBlock.ts b/src/compiler/compile/nodes/PendingBlock.ts index 5ff7352558..44ee4a3a10 100644 --- a/src/compiler/compile/nodes/PendingBlock.ts +++ b/src/compiler/compile/nodes/PendingBlock.ts @@ -2,7 +2,7 @@ import map_children from './shared/map_children'; import AbstractBlock from './shared/AbstractBlock'; export default class PendingBlock extends AbstractBlock { - type: 'PendingBlock'; + type: 'PendingBlock'; constructor(component, parent, scope, info) { super(component, parent, scope, info); this.children = map_children(component, parent, scope, info.children); diff --git a/src/compiler/compile/nodes/Text.ts b/src/compiler/compile/nodes/Text.ts index 7500f5ff30..a4514f56f2 100644 --- a/src/compiler/compile/nodes/Text.ts +++ b/src/compiler/compile/nodes/Text.ts @@ -12,7 +12,7 @@ export default class Text extends Node { super(component, parent, scope, info); this.data = info.data; - if (!component.component_options.preserveWhitespace && !/\S/.test(info.data)) { + if (!component.component_options.preserveWhitespace && !/[\S\u00A0]/.test(info.data)) { let node = parent; while (node) { if (node.type === 'Element' && node.name === 'pre') { diff --git a/src/compiler/compile/nodes/Window.ts b/src/compiler/compile/nodes/Window.ts index 7ddf109ab3..d1e61fb1fc 100644 --- a/src/compiler/compile/nodes/Window.ts +++ b/src/compiler/compile/nodes/Window.ts @@ -44,8 +44,8 @@ export default class Window extends Node { if (!~valid_bindings.indexOf(node.name)) { const match = ( node.name === 'width' ? 'innerWidth' : - node.name === 'height' ? 'innerHeight' : - fuzzymatch(node.name, valid_bindings) + node.name === 'height' ? 'innerHeight' : + fuzzymatch(node.name, valid_bindings) ); const message = `'${node.name}' is not a valid binding on <svelte:window>`; diff --git a/src/compiler/compile/nodes/interfaces.ts b/src/compiler/compile/nodes/interfaces.ts index 434b09e5aa..752168a49d 100644 --- a/src/compiler/compile/nodes/interfaces.ts +++ b/src/compiler/compile/nodes/interfaces.ts @@ -33,32 +33,32 @@ import Window from './Window'; // note: to write less types each of types in union below should have type defined as literal // https://www.typescriptlang.org/docs/handbook/advanced-types.html#discriminated-unions export type INode = Action - | Animation - | Attribute - | AwaitBlock - | Binding - | Body - | CatchBlock - | Class - | Comment - | DebugTag - | EachBlock - | Element - | ElseBlock - | EventHandler - | Fragment - | Head - | IfBlock - | InlineComponent - | Let - | MustacheTag - | Options - | PendingBlock - | RawMustacheTag - | Slot - | Tag - | Text - | ThenBlock - | Title - | Transition - | Window; +| Animation +| Attribute +| AwaitBlock +| Binding +| Body +| CatchBlock +| Class +| Comment +| DebugTag +| EachBlock +| Element +| ElseBlock +| EventHandler +| Fragment +| Head +| IfBlock +| InlineComponent +| Let +| MustacheTag +| Options +| PendingBlock +| RawMustacheTag +| Slot +| Tag +| Text +| ThenBlock +| Title +| Transition +| Window; diff --git a/src/compiler/compile/nodes/shared/Expression.ts b/src/compiler/compile/nodes/shared/Expression.ts index e7c63dfec2..004ae716b9 100644 --- a/src/compiler/compile/nodes/shared/Expression.ts +++ b/src/compiler/compile/nodes/shared/Expression.ts @@ -4,10 +4,10 @@ import is_reference from 'is-reference'; import flatten_reference from '../../utils/flatten_reference'; import { create_scopes, Scope, extract_names } from '../../utils/scope'; import { Node } from '../../../interfaces'; -import { globals } from '../../../utils/names'; +import { globals , sanitize } from '../../../utils/names'; import deindent from '../../utils/deindent'; import Wrapper from '../../render-dom/wrappers/shared/Wrapper'; -import { sanitize } from '../../../utils/names'; + import TemplateScope from './TemplateScope'; import get_object from '../../utils/get_object'; import { nodes_match } from '../../../utils/nodes_match'; @@ -28,8 +28,8 @@ const binary_operators: Record<string, number> = { '<=': 11, '>': 11, '>=': 11, - 'in': 11, - 'instanceof': 11, + in: 11, + instanceof: 11, '==': 10, '!=': 10, '===': 10, @@ -490,7 +490,7 @@ export default class Expression { } } -function get_function_name(node, parent) { +function get_function_name(_node, parent) { if (parent.type === 'EventHandler') { return `${parent.name}_handler`; } diff --git a/src/compiler/compile/nodes/shared/Node.ts b/src/compiler/compile/nodes/shared/Node.ts index 8fa0ec0c97..7435f1eab8 100644 --- a/src/compiler/compile/nodes/shared/Node.ts +++ b/src/compiler/compile/nodes/shared/Node.ts @@ -17,7 +17,7 @@ export default class Node { var: string; attributes: Attribute[]; - constructor(component: Component, parent, scope, info: any) { + constructor(component: Component, parent, _scope, info: any) { this.start = info.start; this.end = info.end; this.type = info.type; diff --git a/src/compiler/compile/render-dom/Block.ts b/src/compiler/compile/render-dom/Block.ts index b95a1a8871..0c585c5bf0 100644 --- a/src/compiler/compile/render-dom/Block.ts +++ b/src/compiler/compile/render-dom/Block.ts @@ -9,7 +9,7 @@ export interface BlockOptions { renderer?: Renderer; comment?: string; key?: string; - bindings?: Map<string, { object: string, property: string, snippet: string }>; + bindings?: Map<string, { object: string; property: string; snippet: string }>; dependencies?: Set<string>; } @@ -26,7 +26,7 @@ export default class Block { dependencies: Set<string>; - bindings: Map<string, { object: string, property: string, snippet: string }>; + bindings: Map<string, { object: string; property: string; snippet: string }>; builders: { init: CodeBuilder; @@ -357,6 +357,7 @@ export default class Block { `); } + /* eslint-disable @typescript-eslint/indent,indent */ return deindent` ${this.variables.size > 0 && `var ${Array.from(this.variables.keys()) @@ -371,9 +372,10 @@ export default class Block { return { ${properties} }; - `.replace(/(#+)(\w*)/g, (match: string, sigil: string, name: string) => { + `.replace(/(#+)(\w*)/g, (_match: string, sigil: string, name: string) => { return sigil === '#' ? this.alias(name) : sigil.slice(1) + name; }); + /* eslint-enable @typescript-eslint/indent,indent */ } render_listeners(chunk: string = '') { @@ -387,7 +389,7 @@ export default class Block { this.builders.destroy.add_line( `#dispose${chunk}();` - ) + ); } else { this.builders.hydrate.add_block(deindent` #dispose${chunk} = [ diff --git a/src/compiler/compile/render-dom/Renderer.ts b/src/compiler/compile/render-dom/Renderer.ts index ea07c1544f..4c61594aa8 100644 --- a/src/compiler/compile/render-dom/Renderer.ts +++ b/src/compiler/compile/render-dom/Renderer.ts @@ -8,7 +8,7 @@ export default class Renderer { component: Component; // TODO Maybe Renderer shouldn't know about Component? options: CompileOptions; - blocks: (Block | string)[] = []; + blocks: Array<Block | string> = []; readonly: Set<string> = new Set(); meta_bindings: CodeBuilder = new CodeBuilder(); // initial values for e.g. window.innerWidth, if there's a <svelte:window> meta tag binding_groups: string[] = []; @@ -17,7 +17,7 @@ export default class Renderer { fragment: FragmentWrapper; file_var: string; - locate: (c: number) => { line: number; column: number; }; + locate: (c: number) => { line: number; column: number }; constructor(component: Component, options: CompileOptions) { this.component = component; diff --git a/src/compiler/compile/render-dom/index.ts b/src/compiler/compile/render-dom/index.ts index 37aa017655..46aa705bfb 100644 --- a/src/compiler/compile/render-dom/index.ts +++ b/src/compiler/compile/render-dom/index.ts @@ -74,18 +74,20 @@ export default function dom( const props = component.vars.filter(variable => !variable.module && variable.export_name); const writable_props = props.filter(variable => variable.writable); + /* eslint-disable @typescript-eslint/indent,indent */ const set = (uses_props || writable_props.length > 0 || component.slots.size > 0) ? deindent` ${$$props} => { ${uses_props && component.invalidate('$$props', `$$props = @assign(@assign({}, $$props), $$new_props)`)} ${writable_props.map(prop => - `if ('${prop.export_name}' in $$props) ${component.invalidate(prop.name, `${prop.name} = $$props.${prop.export_name}`)};` + `if ('${prop.export_name}' in $$props) ${component.invalidate(prop.name, `${prop.name} = $$props.${prop.export_name}`)};` )} ${component.slots.size > 0 && `if ('$$scope' in ${$$props}) ${component.invalidate('$$scope', `$$scope = ${$$props}.$$scope`)};`} } ` : null; + /* eslint-enable @typescript-eslint/indent,indent */ const body = []; @@ -152,12 +154,12 @@ export default function dom( // instrument assignments if (component.ast.instance) { let scope = component.instance_scope; - let map = component.instance_scope_map; + const map = component.instance_scope_map; let pending_assignments = new Set(); walk(component.ast.instance.content, { - enter: (node, parent) => { + enter: (node) => { if (map.has(node)) { scope = map.get(node); } @@ -390,7 +392,7 @@ export default function dom( const store = component.var_lookup.get(name); if (store && store.reassigned) { - return `${$name}, $$unsubscribe_${name} = @noop, $$subscribe_${name} = () => { $$unsubscribe_${name}(); $$unsubscribe_${name} = ${name}.subscribe($$value => { ${$name} = $$value; $$invalidate('${$name}', ${$name}); }) }` + return `${$name}, $$unsubscribe_${name} = @noop, $$subscribe_${name} = () => { $$unsubscribe_${name}(); $$unsubscribe_${name} = ${name}.subscribe($$value => { ${$name} = $$value; $$invalidate('${$name}', ${$name}); }) }`; } return $name; diff --git a/src/compiler/compile/render-dom/wrappers/Body.ts b/src/compiler/compile/render-dom/wrappers/Body.ts index ca6c9df43f..04e677a090 100644 --- a/src/compiler/compile/render-dom/wrappers/Body.ts +++ b/src/compiler/compile/render-dom/wrappers/Body.ts @@ -6,7 +6,7 @@ import Body from '../../nodes/Body'; export default class BodyWrapper extends Wrapper { node: Body; - render(block: Block, parent_node: string, parent_nodes: string) { + render(block: Block, _parent_node: string, _parent_nodes: string) { this.node.handlers.forEach(handler => { const snippet = handler.render(block); diff --git a/src/compiler/compile/render-dom/wrappers/DebugTag.ts b/src/compiler/compile/render-dom/wrappers/DebugTag.ts index bdad6d2493..713113921d 100644 --- a/src/compiler/compile/render-dom/wrappers/DebugTag.ts +++ b/src/compiler/compile/render-dom/wrappers/DebugTag.ts @@ -13,13 +13,13 @@ export default class DebugTagWrapper extends Wrapper { block: Block, parent: Wrapper, node: DebugTag, - strip_whitespace: boolean, - next_sibling: Wrapper + _strip_whitespace: boolean, + _next_sibling: Wrapper ) { super(renderer, block, parent, node); } - render(block: Block, parent_node: string, parent_nodes: string) { + render(block: Block, _parent_node: string, _parent_nodes: string) { const { renderer } = this; const { component } = renderer; diff --git a/src/compiler/compile/render-dom/wrappers/EachBlock.ts b/src/compiler/compile/render-dom/wrappers/EachBlock.ts index 9d23eb7309..a1a875a12f 100644 --- a/src/compiler/compile/render-dom/wrappers/EachBlock.ts +++ b/src/compiler/compile/render-dom/wrappers/EachBlock.ts @@ -425,7 +425,7 @@ export default class EachBlockWrapper extends Wrapper { all_dependencies.add(dependency); }); - const outro_block = this.block.has_outros && block.get_unique_name('outro_block') + const outro_block = this.block.has_outros && block.get_unique_name('outro_block'); if (outro_block) { block.builders.init.add_block(deindent` function ${outro_block}(i, detaching, local) { diff --git a/src/compiler/compile/render-dom/wrappers/Element/Attribute.ts b/src/compiler/compile/render-dom/wrappers/Element/Attribute.ts index 876496e2f6..f55e731fdb 100644 --- a/src/compiler/compile/render-dom/wrappers/Element/Attribute.ts +++ b/src/compiler/compile/render-dom/wrappers/Element/Attribute.ts @@ -52,7 +52,7 @@ export default class AttributeWrapper { element.node.bindings.find( (binding) => /checked|group/.test(binding.name) - ))); + ))); const property_name = is_indirectly_bound_value ? '__value' @@ -70,7 +70,7 @@ export default class AttributeWrapper { const is_legacy_input_type = element.renderer.component.compile_options.legacy && name === 'type' && this.parent.node.name === 'input'; const is_dataset = /^data-/.test(name) && !element.renderer.component.compile_options.legacy && !element.node.namespace; - const camel_case_name = is_dataset ? name.replace('data-', '').replace(/(-\w)/g, function (m) { + const camel_case_name = is_dataset ? name.replace('data-', '').replace(/(-\w)/g, (m) => { return m[1].toUpperCase(); }) : name; @@ -219,84 +219,25 @@ export default class AttributeWrapper { return `="${value.map(chunk => { return chunk.type === 'Text' ? chunk.data.replace(/"/g, '\\"') - : `\${${chunk.render()}}` + : `\${${chunk.render()}}`; })}"`; } } -// source: https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes +// source: https://html.spec.whatwg.org/multipage/indices.html const attribute_lookup = { - accept: { applies_to: ['form', 'input'] }, - 'accept-charset': { property_name: 'acceptCharset', applies_to: ['form'] }, - accesskey: { property_name: 'accessKey' }, - action: { applies_to: ['form'] }, - align: { - applies_to: [ - 'applet', - 'caption', - 'col', - 'colgroup', - 'hr', - 'iframe', - 'img', - 'table', - 'tbody', - 'td', - 'tfoot', - 'th', - 'thead', - 'tr', - ], - }, allowfullscreen: { property_name: 'allowFullscreen', applies_to: ['iframe'] }, - alt: { applies_to: ['applet', 'area', 'img', 'input'] }, + allowpaymentrequest: { property_name: 'allowPaymentRequest', applies_to: ['iframe'] }, async: { applies_to: ['script'] }, - autocomplete: { applies_to: ['form', 'input'] }, autofocus: { applies_to: ['button', 'input', 'keygen', 'select', 'textarea'] }, autoplay: { applies_to: ['audio', 'video'] }, - autosave: { applies_to: ['input'] }, - bgcolor: { - property_name: 'bgColor', - applies_to: [ - 'body', - 'col', - 'colgroup', - 'marquee', - 'table', - 'tbody', - 'tfoot', - 'td', - 'th', - 'tr', - ], - }, - border: { applies_to: ['img', 'object', 'table'] }, - buffered: { applies_to: ['audio', 'video'] }, - challenge: { applies_to: ['keygen'] }, - charset: { applies_to: ['meta', 'script'] }, - checked: { applies_to: ['command', 'input'] }, - cite: { applies_to: ['blockquote', 'del', 'ins', 'q'] }, - class: { property_name: 'className' }, - code: { applies_to: ['applet'] }, - codebase: { property_name: 'codeBase', applies_to: ['applet'] }, - color: { applies_to: ['basefont', 'font', 'hr'] }, - cols: { applies_to: ['textarea'] }, - colspan: { property_name: 'colSpan', applies_to: ['td', 'th'] }, - content: { applies_to: ['meta'] }, - contenteditable: { property_name: 'contentEditable' }, - contextmenu: {}, + checked: { applies_to: ['input'] }, controls: { applies_to: ['audio', 'video'] }, - coords: { applies_to: ['area'] }, - data: { applies_to: ['object'] }, - datetime: { property_name: 'dateTime', applies_to: ['del', 'ins', 'time'] }, default: { applies_to: ['track'] }, defer: { applies_to: ['script'] }, - dir: {}, - dirname: { property_name: 'dirName', applies_to: ['input', 'textarea'] }, disabled: { applies_to: [ 'button', - 'command', 'fieldset', 'input', 'keygen', @@ -306,119 +247,21 @@ const attribute_lookup = { 'textarea', ], }, - download: { applies_to: ['a', 'area'] }, - draggable: {}, - dropzone: {}, - enctype: { applies_to: ['form'] }, - for: { property_name: 'htmlFor', applies_to: ['label', 'output'] }, - formaction: { applies_to: ['input', 'button'] }, - headers: { applies_to: ['td', 'th'] }, - height: { - applies_to: ['canvas', 'embed', 'iframe', 'img', 'input', 'object', 'video'], - }, + formnovalidate: { property_name: 'formNoValidate', applies_to: ['button', 'input'] }, hidden: {}, - high: { applies_to: ['meter'] }, - href: { applies_to: ['a', 'area', 'base', 'link'] }, - hreflang: { applies_to: ['a', 'area', 'link'] }, - 'http-equiv': { property_name: 'httpEquiv', applies_to: ['meta'] }, - icon: { applies_to: ['command'] }, - id: {}, indeterminate: { applies_to: ['input'] }, ismap: { property_name: 'isMap', applies_to: ['img'] }, - itemprop: {}, - keytype: { applies_to: ['keygen'] }, - kind: { applies_to: ['track'] }, - label: { applies_to: ['track'] }, - lang: {}, - language: { applies_to: ['script'] }, - loop: { applies_to: ['audio', 'bgsound', 'marquee', 'video'] }, - low: { applies_to: ['meter'] }, - manifest: { applies_to: ['html'] }, - max: { applies_to: ['input', 'meter', 'progress'] }, - maxlength: { property_name: 'maxLength', applies_to: ['input', 'textarea'] }, - media: { applies_to: ['a', 'area', 'link', 'source', 'style'] }, - method: { applies_to: ['form'] }, - min: { applies_to: ['input', 'meter'] }, + loop: { applies_to: ['audio', 'bgsound', 'video'] }, multiple: { applies_to: ['input', 'select'] }, muted: { applies_to: ['audio', 'video'] }, - name: { - applies_to: [ - 'button', - 'form', - 'fieldset', - 'iframe', - 'input', - 'keygen', - 'object', - 'output', - 'select', - 'textarea', - 'map', - 'meta', - 'param', - ], - }, + nomodule: { property_name: 'noModule', applies_to: ['script'] }, novalidate: { property_name: 'noValidate', applies_to: ['form'] }, - open: { applies_to: ['details'] }, - optimum: { applies_to: ['meter'] }, - pattern: { applies_to: ['input'] }, - ping: { applies_to: ['a', 'area'] }, - placeholder: { applies_to: ['input', 'textarea'] }, - poster: { applies_to: ['video'] }, - preload: { applies_to: ['audio', 'video'] }, - radiogroup: { applies_to: ['command'] }, + open: { applies_to: ['details', 'dialog'] }, + playsinline: { property_name: 'playsInline', applies_to: ['video'] }, readonly: { property_name: 'readOnly', applies_to: ['input', 'textarea'] }, - rel: { applies_to: ['a', 'area', 'link'] }, required: { applies_to: ['input', 'select', 'textarea'] }, reversed: { applies_to: ['ol'] }, - rows: { applies_to: ['textarea'] }, - rowspan: { property_name: 'rowSpan', applies_to: ['td', 'th'] }, - sandbox: { applies_to: ['iframe'] }, - scope: { applies_to: ['th'] }, - scoped: { applies_to: ['style'] }, - seamless: { applies_to: ['iframe'] }, selected: { applies_to: ['option'] }, - shape: { applies_to: ['a', 'area'] }, - size: { applies_to: ['input', 'select'] }, - sizes: { applies_to: ['link', 'img', 'source'] }, - span: { applies_to: ['col', 'colgroup'] }, - spellcheck: {}, - src: { - applies_to: [ - 'audio', - 'embed', - 'iframe', - 'img', - 'input', - 'script', - 'source', - 'track', - 'video', - ], - }, - srcdoc: { applies_to: ['iframe'] }, - srclang: { applies_to: ['track'] }, - srcset: { applies_to: ['img'] }, - start: { applies_to: ['ol'] }, - step: { applies_to: ['input'] }, - style: { property_name: 'style.cssText' }, - summary: { applies_to: ['table'] }, - tabindex: { property_name: 'tabIndex' }, - target: { applies_to: ['a', 'area', 'base', 'form'] }, - title: {}, - type: { - applies_to: [ - 'button', - 'command', - 'embed', - 'object', - 'script', - 'source', - 'style', - 'menu', - ], - }, - usemap: { property_name: 'useMap', applies_to: ['img', 'input', 'object'] }, value: { applies_to: [ 'button', @@ -432,12 +275,6 @@ const attribute_lookup = { 'textarea', ], }, - volume: { applies_to: ['audio', 'video'] }, - playbackRate: { applies_to: ['audio', 'video'] }, - width: { - applies_to: ['canvas', 'embed', 'iframe', 'img', 'input', 'object', 'video'], - }, - wrap: { applies_to: ['textarea'] }, }; Object.keys(attribute_lookup).forEach(name => { diff --git a/src/compiler/compile/render-dom/wrappers/Element/Binding.ts b/src/compiler/compile/render-dom/wrappers/Element/Binding.ts index 70123fa10c..15ceabb356 100644 --- a/src/compiler/compile/render-dom/wrappers/Element/Binding.ts +++ b/src/compiler/compile/render-dom/wrappers/Element/Binding.ts @@ -1,6 +1,5 @@ import Binding from '../../../nodes/Binding'; import ElementWrapper from '../Element'; -import { dimensions } from '../../../../utils/patterns'; import get_object from '../../../utils/get_object'; import Block from '../../Block'; import Node from '../../../nodes/shared/Node'; @@ -23,8 +22,8 @@ export default class BindingWrapper { handler: { uses_context: boolean; mutation: string; - contextual_dependencies: Set<string>, - snippet?: string + contextual_dependencies: Set<string>; + snippet?: string; }; snippet: string; is_readonly: boolean; @@ -87,7 +86,7 @@ export default class BindingWrapper { } is_readonly_media_attribute() { - return this.node.is_readonly_media_attribute() + return this.node.is_readonly_media_attribute(); } render(block: Block, lock: string) { @@ -95,23 +94,23 @@ export default class BindingWrapper { const { parent } = this; - let update_conditions: string[] = this.needs_lock ? [`!${lock}`] : []; + const update_conditions: string[] = this.needs_lock ? [`!${lock}`] : []; const dependency_array = [...this.node.expression.dependencies]; if (dependency_array.length === 1) { - update_conditions.push(`changed.${dependency_array[0]}`) + update_conditions.push(`changed.${dependency_array[0]}`); } else if (dependency_array.length > 1) { update_conditions.push( `(${dependency_array.map(prop => `changed.${prop}`).join(' || ')})` - ) + ); } if (parent.node.name === 'input') { const type = parent.node.get_static_attribute_value('type'); if (type === null || type === "" || type === "text") { - update_conditions.push(`(${parent.var}.${this.node.name} !== ${this.snippet})`) + update_conditions.push(`(${parent.var}.${this.node.name} !== ${this.snippet})`); } } @@ -121,6 +120,7 @@ export default class BindingWrapper { // special cases switch (this.node.name) { case 'group': + { const binding_group = get_binding_group(parent.renderer, this.node.expression.node); block.builders.hydrate.add_line( @@ -131,6 +131,7 @@ export default class BindingWrapper { `ctx.$$binding_groups[${binding_group}].splice(ctx.$$binding_groups[${binding_group}].indexOf(${parent.var}), 1);` ); break; + } case 'currentTime': case 'playbackRate': @@ -139,6 +140,7 @@ export default class BindingWrapper { break; case 'paused': + { // this is necessary to prevent audio restarting by itself const last = block.get_unique_name(`${parent.var}_is_paused`); block.add_variable(last, 'true'); @@ -146,6 +148,7 @@ export default class BindingWrapper { update_conditions.push(`${last} !== (${last} = ${this.snippet})`); update_dom = `${parent.var}[${last} ? "pause" : "play"]();`; break; + } case 'value': if (parent.node.get_static_attribute_value('type') === 'file') { @@ -192,7 +195,15 @@ function get_dom_updater( ? `~${binding.snippet}.indexOf(${element.var}.__value)` : `${element.var}.__value === ${binding.snippet}`; - return `${element.var}.checked = ${condition};` + return `${element.var}.checked = ${condition};`; + } + + if (binding.node.name === 'text') { + return `if (${binding.snippet} !== ${element.var}.textContent) ${element.var}.textContent = ${binding.snippet};`; + } + + if (binding.node.name === 'html') { + return `if (${binding.snippet} !== ${element.var}.innerHTML) ${element.var}.innerHTML = ${binding.snippet};`; } return `${element.var}.${binding.node.name} = ${binding.snippet};`; @@ -304,7 +315,15 @@ function get_value_from_dom( } if ((name === 'buffered' || name === 'seekable' || name === 'played')) { - return `@time_ranges_to_array(this.${name})` + return `@time_ranges_to_array(this.${name})`; + } + + if (name === 'text') { + return `this.textContent`; + } + + if (name === 'html') { + return `this.innerHTML`; } // everything else diff --git a/src/compiler/compile/render-dom/wrappers/Element/StyleAttribute.ts b/src/compiler/compile/render-dom/wrappers/Element/StyleAttribute.ts index f51ef33546..ab764a8583 100644 --- a/src/compiler/compile/render-dom/wrappers/Element/StyleAttribute.ts +++ b/src/compiler/compile/render-dom/wrappers/Element/StyleAttribute.ts @@ -9,7 +9,7 @@ import Text from '../../../nodes/Text'; export interface StyleProp { key: string; - value: (Text|Expression)[]; + value: Array<Text|Expression>; } export default class StyleAttributeWrapper extends AttributeWrapper { @@ -65,7 +65,7 @@ export default class StyleAttributeWrapper extends AttributeWrapper { } } -function optimize_style(value: (Text|Expression)[]) { +function optimize_style(value: Array<Text|Expression>) { const props: StyleProp[] = []; let chunks = value.slice(); @@ -83,12 +83,14 @@ function optimize_style(value: (Text|Expression)[]) { const remaining_data = chunk.data.slice(offset); if (remaining_data) { + /* eslint-disable @typescript-eslint/no-object-literal-type-assertion */ chunks[0] = { start: chunk.start + offset, end: chunk.end, type: 'Text', data: remaining_data } as Text; + /* eslint-enable @typescript-eslint/no-object-literal-type-assertion */ } else { chunks.shift(); } @@ -102,8 +104,8 @@ function optimize_style(value: (Text|Expression)[]) { return props; } -function get_style_value(chunks: (Text | Expression)[]) { - const value: (Text|Expression)[] = []; +function get_style_value(chunks: Array<Text | Expression>) { + const value: Array<Text|Expression> = []; let in_url = false; let quote_mark = null; @@ -171,6 +173,6 @@ function get_style_value(chunks: (Text | Expression)[]) { }; } -function is_dynamic(value: (Text|Expression)[]) { +function is_dynamic(value: Array<Text|Expression>) { return value.length > 1 || value[0].type !== 'Text'; } diff --git a/src/compiler/compile/render-dom/wrappers/Element/index.ts b/src/compiler/compile/render-dom/wrappers/Element/index.ts index dce49dc8be..2f7452e8c6 100644 --- a/src/compiler/compile/render-dom/wrappers/Element/index.ts +++ b/src/compiler/compile/render-dom/wrappers/Element/index.ts @@ -2,7 +2,6 @@ import Renderer from '../../Renderer'; import Element from '../../../nodes/Element'; import Wrapper from '../shared/Wrapper'; import Block from '../../Block'; -import Node from '../../../nodes/shared/Node'; import { is_void, quote_prop_if_necessary, quote_name_if_necessary, sanitize } from '../../../../utils/names'; import FragmentWrapper from '../Fragment'; import { stringify, escape_html, escape } from '../../../utils/stringify'; @@ -24,25 +23,31 @@ import { get_context_merger } from '../shared/get_context_merger'; const events = [ { event_names: ['input'], - filter: (node: Element, name: string) => + filter: (node: Element, _name: string) => node.name === 'textarea' || node.name === 'input' && !/radio|checkbox|range/.test(node.get_static_attribute_value('type') as string) }, { - event_names: ['change'], + event_names: ['input'], filter: (node: Element, name: string) => + (name === 'text' || name === 'html') && + node.attributes.some(attribute => attribute.name === 'contenteditable') + }, + { + event_names: ['change'], + filter: (node: Element, _name: string) => node.name === 'select' || node.name === 'input' && /radio|checkbox/.test(node.get_static_attribute_value('type') as string) }, { event_names: ['change', 'input'], - filter: (node: Element, name: string) => + filter: (node: Element, _name: string) => node.name === 'input' && node.get_static_attribute_value('type') === 'range' }, { event_names: ['resize'], - filter: (node: Element, name: string) => + filter: (_node: Element, name: string) => dimensions.test(name) }, @@ -93,7 +98,7 @@ const events = [ // details event { event_names: ['toggle'], - filter: (node: Element, name: string) => + filter: (node: Element, _name: string) => node.name === 'details' }, ]; @@ -119,7 +124,7 @@ export default class ElementWrapper extends Wrapper { next_sibling: Wrapper ) { super(renderer, block, parent, node); - this.var = node.name.replace(/[^a-zA-Z0-9_$]/g, '_') + this.var = node.name.replace(/[^a-zA-Z0-9_$]/g, '_'); this.class_dependencies = []; @@ -239,7 +244,7 @@ export default class ElementWrapper extends Wrapper { } const node = this.var; - const nodes = parent_nodes && block.get_unique_name(`${this.var}_nodes`) // if we're in unclaimable territory, i.e. <head>, parent_nodes is null + const nodes = parent_nodes && block.get_unique_name(`${this.var}_nodes`); // if we're in unclaimable territory, i.e. <head>, parent_nodes is null block.add_variable(node); const render_statement = this.get_render_statement(); @@ -350,7 +355,7 @@ export default class ElementWrapper extends Wrapper { let open = `<${wrapper.node.name}`; (wrapper as ElementWrapper).attributes.forEach((attr: AttributeWrapper) => { - open += ` ${fix_attribute_casing(attr.node.name)}${attr.stringify()}` + open += ` ${fix_attribute_casing(attr.node.name)}${attr.stringify()}`; }); if (is_void(wrapper.node.name)) return open + '>'; @@ -798,7 +803,8 @@ export default class ElementWrapper extends Wrapper { add_classes(block: Block) { this.node.classes.forEach(class_directive => { const { expression, name } = class_directive; - let snippet, dependencies; + let snippet; + let dependencies; if (expression) { snippet = expression.render(block); dependencies = expression.dependencies; diff --git a/src/compiler/compile/render-dom/wrappers/Fragment.ts b/src/compiler/compile/render-dom/wrappers/Fragment.ts index 21a6704548..f2e2ab7a7a 100644 --- a/src/compiler/compile/render-dom/wrappers/Fragment.ts +++ b/src/compiler/compile/render-dom/wrappers/Fragment.ts @@ -14,7 +14,6 @@ import Text from './Text'; import Title from './Title'; import Window from './Window'; import { INode } from '../../nodes/interfaces'; -import TextWrapper from './Text'; import Renderer from '../Renderer'; import Block from '../Block'; import { trim_start, trim_end } from '../../../utils/trim'; @@ -64,7 +63,7 @@ export default class FragmentWrapper { const child = nodes[i]; if (!child.type) { - throw new Error(`missing type`) + throw new Error(`missing type`); } if (!(child.type in wrappers)) { @@ -102,7 +101,7 @@ export default class FragmentWrapper { continue; } - const wrapper = new TextWrapper(renderer, block, parent, child, data); + const wrapper = new Text(renderer, block, parent, child, data); if (wrapper.skip) continue; this.nodes.unshift(wrapper); @@ -120,7 +119,7 @@ export default class FragmentWrapper { } if (strip_whitespace) { - const first = this.nodes[0] as TextWrapper; + const first = this.nodes[0] as Text; if (first && first.node.type === 'Text') { first.data = trim_start(first.data); diff --git a/src/compiler/compile/render-dom/wrappers/Head.ts b/src/compiler/compile/render-dom/wrappers/Head.ts index dbd38c1c80..d942a69dc2 100644 --- a/src/compiler/compile/render-dom/wrappers/Head.ts +++ b/src/compiler/compile/render-dom/wrappers/Head.ts @@ -29,7 +29,7 @@ export default class HeadWrapper extends Wrapper { ); } - render(block: Block, parent_node: string, parent_nodes: string) { + render(block: Block, _parent_node: string, _parent_nodes: string) { this.fragment.render(block, 'document.head', 'nodes'); } } diff --git a/src/compiler/compile/render-dom/wrappers/IfBlock.ts b/src/compiler/compile/render-dom/wrappers/IfBlock.ts index 464d9c0a53..46f17653a1 100644 --- a/src/compiler/compile/render-dom/wrappers/IfBlock.ts +++ b/src/compiler/compile/render-dom/wrappers/IfBlock.ts @@ -201,7 +201,7 @@ export default class IfBlockWrapper extends Wrapper { render_compound( block: Block, parent_node: string, - parent_nodes: string, + _parent_nodes: string, dynamic, { name, anchor, has_else, if_name, has_transitions }, detaching @@ -210,6 +210,7 @@ export default class IfBlockWrapper extends Wrapper { const current_block_type = block.get_unique_name(`current_block_type`); const current_block_type_and = has_else ? '' : `${current_block_type} && `; + /* eslint-disable @typescript-eslint/indent,indent */ block.builders.init.add_block(deindent` function ${select_block_type}(ctx) { ${this.branches @@ -217,6 +218,7 @@ export default class IfBlockWrapper extends Wrapper { .join('\n')} } `); + /* eslint-enable @typescript-eslint/indent,indent */ block.builders.init.add_block(deindent` var ${current_block_type} = ${select_block_type}(ctx); @@ -265,7 +267,7 @@ export default class IfBlockWrapper extends Wrapper { render_compound_with_outros( block: Block, parent_node: string, - parent_nodes: string, + _parent_nodes: string, dynamic, { name, anchor, has_else, has_transitions }, detaching @@ -283,6 +285,7 @@ export default class IfBlockWrapper extends Wrapper { block.add_variable(current_block_type_index); block.add_variable(name); + /* eslint-disable @typescript-eslint/indent,indent */ block.builders.init.add_block(deindent` var ${if_block_creators} = [ ${this.branches.map(branch => branch.block.name).join(',\n')} @@ -297,6 +300,7 @@ export default class IfBlockWrapper extends Wrapper { ${!has_else && `return -1;`} } `); + /* eslint-enable @typescript-eslint/indent,indent */ if (has_else) { block.builders.init.add_block(deindent` @@ -386,7 +390,7 @@ export default class IfBlockWrapper extends Wrapper { render_simple( block: Block, parent_node: string, - parent_nodes: string, + _parent_nodes: string, dynamic, { name, anchor, if_name, has_transitions }, detaching diff --git a/src/compiler/compile/render-dom/wrappers/InlineComponent/index.ts b/src/compiler/compile/render-dom/wrappers/InlineComponent/index.ts index 049c21e256..696fff51c0 100644 --- a/src/compiler/compile/render-dom/wrappers/InlineComponent/index.ts +++ b/src/compiler/compile/render-dom/wrappers/InlineComponent/index.ts @@ -17,7 +17,7 @@ import TemplateScope from '../../../nodes/shared/TemplateScope'; export default class InlineComponentWrapper extends Wrapper { var: string; - slots: Map<string, { block: Block, scope: TemplateScope, fn?: string }> = new Map(); + slots: Map<string, { block: Block; scope: TemplateScope; fn?: string }> = new Map(); node: InlineComponent; fragment: FragmentWrapper; @@ -62,8 +62,8 @@ export default class InlineComponentWrapper extends Wrapper { this.var = ( this.node.name === 'svelte:self' ? renderer.component.name : - this.node.name === 'svelte:component' ? 'switch_instance' : - sanitize(this.node.name) + this.node.name === 'svelte:component' ? 'switch_instance' : + sanitize(this.node.name) ).toLowerCase(); if (this.node.children.length) { @@ -232,14 +232,16 @@ export default class InlineComponentWrapper extends Wrapper { .filter((attribute: Attribute) => attribute.is_dynamic) .forEach((attribute: Attribute) => { if (attribute.dependencies.size > 0) { + /* eslint-disable @typescript-eslint/indent,indent */ updates.push(deindent` if (${[...attribute.dependencies] .map(dependency => `changed.${dependency}`) .join(' || ')}) ${name_changes}${quote_prop_if_necessary(attribute.name)} = ${attribute.get_value(block)}; `); + /* eslint-enable @typescript-eslint/indent,indent */ } }); - } + } } if (non_let_dependencies.length > 0) { @@ -265,7 +267,7 @@ export default class InlineComponentWrapper extends Wrapper { // bind:x={y} — we can't just do `y = x`, we need to // to `array[index] = x; const { name } = binding.expression.node; - const { object, property, snippet } = block.bindings.get(name); + const { snippet } = block.bindings.get(name); lhs = snippet; // TODO we need to invalidate... something @@ -361,7 +363,9 @@ export default class InlineComponentWrapper extends Wrapper { }); const munged_handlers = this.node.handlers.map(handler => { - const snippet = handler.render(block); + let snippet = handler.render(block); + if (handler.modifiers.has('once')) snippet = `@once(${snippet})`; + return `${name}.$on("${handler.name}", ${snippet});`; }); diff --git a/src/compiler/compile/render-dom/wrappers/Slot.ts b/src/compiler/compile/render-dom/wrappers/Slot.ts index 8a9dc7aca2..5347b87de4 100644 --- a/src/compiler/compile/render-dom/wrappers/Slot.ts +++ b/src/compiler/compile/render-dom/wrappers/Slot.ts @@ -78,7 +78,7 @@ export default class SlotWrapper extends Wrapper { }); if (attribute.dependencies.size > 0) { - changes_props.push(`${attribute.name}: ${[...attribute.dependencies].join(' || ')}`) + changes_props.push(`${attribute.name}: ${[...attribute.dependencies].join(' || ')}`); } }); @@ -101,7 +101,7 @@ export default class SlotWrapper extends Wrapper { const ${slot} = @create_slot(${slot_definition}, ctx, ${get_slot_context}); `); - let mount_before = block.builders.mount.toString(); + const mount_before = block.builders.mount.toString(); block.builders.create.push_condition(`!${slot}`); block.builders.claim.push_condition(`!${slot}`); diff --git a/src/compiler/compile/render-dom/wrappers/Title.ts b/src/compiler/compile/render-dom/wrappers/Title.ts index f24e2926e0..456a833a8f 100644 --- a/src/compiler/compile/render-dom/wrappers/Title.ts +++ b/src/compiler/compile/render-dom/wrappers/Title.ts @@ -14,13 +14,13 @@ export default class TitleWrapper extends Wrapper { block: Block, parent: Wrapper, node: Title, - strip_whitespace: boolean, - next_sibling: Wrapper + _strip_whitespace: boolean, + _next_sibling: Wrapper ) { super(renderer, block, parent, node); } - render(block: Block, parent_node: string, parent_nodes: string) { + render(block: Block, _parent_node: string, _parent_nodes: string) { const is_dynamic = !!this.node.children.find(node => node.type !== 'Text'); if (is_dynamic) { @@ -65,13 +65,12 @@ export default class TitleWrapper extends Wrapper { if (this.node.should_cache) block.add_variable(last); - let updater; const init = this.node.should_cache ? `${last} = ${value}` : value; block.builders.init.add_line( `document.title = ${init};` ); - updater = `document.title = ${this.node.should_cache ? last : value};`; + const updater = `document.title = ${this.node.should_cache ? last : value};`; if (all_dependencies.size) { const dependencies = Array.from(all_dependencies); @@ -92,7 +91,10 @@ export default class TitleWrapper extends Wrapper { ); } } else { - const value = stringify((this.node.children[0] as Text).data); + const value = this.node.children.length > 0 + ? stringify((this.node.children[0] as Text).data) + : '""'; + block.builders.hydrate.add_line(`document.title = ${value};`); } } diff --git a/src/compiler/compile/render-dom/wrappers/Window.ts b/src/compiler/compile/render-dom/wrappers/Window.ts index 56c63adb3d..585864664a 100644 --- a/src/compiler/compile/render-dom/wrappers/Window.ts +++ b/src/compiler/compile/render-dom/wrappers/Window.ts @@ -1,6 +1,5 @@ import Renderer from '../Renderer'; import Block from '../Block'; -import Node from '../../nodes/shared/Node'; import Wrapper from './shared/Wrapper'; import deindent from '../../utils/deindent'; import add_event_handlers from './shared/add_event_handlers'; @@ -38,7 +37,7 @@ export default class WindowWrapper extends Wrapper { super(renderer, block, parent, node); } - render(block: Block, parent_node: string, parent_nodes: string) { + render(block: Block, _parent_node: string, _parent_nodes: string) { const { renderer } = this; const { component } = renderer; @@ -88,7 +87,7 @@ export default class WindowWrapper extends Wrapper { bindings.scrollY && `"${bindings.scrollY}" in this._state` ].filter(Boolean).join(' || '); - const x = bindings.scrollX && `this._state.${bindings.scrollX}`; + const x = bindings.scrollX && `this._state.${bindings.scrollX}`; const y = bindings.scrollY && `this._state.${bindings.scrollY}`; renderer.meta_bindings.add_block(deindent` diff --git a/src/compiler/compile/render-dom/wrappers/shared/Wrapper.ts b/src/compiler/compile/render-dom/wrappers/shared/Wrapper.ts index 3315b6b483..60c4a4187b 100644 --- a/src/compiler/compile/render-dom/wrappers/shared/Wrapper.ts +++ b/src/compiler/compile/render-dom/wrappers/shared/Wrapper.ts @@ -76,7 +76,7 @@ export default class Wrapper { ); } - render(block: Block, parent_node: string, parent_nodes: string){ + render(_block: Block, _parent_node: string, _parent_nodes: string) { throw Error('Wrapper class is not renderable'); } } diff --git a/src/compiler/compile/render-dom/wrappers/shared/add_actions.ts b/src/compiler/compile/render-dom/wrappers/shared/add_actions.ts index 5ae5810e9f..260058f2be 100644 --- a/src/compiler/compile/render-dom/wrappers/shared/add_actions.ts +++ b/src/compiler/compile/render-dom/wrappers/shared/add_actions.ts @@ -10,7 +10,8 @@ export default function add_actions( ) { actions.forEach(action => { const { expression } = action; - let snippet, dependencies; + let snippet; + let dependencies; if (expression) { snippet = expression.render(block); @@ -44,4 +45,4 @@ export default function add_actions( `if (${name} && typeof ${name}.destroy === 'function') ${name}.destroy();` ); }); -} \ No newline at end of file +} diff --git a/src/compiler/compile/render-ssr/Renderer.ts b/src/compiler/compile/render-ssr/Renderer.ts index ef1d16429e..9680866349 100644 --- a/src/compiler/compile/render-ssr/Renderer.ts +++ b/src/compiler/compile/render-ssr/Renderer.ts @@ -16,7 +16,7 @@ import { INode } from '../nodes/interfaces'; type Handler = (node: any, renderer: Renderer, options: CompileOptions) => void; -function noop(){} +function noop() {} const handlers: Record<string, Handler> = { AwaitBlock, @@ -38,8 +38,8 @@ const handlers: Record<string, Handler> = { }; export interface RenderOptions extends CompileOptions{ - locate: (c: number) => { line: number; column: number; }; -}; + locate: (c: number) => { line: number; column: number }; +} export default class Renderer { has_bindings = false; diff --git a/src/compiler/compile/render-ssr/handlers/EachBlock.ts b/src/compiler/compile/render-ssr/handlers/EachBlock.ts index 5ed27dff15..d44c404603 100644 --- a/src/compiler/compile/render-ssr/handlers/EachBlock.ts +++ b/src/compiler/compile/render-ssr/handlers/EachBlock.ts @@ -9,7 +9,7 @@ export default function(node: EachBlock, renderer: Renderer, options: RenderOpti const ctx = node.index ? `([✂${start}-${end}✂], ${node.index})` - : `([✂${start}-${end}✂])` + : `([✂${start}-${end}✂])`; const open = `\${${node.else ? `${snippet}.length ? ` : ''}@each(${snippet}, ${ctx} => \``; renderer.append(open); diff --git a/src/compiler/compile/render-ssr/handlers/Element.ts b/src/compiler/compile/render-ssr/handlers/Element.ts index 5ed6875dec..0fbb4d3410 100644 --- a/src/compiler/compile/render-ssr/handlers/Element.ts +++ b/src/compiler/compile/render-ssr/handlers/Element.ts @@ -1,7 +1,6 @@ import { is_void, quote_prop_if_necessary, quote_name_if_necessary } from '../../../utils/names'; import Attribute from '../../nodes/Attribute'; import Class from '../../nodes/Class'; -import Node from '../../nodes/shared/Node'; import { snip } from '../../utils/snip'; import { stringify_attribute } from '../../utils/stringify_attribute'; import { get_slot_scope } from './shared/get_slot_scope'; @@ -54,7 +53,12 @@ export default function(node: Element, renderer: Renderer, options: RenderOption slot_scopes: Map<any, any>; }) { let opening_tag = `<${node.name}`; - let textarea_contents; // awkward special case + let node_contents; // awkward special case + const contenteditable = ( + node.name !== 'textarea' && + node.name !== 'input' && + node.attributes.some((attribute) => attribute.name === 'contenteditable') + ); const slot = node.get_static_attribute_value('slot'); const component = node.find_nearest(/InlineComponent/); @@ -91,7 +95,7 @@ export default function(node: Element, renderer: Renderer, options: RenderOption args.push(snip(attribute.expression)); } else { if (attribute.name === 'value' && node.name === 'textarea') { - textarea_contents = stringify_attribute(attribute, true); + node_contents = stringify_attribute(attribute, true); } else if (attribute.is_true) { args.push(`{ ${quote_name_if_necessary(attribute.name)}: true }`); } else if ( @@ -113,7 +117,7 @@ export default function(node: Element, renderer: Renderer, options: RenderOption if (attribute.type !== 'Attribute') return; if (attribute.name === 'value' && node.name === 'textarea') { - textarea_contents = stringify_attribute(attribute, true); + node_contents = stringify_attribute(attribute, true); } else if (attribute.is_true) { opening_tag += ` ${attribute.name}`; } else if ( @@ -146,6 +150,17 @@ export default function(node: Element, renderer: Renderer, options: RenderOption if (name === 'group') { // TODO server-render group bindings + } else if (contenteditable && (name === 'text' || name === 'html')) { + const snippet = snip(expression); + if (name == 'text') { + node_contents = '${@escape(' + snippet + ')}'; + } else { + // Do not escape HTML content + node_contents = '${' + snippet + '}'; + } + } else if (binding.name === 'value' && node.name === 'textarea') { + const snippet = snip(expression); + node_contents='${(' + snippet + ') || ""}'; } else { const snippet = snip(expression); opening_tag += ' ${(v => v ? ("' + name + '" + (v === true ? "" : "=" + JSON.stringify(v))) : "")(' + snippet + ')}'; @@ -160,8 +175,8 @@ export default function(node: Element, renderer: Renderer, options: RenderOption renderer.append(opening_tag); - if (node.name === 'textarea' && textarea_contents !== undefined) { - renderer.append(textarea_contents); + if ((node.name === 'textarea' || contenteditable) && node_contents !== undefined) { + renderer.append(node_contents); } else { renderer.render(node.children, options); } diff --git a/src/compiler/compile/render-ssr/handlers/HtmlTag.ts b/src/compiler/compile/render-ssr/handlers/HtmlTag.ts index 84e2e1f573..ee62a4defc 100644 --- a/src/compiler/compile/render-ssr/handlers/HtmlTag.ts +++ b/src/compiler/compile/render-ssr/handlers/HtmlTag.ts @@ -2,6 +2,6 @@ import { snip } from '../../utils/snip'; import Renderer, { RenderOptions } from '../Renderer'; import RawMustacheTag from '../../nodes/RawMustacheTag'; -export default function(node: RawMustacheTag, renderer: Renderer, options: RenderOptions) { +export default function(node: RawMustacheTag, renderer: Renderer, _options: RenderOptions) { renderer.append('${' + snip(node.expression) + '}'); } diff --git a/src/compiler/compile/render-ssr/handlers/Tag.ts b/src/compiler/compile/render-ssr/handlers/Tag.ts index d03f46fe0a..353939049d 100644 --- a/src/compiler/compile/render-ssr/handlers/Tag.ts +++ b/src/compiler/compile/render-ssr/handlers/Tag.ts @@ -1,6 +1,6 @@ import { snip } from '../../utils/snip'; import Renderer, { RenderOptions } from '../Renderer'; -export default function(node, renderer: Renderer, options: RenderOptions) { +export default function(node, renderer: Renderer, _options: RenderOptions) { const snippet = snip(node.expression); renderer.append( diff --git a/src/compiler/compile/render-ssr/handlers/Text.ts b/src/compiler/compile/render-ssr/handlers/Text.ts index 1d2906d10a..5e56952f13 100644 --- a/src/compiler/compile/render-ssr/handlers/Text.ts +++ b/src/compiler/compile/render-ssr/handlers/Text.ts @@ -3,7 +3,7 @@ import Renderer, { RenderOptions } from '../Renderer'; import Text from '../../nodes/Text'; import Element from '../../nodes/Element'; -export default function(node: Text, renderer: Renderer, options: RenderOptions) { +export default function(node: Text, renderer: Renderer, _options: RenderOptions) { let text = node.data; if ( !node.parent || diff --git a/src/compiler/compile/utils/__test__.ts b/src/compiler/compile/utils/__test__.ts index 7a8b5a6fd7..b5bc5d8ea8 100644 --- a/src/compiler/compile/utils/__test__.ts +++ b/src/compiler/compile/utils/__test__.ts @@ -1,6 +1,7 @@ import * as assert from 'assert'; import deindent from './deindent'; import CodeBuilder from './CodeBuilder'; +import get_name_from_filename from './get_name_from_filename'; describe('deindent', () => { it('deindents a simple string', () => { @@ -164,3 +165,17 @@ describe('CodeBuilder', () => { ); }); }); + +describe('get_name_from_filename', () => { + it('uses the basename', () => { + assert.equal(get_name_from_filename('path/to/Widget.svelte'), 'Widget'); + }); + + it('uses the directory name, if basename is index', () => { + assert.equal(get_name_from_filename('path/to/Widget/index.svelte'), 'Widget'); + }); + + it('handles unusual filenames', () => { + assert.equal(get_name_from_filename('path/to/[...parts].svelte'), 'Parts'); + }); +}); diff --git a/src/compiler/compile/utils/add_to_set.ts b/src/compiler/compile/utils/add_to_set.ts index b37e0db931..530a7fe2ca 100644 --- a/src/compiler/compile/utils/add_to_set.ts +++ b/src/compiler/compile/utils/add_to_set.ts @@ -1,4 +1,4 @@ -export default function add_to_set<T>(a: Set<T>, b: Set<T> | Array<T>) { +export default function add_to_set<T>(a: Set<T>, b: Set<T> | T[]) { // @ts-ignore b.forEach(item => { a.add(item); diff --git a/src/compiler/compile/utils/get_name_from_filename.ts b/src/compiler/compile/utils/get_name_from_filename.ts new file mode 100644 index 0000000000..19c781825c --- /dev/null +++ b/src/compiler/compile/utils/get_name_from_filename.ts @@ -0,0 +1,26 @@ +export default function get_name_from_filename(filename: string) { + if (!filename) return null; + // eslint-disable-next-line no-useless-escape + const parts = filename.split(/[\/\\]/); + + if (parts.length > 1) { + const index_match = parts[parts.length - 1].match(/^index(\.\w+)/); + if (index_match) { + parts.pop(); + parts[parts.length - 1] += index_match[1]; + } + } + + const base = parts.pop() + .replace(/\.[^.]+$/, "") + .replace(/[^a-zA-Z_$0-9]+/g, '_') + .replace(/^_/, '') + .replace(/_$/, '') + .replace(/^(\d)/, '_$1'); + + if (!base) { + throw new Error(`Could not derive component name from file ${filename}`); + } + + return base[0].toUpperCase() + base.slice(1); +} \ No newline at end of file diff --git a/src/compiler/compile/utils/scope.ts b/src/compiler/compile/utils/scope.ts index 1303d205a0..6bf3f9eaf4 100644 --- a/src/compiler/compile/utils/scope.ts +++ b/src/compiler/compile/utils/scope.ts @@ -50,10 +50,10 @@ export function create_scopes(expression: Node) { if (map.has(node)) { scope = scope.parent; } - }, + } }); - scope.declarations.forEach((node, name) => { + scope.declarations.forEach((_node, name) => { globals.delete(name); }); diff --git a/src/compiler/interfaces.ts b/src/compiler/interfaces.ts index ddd0b4a629..d63194edcd 100644 --- a/src/compiler/interfaces.ts +++ b/src/compiler/interfaces.ts @@ -7,33 +7,33 @@ interface BaseNode { } export interface Text extends BaseNode { - type: 'Text', + type: 'Text'; data: string; } export interface MustacheTag extends BaseNode { - type: 'MustacheTag', + type: 'MustacheTag'; expression: Node; } export type DirectiveType = 'Action' - | 'Animation' - | 'Binding' - | 'Class' - | 'EventHandler' - | 'Let' - | 'Ref' - | 'Transition'; +| 'Animation' +| 'Binding' +| 'Class' +| 'EventHandler' +| 'Let' +| 'Ref' +| 'Transition'; interface BaseDirective extends BaseNode { type: DirectiveType; expression: null|Node; name: string; - modifiers: string[] + modifiers: string[]; } export interface Transition extends BaseDirective{ - type: 'Transition', + type: 'Transition'; intro: boolean; outro: boolean; } @@ -41,17 +41,17 @@ export interface Transition extends BaseDirective{ export type Directive = BaseDirective | Transition; export type Node = Text - | MustacheTag - | BaseNode - | Directive - | Transition; +| MustacheTag +| BaseNode +| Directive +| Transition; export interface Parser { readonly template: string; readonly filename?: string; index: number; - stack: Array<Node>; + stack: Node[]; html: Node; css: Node; @@ -68,7 +68,7 @@ export interface Ast { export interface Warning { start?: { line: number; column: number; pos?: number }; - end?: { line: number; column: number; }; + end?: { line: number; column: number }; pos?: number; code: string; message: string; @@ -114,7 +114,7 @@ export interface Visitor { export interface AppendTarget { slots: Record<string, string>; - slot_stack: string[] + slot_stack: string[]; } export interface Var { diff --git a/src/compiler/parse/index.ts b/src/compiler/parse/index.ts index a9c3950425..2110df7280 100644 --- a/src/compiler/parse/index.ts +++ b/src/compiler/parse/index.ts @@ -14,7 +14,7 @@ export class Parser { readonly customElement: boolean; index = 0; - stack: Array<Node> = []; + stack: Node[] = []; html: Node; css: Node[] = []; @@ -89,7 +89,7 @@ export class Parser { }, err.pos); } - error({ code, message }: { code: string, message: string }, index = this.index) { + error({ code, message }: { code: string; message: string }, index = this.index) { error(message, { name: 'ParseError', code, diff --git a/src/compiler/parse/read/context.ts b/src/compiler/parse/read/context.ts index ac47f164dd..0db0c676a3 100644 --- a/src/compiler/parse/read/context.ts +++ b/src/compiler/parse/read/context.ts @@ -1,13 +1,13 @@ import { Parser } from '../index'; -type Identifier = { +interface Identifier { start: number; end: number; type: 'Identifier'; name: string; -}; +} -type Property = { +interface Property { start: number; end: number; type: 'Property'; @@ -15,9 +15,9 @@ type Property = { shorthand: boolean; key: Identifier; value: Context; -}; +} -type Context = { +interface Context { start: number; end: number; type: 'Identifier' | 'ArrayPattern' | 'ObjectPattern' | 'RestIdentifier'; @@ -91,7 +91,7 @@ export default function read_context(parser: Parser) { end: parser.index, type: 'Identifier', name - } + }; const property: Property = { start, end: parser.index, @@ -100,7 +100,7 @@ export default function read_context(parser: Parser) { shorthand: true, key, value: key - } + }; context.properties.push(property); diff --git a/src/compiler/parse/read/expression.ts b/src/compiler/parse/read/expression.ts index 615f270112..78a28ba72b 100644 --- a/src/compiler/parse/read/expression.ts +++ b/src/compiler/parse/read/expression.ts @@ -12,6 +12,7 @@ export default function read_expression(parser: Parser): Node { const end = start + name.length; if (literals.has(name)) { + // eslint-disable-next-line @typescript-eslint/no-object-literal-type-assertion return { type: 'Literal', start, @@ -21,6 +22,7 @@ export default function read_expression(parser: Parser): Node { } as SimpleLiteral; } + // eslint-disable-next-line @typescript-eslint/no-object-literal-type-assertion return { type: 'Identifier', start, diff --git a/src/compiler/parse/state/mustache.ts b/src/compiler/parse/state/mustache.ts index b4d0c6ad8d..4abd506984 100644 --- a/src/compiler/parse/state/mustache.ts +++ b/src/compiler/parse/state/mustache.ts @@ -295,7 +295,7 @@ export default function mustache(parser: Parser) { } } - let await_block_shorthand = type === 'AwaitBlock' && parser.eat('then'); + const await_block_shorthand = type === 'AwaitBlock' && parser.eat('then'); if (await_block_shorthand) { parser.require_whitespace(); block.value = parser.read_identifier(); diff --git a/src/compiler/parse/state/tag.ts b/src/compiler/parse/state/tag.ts index 108cfce3e1..907233fdc7 100644 --- a/src/compiler/parse/state/tag.ts +++ b/src/compiler/parse/state/tag.ts @@ -8,6 +8,7 @@ import { Directive, DirectiveType, Node, Text } from '../../interfaces'; import fuzzymatch from '../../utils/fuzzymatch'; import list from '../../utils/list'; +// eslint-disable-next-line no-useless-escape const valid_tag_name = /^\!?[a-zA-Z]{1,}:?[a-zA-Z0-9\-]*/; const meta_tags = new Map([ @@ -36,7 +37,9 @@ const specials = new Map([ ], ]); +// eslint-disable-next-line no-useless-escape const SELF = /^svelte:self(?=[\s\/>])/; +// eslint-disable-next-line no-useless-escape const COMPONENT = /^svelte:component(?=[\s\/>])/; // based on http://developers.whatwg.org/syntax.html#syntax-tag-omission @@ -358,7 +361,8 @@ function read_attribute(parser: Parser, unique_names: Set<string>) { } } - let name = parser.read_until(/[\s=\/>"']/); + // eslint-disable-next-line no-useless-escape + const name = parser.read_until(/[\s=\/>"']/); if (!name) return null; let end = parser.index; @@ -381,6 +385,7 @@ function read_attribute(parser: Parser, unique_names: Set<string>) { let value: any[] | true = true; if (parser.eat('=')) { + parser.allow_whitespace(); value = read_attribute_value(parser); end = parser.index; } else if (parser.match_regex(/["']/)) { @@ -401,7 +406,7 @@ function read_attribute(parser: Parser, unique_names: Set<string>) { } if (value[0]) { - if ((value as Array<any>).length > 1 || value[0].type === 'Text') { + if ((value as any[]).length > 1 || value[0].type === 'Text') { parser.error({ code: `invalid-directive-value`, message: `Directive value must be a JavaScript expression enclosed in curly braces` @@ -445,7 +450,7 @@ function read_attribute(parser: Parser, unique_names: Set<string>) { }; } -function get_directive_type(name: string):DirectiveType { +function get_directive_type(name: string): DirectiveType { if (name === 'use') return 'Action'; if (name === 'animate') return 'Animation'; if (name === 'bind') return 'Binding'; diff --git a/src/compiler/parse/state/text.ts b/src/compiler/parse/state/text.ts index 1d9099055e..56be592ca9 100644 --- a/src/compiler/parse/state/text.ts +++ b/src/compiler/parse/state/text.ts @@ -14,7 +14,7 @@ export default function text(parser: Parser) { data += parser.template[parser.index++]; } - let node = { + const node = { start, end: parser.index, type: 'Text', diff --git a/src/compiler/preprocess/index.ts b/src/compiler/preprocess/index.ts index a9dad9f05b..8543a56d18 100644 --- a/src/compiler/preprocess/index.ts +++ b/src/compiler/preprocess/index.ts @@ -2,18 +2,18 @@ import { SourceMap } from 'magic-string'; export interface PreprocessorGroup { markup?: (options: { - content: string, - filename: string - }) => { code: string, map?: SourceMap | string, dependencies?: string[] }; + content: string; + filename: string; + }) => { code: string; map?: SourceMap | string; dependencies?: string[] }; style?: Preprocessor; script?: Preprocessor; } export type Preprocessor = (options: { - content: string, - attributes: Record<string, string | boolean>, - filename?: string -}) => { code: string, map?: SourceMap | string, dependencies?: string[] }; + content: string; + attributes: Record<string, string | boolean>; + filename?: string; +}) => { code: string; map?: SourceMap | string; dependencies?: string[] }; interface Processed { code: string; @@ -43,16 +43,16 @@ interface Replacement { } async function replace_async(str: string, re: RegExp, func: (...any) => Promise<string>) { - const replacements: Promise<Replacement>[] = []; + const replacements: Array<Promise<Replacement>> = []; str.replace(re, (...args) => { replacements.push( func(...args).then( - res => - <Replacement>({ + res => // eslint-disable-next-line @typescript-eslint/no-object-literal-type-assertion + ({ offset: args[args.length - 2], length: args[0].length, replacement: res, - }) + }) as Replacement ) ); return ''; diff --git a/src/compiler/tsconfig.json b/src/compiler/tsconfig.json new file mode 100644 index 0000000000..c5939a0fdc --- /dev/null +++ b/src/compiler/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "../../tsconfig.json", + "include": ["."], + + "compilerOptions": { + "lib": ["es2017", "webworker"] + + // TODO: remove mocha types from the whole project + // "types": ["node", "estree"] + } +} diff --git a/src/compiler/utils/error.ts b/src/compiler/utils/error.ts index a34d3fe112..d13222578a 100644 --- a/src/compiler/utils/error.ts +++ b/src/compiler/utils/error.ts @@ -3,8 +3,8 @@ import get_code_frame from './get_code_frame'; class CompileError extends Error { code: string; - start: { line: number, column: number }; - end: { line: number, column: number }; + start: { line: number; column: number }; + end: { line: number; column: number }; pos: number; filename: string; frame: string; @@ -15,12 +15,12 @@ class CompileError extends Error { } export default function error(message: string, props: { - name: string, - code: string, - source: string, - filename: string, - start: number, - end?: number + name: string; + code: string; + source: string; + filename: string; + start: number; + end?: number; }) { const error = new CompileError(message); error.name = props.name; diff --git a/src/compiler/utils/full_char_code_at.ts b/src/compiler/utils/full_char_code_at.ts index e0c15588c7..b5187693eb 100644 --- a/src/compiler/utils/full_char_code_at.ts +++ b/src/compiler/utils/full_char_code_at.ts @@ -2,9 +2,9 @@ // Reproduced under MIT License https://github.com/acornjs/acorn/blob/master/LICENSE export default function full_char_code_at(str: string, i: number): number { - let code = str.charCodeAt(i) + const code = str.charCodeAt(i); if (code <= 0xd7ff || code >= 0xe000) return code; - let next = str.charCodeAt(i + 1); + const next = str.charCodeAt(i + 1); return (code << 10) + next - 0x35fdc00; } \ No newline at end of file diff --git a/src/compiler/utils/fuzzymatch.ts b/src/compiler/utils/fuzzymatch.ts index 89d98fe1c1..2efadc3847 100644 --- a/src/compiler/utils/fuzzymatch.ts +++ b/src/compiler/utils/fuzzymatch.ts @@ -144,7 +144,7 @@ class FuzzySet { items[index] = [vector_normal, normalized_value]; this.items[gram_size] = items; this.exact_set[normalized_value] = value; - }; + } get(value: string) { const normalized_value = value.toLowerCase(); @@ -232,5 +232,5 @@ class FuzzySet { } return new_results; - }; -} \ No newline at end of file + } +} diff --git a/src/runtime/animate/index.ts b/src/runtime/animate/index.ts index f5500020cc..d00d23c98d 100644 --- a/src/runtime/animate/index.ts +++ b/src/runtime/animate/index.ts @@ -3,20 +3,20 @@ import { is_function } from 'svelte/internal'; // todo: same as Transition, should it be shared? export interface AnimationConfig { - delay?: number, - duration?: number, - easing?: (t: number) => number, - css?: (t: number, u: number) => string, - tick?: (t: number, u: number) => void + delay?: number; + duration?: number; + easing?: (t: number) => number; + css?: (t: number, u: number) => string; + tick?: (t: number, u: number) => void; } interface FlipParams { delay: number; duration: number | ((len: number) => number); - easing: (t: number) => number, + easing: (t: number) => number; } -export function flip(node: Element, animation: { from: DOMRect, to: DOMRect }, params: FlipParams): AnimationConfig { +export function flip(node: Element, animation: { from: DOMRect; to: DOMRect }, params: FlipParams): AnimationConfig { const style = getComputedStyle(node); const transform = style.transform === 'none' ? '' : style.transform; @@ -35,6 +35,6 @@ export function flip(node: Element, animation: { from: DOMRect, to: DOMRect }, p delay, duration: is_function(duration) ? duration(d) : duration, easing, - css: (t, u) => `transform: ${transform} translate(${u * dx}px, ${u * dy}px);` + css: (_t, u) => `transform: ${transform} translate(${u * dx}px, ${u * dy}px);` }; } diff --git a/src/runtime/internal/Component.ts b/src/runtime/internal/Component.ts index 714d15df34..7624d5c829 100644 --- a/src/runtime/internal/Component.ts +++ b/src/runtime/internal/Component.ts @@ -3,6 +3,7 @@ import { current_component, set_current_component } from './lifecycle'; import { blank_object, is_function, run, run_all, noop } from './utils'; import { children } from './dom'; +// eslint-disable-next-line @typescript-eslint/class-name-casing interface T$$ { dirty: null; ctx: null|any; @@ -16,7 +17,7 @@ interface T$$ { before_render: any[]; context: Map<any, any>; on_mount: any[]; - on_destroy: any[] + on_destroy: any[]; } export function bind(component, name, callback) { @@ -115,8 +116,10 @@ export function init(component, options, instance, create_fragment, not_equal, p if (options.target) { if (options.hydrate) { + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion $$.fragment!.l(children(options.target)); } else { + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion $$.fragment!.c(); } @@ -145,7 +148,7 @@ if (typeof HTMLElement !== 'undefined') { } } - attributeChangedCallback(attr, oldValue, newValue) { + attributeChangedCallback(attr, _oldValue, newValue) { this[attr] = newValue; } diff --git a/src/runtime/internal/animations.ts b/src/runtime/internal/animations.ts index b0357647f5..6dc6a446f6 100644 --- a/src/runtime/internal/animations.ts +++ b/src/runtime/internal/animations.ts @@ -1,4 +1,5 @@ -import { identity as linear, noop, now } from './utils'; +import { identity as linear, noop } from './utils'; +import { now } from './environment'; import { loop } from './loop'; import { create_rule, delete_rule } from './style_manager'; import { AnimationConfig } from '../animate'; @@ -7,7 +8,7 @@ import { AnimationConfig } from '../animate'; //todo: documentation says it is DOMRect, but in IE it would be ClientRect type PositionRect = DOMRect|ClientRect; -type AnimationFn = (node: Element, { from, to }: { from: PositionRect, to: PositionRect }, params: any) => AnimationConfig; +type AnimationFn = (node: Element, { from, to }: { from: PositionRect; to: PositionRect }, params: any) => AnimationConfig; export function create_animation(node: Element & ElementCSSInlineStyle, from: PositionRect, fn: AnimationFn, params) { if (!from) return noop; diff --git a/src/runtime/internal/dom.ts b/src/runtime/internal/dom.ts index edf394e4da..f65d07117c 100644 --- a/src/runtime/internal/dom.ts +++ b/src/runtime/internal/dom.ts @@ -1,8 +1,8 @@ -export function append(target:Node, node:Node) { +export function append(target: Node, node: Node) { target.appendChild(node); } -export function insert(target: Node, node: Node, anchor?:Node) { +export function insert(target: Node, node: Node, anchor?: Node) { target.insertBefore(node, anchor || null); } @@ -16,13 +16,13 @@ export function detach_between(before: Node, after: Node) { } } -export function detach_before(after:Node) { +export function detach_before(after: Node) { while (after.previousSibling) { after.parentNode.removeChild(after.previousSibling); } } -export function detach_after(before:Node) { +export function detach_after(before: Node) { while (before.nextSibling) { before.parentNode.removeChild(before.nextSibling); } @@ -38,7 +38,8 @@ export function element<K extends keyof HTMLElementTagNameMap>(name: K) { return document.createElement<K>(name); } -export function object_without_properties<T,K extends keyof T>(obj:T, exclude: K[]) { +export function object_without_properties<T, K extends keyof T>(obj: T, exclude: K[]) { + // eslint-disable-next-line @typescript-eslint/no-object-literal-type-assertion const target = {} as Pick<T, Exclude<keyof T, K>>; for (const k in obj) { if ( @@ -53,11 +54,11 @@ export function object_without_properties<T,K extends keyof T>(obj:T, exclude: K return target; } -export function svg_element<K extends keyof SVGElementTagNameMap>(name:K):SVGElement { +export function svg_element<K extends keyof SVGElementTagNameMap>(name: K): SVGElement { return document.createElementNS<K>('http://www.w3.org/2000/svg', name); } -export function text(data:string) { +export function text(data: string) { return document.createTextNode(data); } @@ -95,7 +96,7 @@ export function attr(node: Element, attribute: string, value?: string) { else node.setAttribute(attribute, value); } -export function set_attributes(node: Element & ElementCSSInlineStyle, attributes: { [x: string]: string; }) { +export function set_attributes(node: Element & ElementCSSInlineStyle, attributes: { [x: string]: string }) { for (const key in attributes) { if (key === 'style') { node.style.cssText = attributes[key]; diff --git a/src/runtime/internal/environment.ts b/src/runtime/internal/environment.ts new file mode 100644 index 0000000000..a1d50b5521 --- /dev/null +++ b/src/runtime/internal/environment.ts @@ -0,0 +1,16 @@ +export const is_client = typeof window !== 'undefined'; + +export let now: () => number = is_client + ? () => window.performance.now() + : () => Date.now(); + +export let raf = cb => requestAnimationFrame(cb); + +// used internally for testing +export function set_now(fn) { + now = fn; +} + +export function set_raf(fn) { + raf = fn; +} diff --git a/src/runtime/internal/index.ts b/src/runtime/internal/index.ts index 6487f04525..d9d95541eb 100644 --- a/src/runtime/internal/index.ts +++ b/src/runtime/internal/index.ts @@ -1,6 +1,7 @@ export * from './animations'; export * from './await-block'; export * from './dom'; +export * from './environment'; export * from './keyed-each'; export * from './lifecycle'; export * from './loop'; diff --git a/src/runtime/internal/loop.ts b/src/runtime/internal/loop.ts index c41d72ed74..c1a42aa724 100644 --- a/src/runtime/internal/loop.ts +++ b/src/runtime/internal/loop.ts @@ -1,4 +1,4 @@ -import { now, raf } from './utils'; +import { now, raf } from './environment'; export interface Task { abort(): void; promise: Promise<void> } @@ -23,7 +23,7 @@ export function clear_loops() { running = false; } -export function loop(fn: (number)=>void): Task { +export function loop(fn: (number) => void): Task { let task; if (!running) { diff --git a/src/runtime/internal/style_manager.ts b/src/runtime/internal/style_manager.ts index 2721200627..d9264e3c08 100644 --- a/src/runtime/internal/style_manager.ts +++ b/src/runtime/internal/style_manager.ts @@ -1,5 +1,5 @@ import { element } from './dom'; -import { raf } from './utils'; +import { raf } from './environment'; let stylesheet; let active = 0; diff --git a/src/runtime/internal/transitions.ts b/src/runtime/internal/transitions.ts index 4c6191964c..80c76ffec5 100644 --- a/src/runtime/internal/transitions.ts +++ b/src/runtime/internal/transitions.ts @@ -1,4 +1,5 @@ -import { identity as linear, is_function, noop, now, run_all } from './utils'; +import { identity as linear, is_function, noop, run_all } from './utils'; +import { now } from "./environment"; import { loop } from './loop'; import { create_rule, delete_rule } from './style_manager'; import { custom_event } from './dom'; @@ -71,14 +72,14 @@ export function create_in_transition(node: Element & ElementCSSInlineStyle, fn: if (task) task.abort(); running = true; - add_render_callback(() => dispatch(node, true, 'start')); + add_render_callback(() => dispatch(node, true, 'start')); task = loop(now => { if (running) { if (now >= end_time) { tick(1, 0); - dispatch(node, true, 'end'); + dispatch(node, true, 'end'); cleanup(); return running = false; @@ -146,14 +147,14 @@ export function create_out_transition(node: Element & ElementCSSInlineStyle, fn: const start_time = now() + delay; const end_time = start_time + duration; - add_render_callback(() => dispatch(node, false, 'start')); + add_render_callback(() => dispatch(node, false, 'start')); loop(now => { if (running) { if (now >= end_time) { tick(0, 1); - dispatch(node, false, 'end'); + dispatch(node, false, 'end'); if (!--group.remaining) { // this will result in `end()` being called, diff --git a/src/runtime/internal/utils.ts b/src/runtime/internal/utils.ts index 7997a25b1d..08410ec33a 100644 --- a/src/runtime/internal/utils.ts +++ b/src/runtime/internal/utils.ts @@ -2,7 +2,7 @@ export function noop() {} export const identity = x => x; -export function assign<T, S>(tar:T, src:S): T & S { +export function assign<T, S>(tar: T, src: S): T & S { // @ts-ignore for (const k in src) tar[k] = src[k]; return tar as T & S; @@ -81,19 +81,11 @@ export function exclude_internal_props(props) { return result; } -const is_client = typeof window !== 'undefined'; - -export let now: () => number = is_client - ? () => window.performance.now() - : () => Date.now(); - -export let raf = is_client ? requestAnimationFrame : noop; - -// used internally for testing -export function set_now(fn) { - now = fn; -} - -export function set_raf(fn) { - raf = fn; +export function once(fn) { + let ran = false; + return function(this: any, ...args) { + if (ran) return; + ran = true; + fn.call(this, ...args); + }; } diff --git a/src/runtime/motion/spring.ts b/src/runtime/motion/spring.ts index f99e8db41f..7742dd4106 100644 --- a/src/runtime/motion/spring.ts +++ b/src/runtime/motion/spring.ts @@ -6,10 +6,10 @@ interface TickContext<T> { inv_mass: number; dt: number; opts: Spring<T>; - settled: boolean + settled: boolean; } -function tick_spring<T>(ctx: TickContext<T>, last_value: T, current_value: T, target_value: T):T { +function tick_spring<T>(ctx: TickContext<T>, last_value: T, current_value: T, target_value: T): T { if (typeof current_value === 'number' || is_date(current_value)) { // @ts-ignore const delta = target_value - current_value; @@ -45,9 +45,9 @@ function tick_spring<T>(ctx: TickContext<T>, last_value: T, current_value: T, ta } interface SpringOpts { - stiffness?: number, - damping?: number, - precision?: number, + stiffness?: number; + damping?: number; + precision?: number; } interface SpringUpdateOpts { @@ -62,7 +62,7 @@ interface Spring<T> extends Readable<T>{ update: (fn: Updater<T>, opts?: SpringUpdateOpts) => Promise<void>; precision: number; damping: number; - stiffness: number + stiffness: number; } export function spring<T=any>(value: T, opts: SpringOpts = {}): Spring<T> { @@ -72,13 +72,14 @@ export function spring<T=any>(value: T, opts: SpringOpts = {}): Spring<T> { let last_time: number; let task: Task; let current_token: object; - let last_value:T = value; - let target_value:T = value; + let last_value: T = value; + let target_value: T = value; let inv_mass = 1; let inv_mass_recovery_rate = 0; let cancel_task = false; + /* eslint-disable @typescript-eslint/no-use-before-define */ function set(new_value: T, opts: SpringUpdateOpts={}): Promise<void> { target_value = new_value; const token = current_token = {}; @@ -133,15 +134,16 @@ export function spring<T=any>(value: T, opts: SpringOpts = {}): Spring<T> { }); }); } + /* eslint-enable @typescript-eslint/no-use-before-define */ - const spring = { + const spring: Spring<T> = { set, - update: (fn, opts:SpringUpdateOpts) => set(fn(target_value, value), opts), + update: (fn, opts: SpringUpdateOpts) => set(fn(target_value, value), opts), subscribe: store.subscribe, stiffness, damping, precision - } as Spring<T>; + }; return spring; } diff --git a/src/runtime/motion/tweened.ts b/src/runtime/motion/tweened.ts index ea3f2cdd86..7159c17eb5 100644 --- a/src/runtime/motion/tweened.ts +++ b/src/runtime/motion/tweened.ts @@ -56,9 +56,9 @@ function get_interpolator(a, b) { interface Options<T> { delay?: number; - duration?: number | ((from: T, to: T) => number) + duration?: number | ((from: T, to: T) => number); easing?: (t: number) => number; - interpolate?: (a: T, b: T) => (t: number) => T + interpolate?: (a: T, b: T) => (t: number) => T; } type Updater<T> = (target_value: T, value: T) => T; @@ -69,7 +69,7 @@ interface Tweened<T> extends Readable<T> { update(updater: Updater<T>, opts: Options<T>): Promise<void>; } -export function tweened<T>(value: T, defaults: Options<T> = {}):Tweened<T> { +export function tweened<T>(value: T, defaults: Options<T> = {}): Tweened<T> { const store = writable(value); let task: Task; @@ -122,7 +122,7 @@ export function tweened<T>(value: T, defaults: Options<T> = {}):Tweened<T> { return { set, - update: (fn, opts:Options<T>) => set(fn(target_value, value), opts), + update: (fn, opts: Options<T>) => set(fn(target_value, value), opts), subscribe: store.subscribe }; } diff --git a/src/runtime/store/index.ts b/src/runtime/store/index.ts index 5ab6cfa26b..1842124735 100644 --- a/src/runtime/store/index.ts +++ b/src/runtime/store/index.ts @@ -186,7 +186,7 @@ export function derived<T, S extends Stores>( unsubscribe(); }; } - } + }; } /** @@ -197,4 +197,4 @@ export function get<T>(store: Readable<T>): T { let value: T | undefined; store.subscribe((_: T) => value = _)(); return value as T; -} \ No newline at end of file +} diff --git a/src/runtime/transition/index.ts b/src/runtime/transition/index.ts index b3f4f21288..3aaa19ef3b 100644 --- a/src/runtime/transition/index.ts +++ b/src/runtime/transition/index.ts @@ -2,11 +2,11 @@ import { cubicOut, cubicInOut } from 'svelte/easing'; import { assign, is_function } from 'svelte/internal'; export interface TransitionConfig { - delay?: number, - duration?: number, - easing?: (t: number) => number, - css?: (t: number, u: number) => string, - tick?: (t: number, u: number) => void + delay?: number; + duration?: number; + easing?: (t: number) => number; + css?: (t: number, u: number) => string; + tick?: (t: number, u: number) => void; } interface FadeParams { @@ -30,7 +30,7 @@ export function fade(node: Element, { interface FlyParams { delay: number; duration: number; - easing: (t: number)=>number, + easing: (t: number) => number; x: number; y: number; opacity: number; @@ -63,7 +63,7 @@ export function fly(node: Element, { interface SlideParams { delay: number; duration: number; - easing: (t: number)=>number, + easing: (t: number) => number; } export function slide(node: Element, { @@ -101,7 +101,7 @@ export function slide(node: Element, { interface ScaleParams { delay: number; duration: number; - easing: (t: number)=>number, + easing: (t: number) => number; start: number; opacity: number; } @@ -124,7 +124,7 @@ export function scale(node: Element, { delay, duration, easing, - css: (t, u) => ` + css: (_t, u) => ` transform: ${transform} scale(${1 - (sd * u)}); opacity: ${target_opacity - (od * u)} ` @@ -135,7 +135,7 @@ interface DrawParams { delay: number; speed: number; duration: number | ((len: number) => number); - easing: (t: number) => number, + easing: (t: number) => number; } export function draw(node: SVGElement & { getTotalLength(): number }, { @@ -167,18 +167,18 @@ export function draw(node: SVGElement & { getTotalLength(): number }, { interface CrossfadeParams { delay: number; duration: number | ((len: number) => number); - easing: (t: number) => number, + easing: (t: number) => number; } type ClientRectMap = Map<any, { rect: ClientRect }>; export function crossfade({ fallback, ...defaults }: CrossfadeParams & { - fallback: (node: Element, params: CrossfadeParams, intro: boolean)=> TransitionConfig + fallback: (node: Element, params: CrossfadeParams, intro: boolean) => TransitionConfig; }) { const to_receive: ClientRectMap = new Map(); const to_send: ClientRectMap = new Map(); - function crossfade(from: ClientRect, node: Element, params: CrossfadeParams):TransitionConfig { + function crossfade(from: ClientRect, node: Element, params: CrossfadeParams): TransitionConfig { const { delay = 0, duration = d => Math.sqrt(d) * 30, diff --git a/src/runtime/tsconfig.json b/src/runtime/tsconfig.json new file mode 100644 index 0000000000..f3b4691b41 --- /dev/null +++ b/src/runtime/tsconfig.json @@ -0,0 +1,15 @@ +{ + "extends": "../../tsconfig.json", + "include": ["."], + + "compilerOptions": { + "lib": ["es2015", "dom", "dom.iterable"], + "target": "es2015", + "types": [], + + "baseUrl": ".", + "paths": { + "svelte/*": ["*"] + } + } +} diff --git a/test/.eslintrc.json b/test/.eslintrc.json new file mode 100644 index 0000000000..d5ba8f9d9c --- /dev/null +++ b/test/.eslintrc.json @@ -0,0 +1,5 @@ +{ + "rules": { + "no-console": "off" + } +} diff --git a/test/js/samples/action/expected.js b/test/js/samples/action/expected.js index cbbcb0d317..ed0a0a7430 100644 --- a/test/js/samples/action/expected.js +++ b/test/js/samples/action/expected.js @@ -1,6 +1,7 @@ /* generated by Svelte vX.Y.Z */ import { SvelteComponent, + attr, detach, element, init, @@ -16,7 +17,7 @@ function create_fragment(ctx) { c() { a = element("a"); a.textContent = "Test"; - a.href = "#"; + attr(a, "href", "#"); }, m(target, anchor) { diff --git a/test/js/samples/collapses-text-around-comments/expected.js b/test/js/samples/collapses-text-around-comments/expected.js index 12164d0579..09b40a1e98 100644 --- a/test/js/samples/collapses-text-around-comments/expected.js +++ b/test/js/samples/collapses-text-around-comments/expected.js @@ -2,6 +2,7 @@ import { SvelteComponent, append, + attr, detach, element, init, @@ -26,7 +27,7 @@ function create_fragment(ctx) { c() { p = element("p"); t = text(ctx.foo); - p.className = "svelte-1a7i8ec"; + attr(p, "class", "svelte-1a7i8ec"); }, m(target, anchor) { diff --git a/test/js/samples/css-media-query/expected.js b/test/js/samples/css-media-query/expected.js index d4be134376..82b7c5dfc8 100644 --- a/test/js/samples/css-media-query/expected.js +++ b/test/js/samples/css-media-query/expected.js @@ -2,6 +2,7 @@ import { SvelteComponent, append, + attr, detach, element, init, @@ -23,7 +24,7 @@ function create_fragment(ctx) { return { c() { div = element("div"); - div.className = "svelte-1slhpfn"; + attr(div, "class", "svelte-1slhpfn"); }, m(target, anchor) { diff --git a/test/js/samples/each-block-changed-check/expected.js b/test/js/samples/each-block-changed-check/expected.js index 951565bae4..b4d4577df3 100644 --- a/test/js/samples/each-block-changed-check/expected.js +++ b/test/js/samples/each-block-changed-check/expected.js @@ -2,6 +2,7 @@ import { SvelteComponent, append, + attr, destroy_each, detach, detach_after, @@ -39,8 +40,8 @@ function create_each_block(ctx) { t5 = text(" ago:"); t6 = space(); raw_before = element('noscript'); - span.className = "meta"; - div.className = "comment"; + attr(span, "class", "meta"); + attr(div, "class", "comment"); }, m(target, anchor) { diff --git a/test/js/samples/event-handler-no-passive/expected.js b/test/js/samples/event-handler-no-passive/expected.js index 41fcbeeb2a..e8ca72c556 100644 --- a/test/js/samples/event-handler-no-passive/expected.js +++ b/test/js/samples/event-handler-no-passive/expected.js @@ -1,6 +1,7 @@ /* generated by Svelte vX.Y.Z */ import { SvelteComponent, + attr, detach, element, init, @@ -17,7 +18,7 @@ function create_fragment(ctx) { c() { a = element("a"); a.textContent = "this should not navigate to example.com"; - a.href = "https://example.com"; + attr(a, "href", "https://example.com"); dispose = listen(a, "touchstart", touchstart_handler); }, diff --git a/test/js/samples/head-no-whitespace/expected.js b/test/js/samples/head-no-whitespace/expected.js index b95177bba7..457df77dc8 100644 --- a/test/js/samples/head-no-whitespace/expected.js +++ b/test/js/samples/head-no-whitespace/expected.js @@ -2,6 +2,7 @@ import { SvelteComponent, append, + attr, detach, element, init, @@ -16,10 +17,10 @@ function create_fragment(ctx) { c() { meta0 = element("meta"); meta1 = element("meta"); - meta0.name = "twitter:creator"; - meta0.content = "@sveltejs"; - meta1.name = "twitter:title"; - meta1.content = "Svelte"; + attr(meta0, "name", "twitter:creator"); + attr(meta0, "content", "@sveltejs"); + attr(meta1, "name", "twitter:title"); + attr(meta1, "content", "Svelte"); }, m(target, anchor) { diff --git a/test/js/samples/inline-style-unoptimized/expected.js b/test/js/samples/inline-style-unoptimized/expected.js index 8f3b668827..9349ade12c 100644 --- a/test/js/samples/inline-style-unoptimized/expected.js +++ b/test/js/samples/inline-style-unoptimized/expected.js @@ -1,6 +1,7 @@ /* generated by Svelte vX.Y.Z */ import { SvelteComponent, + attr, detach, element, init, @@ -18,8 +19,8 @@ function create_fragment(ctx) { div0 = element("div"); t = space(); div1 = element("div"); - div0.style.cssText = ctx.style; - div1.style.cssText = div1_style_value = "" + ctx.key + ": " + ctx.value; + attr(div0, "style", ctx.style); + attr(div1, "style", div1_style_value = "" + ctx.key + ": " + ctx.value); }, m(target, anchor) { @@ -30,11 +31,11 @@ function create_fragment(ctx) { p(changed, ctx) { if (changed.style) { - div0.style.cssText = ctx.style; + attr(div0, "style", ctx.style); } if ((changed.key || changed.value) && div1_style_value !== (div1_style_value = "" + ctx.key + ": " + ctx.value)) { - div1.style.cssText = div1_style_value; + attr(div1, "style", div1_style_value); } }, diff --git a/test/parser/samples/attribute-with-whitespace/input.svelte b/test/parser/samples/attribute-with-whitespace/input.svelte new file mode 100644 index 0000000000..2743a89ed0 --- /dev/null +++ b/test/parser/samples/attribute-with-whitespace/input.svelte @@ -0,0 +1 @@ +<button on:click= {foo}>Click</button> diff --git a/test/parser/samples/attribute-with-whitespace/output.json b/test/parser/samples/attribute-with-whitespace/output.json new file mode 100644 index 0000000000..eab6054f2a --- /dev/null +++ b/test/parser/samples/attribute-with-whitespace/output.json @@ -0,0 +1,39 @@ +{ + "html": { + "start": 0, + "end": 38, + "type": "Fragment", + "children": [ + { + "start": 0, + "end": 38, + "type": "Element", + "name": "button", + "attributes": [ + { + "start": 8, + "end": 23, + "type": "EventHandler", + "name": "click", + "modifiers": [], + "expression": { + "type": "Identifier", + "start": 19, + "end": 22, + "name": "foo" + } + } + ], + "children": [ + { + "start": 24, + "end": 29, + "type": "Text", + "raw": "Click", + "data": "Click" + } + ] + } + ] + } +} diff --git a/test/runtime/samples/animation-css/_config.js b/test/runtime/samples/animation-css/_config.js index 544c6378ff..201a282e58 100644 --- a/test/runtime/samples/animation-css/_config.js +++ b/test/runtime/samples/animation-css/_config.js @@ -29,9 +29,9 @@ export default { right: 100, top, bottom: top + 20 - } + }; }; - }) + }); component.things = [ { id: 5, name: 'e' }, diff --git a/test/runtime/samples/animation-js-delay/_config.js b/test/runtime/samples/animation-js-delay/_config.js index faed25ecaa..6bd02d17e6 100644 --- a/test/runtime/samples/animation-js-delay/_config.js +++ b/test/runtime/samples/animation-js-delay/_config.js @@ -29,9 +29,9 @@ export default { right: 100, top, bottom: top + 20 - } + }; }; - }) + }); component.things = [ { id: 5, name: 'e' }, diff --git a/test/runtime/samples/animation-js-easing/_config.js b/test/runtime/samples/animation-js-easing/_config.js index a31825c3f9..415af042a9 100644 --- a/test/runtime/samples/animation-js-easing/_config.js +++ b/test/runtime/samples/animation-js-easing/_config.js @@ -29,9 +29,9 @@ export default { right: 100, top, bottom: top + 20 - } + }; }; - }) + }); component.things = [ { id: 5, name: 'e' }, diff --git a/test/runtime/samples/animation-js/_config.js b/test/runtime/samples/animation-js/_config.js index d5991a915a..521753633d 100644 --- a/test/runtime/samples/animation-js/_config.js +++ b/test/runtime/samples/animation-js/_config.js @@ -29,7 +29,7 @@ export default { right: 100, top, bottom: top + 20 - } + }; }; }); diff --git a/test/runtime/samples/await-containing-if/_config.js b/test/runtime/samples/await-containing-if/_config.js index 9e24e4f614..cd83585cc1 100644 --- a/test/runtime/samples/await-containing-if/_config.js +++ b/test/runtime/samples/await-containing-if/_config.js @@ -1,6 +1,6 @@ let fulfil; -let thePromise = new Promise(f => { +const thePromise = new Promise(f => { fulfil = f; }); diff --git a/test/runtime/samples/await-in-each/_config.js b/test/runtime/samples/await-in-each/_config.js index b1a232e4bd..6c7da69ee3 100644 --- a/test/runtime/samples/await-in-each/_config.js +++ b/test/runtime/samples/await-in-each/_config.js @@ -1,6 +1,6 @@ let fulfil; -let thePromise = new Promise(f => { +const thePromise = new Promise(f => { fulfil = f; }); diff --git a/test/runtime/samples/await-then-catch-order/_config.js b/test/runtime/samples/await-then-catch-order/_config.js index 5c4eb530e9..f972520904 100644 --- a/test/runtime/samples/await-then-catch-order/_config.js +++ b/test/runtime/samples/await-then-catch-order/_config.js @@ -1,6 +1,6 @@ let fulfil; -let thePromise = new Promise(f => { +const thePromise = new Promise(f => { fulfil = f; }); diff --git a/test/runtime/samples/await-with-components/_config.js b/test/runtime/samples/await-with-components/_config.js index ffef7441ff..a0a558782a 100644 --- a/test/runtime/samples/await-with-components/_config.js +++ b/test/runtime/samples/await-with-components/_config.js @@ -1,6 +1,7 @@ export default { async test({ assert, component, target }) { - let resolve, reject; + let resolve; + let reject; let promise = new Promise(ok => resolve = ok); component.promise = promise; diff --git a/test/runtime/samples/binding-textarea/_config.js b/test/runtime/samples/binding-textarea/_config.js index c09256e059..ac092096e6 100644 --- a/test/runtime/samples/binding-textarea/_config.js +++ b/test/runtime/samples/binding-textarea/_config.js @@ -9,7 +9,7 @@ export default { `, ssrHtml: ` - <textarea value="some text"></textarea> + <textarea>some text</textarea> <p>some text</p> `, diff --git a/test/runtime/samples/component-event-handler-modifier-once/Button.svelte b/test/runtime/samples/component-event-handler-modifier-once/Button.svelte new file mode 100644 index 0000000000..9b5b7a5f67 --- /dev/null +++ b/test/runtime/samples/component-event-handler-modifier-once/Button.svelte @@ -0,0 +1 @@ +<button on:click><slot></slot></button> \ No newline at end of file diff --git a/test/runtime/samples/component-event-handler-modifier-once/_config.js b/test/runtime/samples/component-event-handler-modifier-once/_config.js new file mode 100644 index 0000000000..41daf374c8 --- /dev/null +++ b/test/runtime/samples/component-event-handler-modifier-once/_config.js @@ -0,0 +1,16 @@ +export default { + html: ` + <button>0</button> + `, + + async test({ assert, component, target, window }) { + const button = target.querySelector('button'); + const event = new window.MouseEvent('click'); + + await button.dispatchEvent(event); + assert.equal(component.count, 1); + + await button.dispatchEvent(event); + assert.equal(component.count, 1); + } +}; diff --git a/test/runtime/samples/component-event-handler-modifier-once/main.svelte b/test/runtime/samples/component-event-handler-modifier-once/main.svelte new file mode 100644 index 0000000000..b9bca3b5eb --- /dev/null +++ b/test/runtime/samples/component-event-handler-modifier-once/main.svelte @@ -0,0 +1,6 @@ +<script> + import Button from './Button.svelte'; + export let count = 0; +</script> + +<Button on:click|once="{() => count += 1}">{count}</Button> \ No newline at end of file diff --git a/test/runtime/samples/component-slot-named-inherits-default-lets/_config.js b/test/runtime/samples/component-slot-named-inherits-default-lets/_config.js index 212c57308a..a07a1482bc 100644 --- a/test/runtime/samples/component-slot-named-inherits-default-lets/_config.js +++ b/test/runtime/samples/component-slot-named-inherits-default-lets/_config.js @@ -22,4 +22,4 @@ export default { </div> `); } -} \ No newline at end of file +}; \ No newline at end of file diff --git a/test/runtime/samples/contenteditable-html/_config.js b/test/runtime/samples/contenteditable-html/_config.js new file mode 100644 index 0000000000..285512b6c9 --- /dev/null +++ b/test/runtime/samples/contenteditable-html/_config.js @@ -0,0 +1,43 @@ +export default { + props: { + name: '<b>world</b>', + }, + + html: ` + <editor contenteditable="true"><b>world</b></editor> + <p>hello <b>world</b></p> + `, + + ssrHtml: ` + <editor contenteditable="true"><b>world</b></editor> + <p>hello <b>world</b></p> + `, + + async test({ assert, component, target, window }) { + const el = target.querySelector('editor'); + assert.equal(el.innerHTML, '<b>world</b>'); + + el.innerHTML = 'every<span>body</span>'; + + // No updates to data yet + assert.htmlEqual(target.innerHTML, ` + <editor contenteditable="true">every<span>body</span></editor> + <p>hello <b>world</b></p> + `); + + // Handle user input + const event = new window.Event('input'); + await el.dispatchEvent(event); + assert.htmlEqual(target.innerHTML, ` + <editor contenteditable="true">every<span>body</span></editor> + <p>hello every<span>body</span></p> + `); + + component.name = 'good<span>bye</span>'; + assert.equal(el.innerHTML, 'good<span>bye</span>'); + assert.htmlEqual(target.innerHTML, ` + <editor contenteditable="true">good<span>bye</span></editor> + <p>hello good<span>bye</span></p> + `); + }, +}; 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 @@ +<script> + export let name; +</script> + +<editor contenteditable="true" bind:html={name}></editor> +<p>hello {@html name}</p> \ 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..059cda7cfe --- /dev/null +++ b/test/runtime/samples/contenteditable-text/_config.js @@ -0,0 +1,37 @@ +export default { + props: { + name: 'world', + }, + + html: ` + <editor contenteditable="true">world</editor> + <p>hello world</p> + `, + + ssrHtml: ` + <editor contenteditable="true">world</editor> + <p>hello world</p> + `, + + 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, ` + <editor contenteditable="true">everybody</editor> + <p>hello everybody</p> + `); + + component.name = 'goodbye'; + assert.equal(el.textContent, 'goodbye'); + assert.htmlEqual(target.innerHTML, ` + <editor contenteditable="true">goodbye</editor> + <p>hello goodbye</p> + `); + }, +}; 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 @@ +<script> + export let name; +</script> + +<editor contenteditable="true" bind:text={name}></editor> +<p>hello {name}</p> \ 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: ` <foo-bar>Hello</foo-bar> ` -} +}; diff --git a/test/runtime/samples/export-function-hoisting/_config.js b/test/runtime/samples/export-function-hoisting/_config.js index c56851d065..f01c8b4841 100644 --- a/test/runtime/samples/export-function-hoisting/_config.js +++ b/test/runtime/samples/export-function-hoisting/_config.js @@ -1,3 +1,3 @@ export default { - html: 'Compile plz' -} + html: 'Compile plz' +}; diff --git a/test/runtime/samples/function-hoisting/_config.js b/test/runtime/samples/function-hoisting/_config.js index 5a22ffaf0b..91492d8c38 100644 --- a/test/runtime/samples/function-hoisting/_config.js +++ b/test/runtime/samples/function-hoisting/_config.js @@ -1,7 +1,7 @@ export default { - props: { - greeting: 'Good day' - }, + props: { + greeting: 'Good day' + }, - html: '<h1>Good day, world</h1>' -} + html: '<h1>Good day, world</h1>' +}; diff --git a/test/runtime/samples/get-after-destroy/_config.js b/test/runtime/samples/get-after-destroy/_config.js index bf4d8e90ba..5d10bbe72a 100644 --- a/test/runtime/samples/get-after-destroy/_config.js +++ b/test/runtime/samples/get-after-destroy/_config.js @@ -10,4 +10,4 @@ export default { const { foo } = component; assert.equal(foo, undefined); } -} \ No newline at end of file +}; diff --git a/test/runtime/samples/head-title-empty/_config.js b/test/runtime/samples/head-title-empty/_config.js new file mode 100644 index 0000000000..497855156c --- /dev/null +++ b/test/runtime/samples/head-title-empty/_config.js @@ -0,0 +1,5 @@ +export default { + test({ assert, window }) { + assert.equal(window.document.title, ''); + } +}; \ No newline at end of file diff --git a/test/runtime/samples/head-title-empty/main.svelte b/test/runtime/samples/head-title-empty/main.svelte new file mode 100644 index 0000000000..3f81715df5 --- /dev/null +++ b/test/runtime/samples/head-title-empty/main.svelte @@ -0,0 +1,3 @@ +<svelte:head> + <title> + \ No newline at end of file diff --git a/test/runtime/samples/immutable-nested/_config.js b/test/runtime/samples/immutable-nested/_config.js index da90b43727..8b1dd7e68a 100644 --- a/test/runtime/samples/immutable-nested/_config.js +++ b/test/runtime/samples/immutable-nested/_config.js @@ -15,7 +15,7 @@ export default { `, test({ assert, component, target }) { - var nested = component.nested; + const nested = component.nested; assert.htmlEqual(target.innerHTML, `
@@ -24,6 +24,7 @@ export default {
`); + // eslint-disable-next-line no-self-assign nested.foo = nested.foo; assert.htmlEqual(target.innerHTML, `
diff --git a/test/runtime/samples/immutable-option/_config.js b/test/runtime/samples/immutable-option/_config.js index 0aaa742fbe..1224d0213a 100644 --- a/test/runtime/samples/immutable-option/_config.js +++ b/test/runtime/samples/immutable-option/_config.js @@ -4,6 +4,7 @@ export default { html: `

Called 1 times.

`, test({ assert, component, target }) { + // eslint-disable-next-line no-self-assign component.foo = component.foo; assert.htmlEqual(target.innerHTML, `

Called 1 times.

`); } diff --git a/test/runtime/samples/immutable-svelte-meta-false/_config.js b/test/runtime/samples/immutable-svelte-meta-false/_config.js index 933c151d6b..664f99f087 100644 --- a/test/runtime/samples/immutable-svelte-meta-false/_config.js +++ b/test/runtime/samples/immutable-svelte-meta-false/_config.js @@ -4,6 +4,7 @@ export default { html: `

Called 1 times.

`, test({ assert, component, target }) { + // eslint-disable-next-line no-self-assign component.foo = component.foo; assert.htmlEqual(target.innerHTML, `

Called 2 times.

`); } diff --git a/test/runtime/samples/immutable-svelte-meta/_config.js b/test/runtime/samples/immutable-svelte-meta/_config.js index 9bd32dbd11..4e39f36224 100644 --- a/test/runtime/samples/immutable-svelte-meta/_config.js +++ b/test/runtime/samples/immutable-svelte-meta/_config.js @@ -2,6 +2,7 @@ export default { html: `

Called 1 times.

`, test({ assert, component, target }) { + // eslint-disable-next-line no-self-assign component.foo = component.foo; assert.htmlEqual(target.innerHTML, `

Called 1 times.

`); } diff --git a/test/runtime/samples/internal-state/_config.js b/test/runtime/samples/internal-state/_config.js index 09ea61a8eb..6b8440aaf3 100644 --- a/test/runtime/samples/internal-state/_config.js +++ b/test/runtime/samples/internal-state/_config.js @@ -1,18 +1,18 @@ 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/nbsp-div/_config.js b/test/runtime/samples/nbsp-div/_config.js new file mode 100644 index 0000000000..6026af2c90 --- /dev/null +++ b/test/runtime/samples/nbsp-div/_config.js @@ -0,0 +1,19 @@ +export default { + html: `
 hello
+
 hello  
+
 hello   hello
`, + + test({ assert, component, target }) { + var divList = target.querySelectorAll('div') + assert.equal( divList[0].textContent.charCodeAt( 0 ), 160 ); + assert.equal( divList[1].textContent.charCodeAt( 0 ), 160 ); + assert.equal( divList[1].textContent.charCodeAt( 6 ), 160 ); + assert.equal( divList[1].textContent.charCodeAt( 7 ), 160 ); + assert.equal( divList[2].textContent.charCodeAt( 0 ), 160 ); + assert.equal( divList[2].textContent.charCodeAt( 6 ), 160 ); + assert.equal( divList[2].textContent.charCodeAt( 7 ), 32 );//normal space + assert.equal( divList[2].textContent.charCodeAt( 8 ), 160 ); + + + } +}; \ No newline at end of file diff --git a/test/runtime/samples/nbsp-div/main.svelte b/test/runtime/samples/nbsp-div/main.svelte new file mode 100644 index 0000000000..64557bfeb1 --- /dev/null +++ b/test/runtime/samples/nbsp-div/main.svelte @@ -0,0 +1,7 @@ + + +
 {name}
+
 {name}  
+
 {name}   {name}
\ No newline at end of file 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/set-undefined-attr/_config.js b/test/runtime/samples/set-undefined-attr/_config.js index e28bad8257..b23f51dfc9 100644 --- a/test/runtime/samples/set-undefined-attr/_config.js +++ b/test/runtime/samples/set-undefined-attr/_config.js @@ -1,5 +1,5 @@ export default { - html: '
', + html: `
`, - ssrHtml: '
' + ssrHtml: `
`, }; diff --git a/test/runtime/samples/set-undefined-attr/main.svelte b/test/runtime/samples/set-undefined-attr/main.svelte index 8191acbeff..77a1885415 100644 --- a/test/runtime/samples/set-undefined-attr/main.svelte +++ b/test/runtime/samples/set-undefined-attr/main.svelte @@ -3,10 +3,11 @@ export let foo = 1; export let bar; + export let _class; onMount(() => { foo = undefined; }); -
+
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/styles-nested/_actual.css b/test/server-side-rendering/samples/styles-nested/_actual.css deleted file mode 100644 index 775ae8a91c..0000000000 --- a/test/server-side-rendering/samples/styles-nested/_actual.css +++ /dev/null @@ -1,2 +0,0 @@ -div.svelte-bzh57p{color:red} -div.svelte-4yw8vx{color:green} \ No newline at end of file diff --git a/test/server-side-rendering/samples/styles/_actual.css b/test/server-side-rendering/samples/styles/_actual.css deleted file mode 100644 index 2025c64f84..0000000000 --- a/test/server-side-rendering/samples/styles/_actual.css +++ /dev/null @@ -1 +0,0 @@ -div.svelte-bzh57p{color:red} \ No newline at end of file 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/tsconfig.json b/test/tsconfig.json new file mode 100644 index 0000000000..82eaf0245e --- /dev/null +++ b/test/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../tsconfig.json", + "include": ["."], + + "compilerOptions": { + "allowJs": true, + "checkJs": true, + "noEmit": true + } +} 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 @@ + + diff --git a/test/validator/samples/contenteditable-missing/errors.json b/test/validator/samples/contenteditable-missing/errors.json new file mode 100644 index 0000000000..9cadb20629 --- /dev/null +++ b/test/validator/samples/contenteditable-missing/errors.json @@ -0,0 +1,15 @@ +[{ + "code": "missing-contenteditable-attribute", + "message": "'contenteditable' attribute is required for text and html two-way bindings", + "start": { + "line": 4, + "column": 8, + "character": 48 + }, + "end": { + "line": 4, + "column": 24, + "character": 64 + }, + "pos": 48 +}] \ No newline at end of file diff --git a/test/validator/samples/contenteditable-missing/input.svelte b/test/validator/samples/contenteditable-missing/input.svelte new file mode 100644 index 0000000000..47f125894a --- /dev/null +++ b/test/validator/samples/contenteditable-missing/input.svelte @@ -0,0 +1,4 @@ + + diff --git a/tsconfig.json b/tsconfig.json index 9ac29a84fe..39476f3dd1 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,31 +1,30 @@ { + "include": [], + "compilerOptions": { - "target": "es2015", - "module": "es6", + "rootDir": "src", + + // target node v8+ (https://node.green/) + // the only missing feature is Array.prototype.values + "lib": ["es2017"], + "target": "es2017", + "declaration": true, "declarationDir": "types", - "noImplicitThis": true, + "noEmitOnError": true, - "lib": [ - "es5", - "es6", - "dom", - "es2015" - ], - "importHelpers": true, + "noErrorTruncation": true, + + // rollup takes care of these + "module": "esnext", "moduleResolution": "node", - "baseUrl": ".", - "paths": { - "svelte/internal": ["./src/runtime/internal/index"], - "svelte/easing": ["./src/runtime/easing/index"], - "svelte/motion": ["./src/runtime/motion/index"], - "svelte/store": ["./src/runtime/store/index"] - }, - "typeRoots": [ - "node_modules/@types" - ] - }, - "include": [ - "src/**/*" - ] + "resolveJsonModule": true, + "allowSyntheticDefaultImports": true, + + // TODO: error all the things + //"strict": true, + "noImplicitThis": true, + "noUnusedLocals": true, + "noUnusedParameters": true + } }