Merge branch 'master' into silence-warnings

pull/6504/head
Simon Holthausen 5 years ago
commit b62355d133

@ -7,6 +7,7 @@
* Add `varsReport` compiler option to include all variables reference in the component in the `variables` report ([#6192](https://github.com/sveltejs/svelte/pull/6192)) * Add `varsReport` compiler option to include all variables reference in the component in the `variables` report ([#6192](https://github.com/sveltejs/svelte/pull/6192))
* Throw compiler error when passing empty directive names ([#6299](https://github.com/sveltejs/svelte/issues/6299)) * Throw compiler error when passing empty directive names ([#6299](https://github.com/sveltejs/svelte/issues/6299))
* Throw proper error for `export default function() {}` and `export default class {}` rather than crashing the compiler ([#3275](https://github.com/sveltejs/svelte/issues/3275)) * Throw proper error for `export default function() {}` and `export default class {}` rather than crashing the compiler ([#3275](https://github.com/sveltejs/svelte/issues/3275))
* Fix usage of falsy `input` values ([#6458](https://github.com/sveltejs/svelte/pull/6458))
* Fix ordering of elements in keyed `{#each}` ([#6445](https://github.com/sveltejs/svelte/pull/6445)) * Fix ordering of elements in keyed `{#each}` ([#6445](https://github.com/sveltejs/svelte/pull/6445))
* Fix `preserveComments` in SSR mode ([#4730](https://github.com/sveltejs/svelte/issues/4730)) * Fix `preserveComments` in SSR mode ([#4730](https://github.com/sveltejs/svelte/issues/4730))
* Fix compiler error when using `:where()` inside `:global()` ([#6434](https://github.com/sveltejs/svelte/issues/6434)) * Fix compiler error when using `:where()` inside `:global()` ([#6434](https://github.com/sveltejs/svelte/issues/6434))

@ -6,12 +6,17 @@ Set up the site sub-project:
git clone https://github.com/sveltejs/svelte.git git clone https://github.com/sveltejs/svelte.git
cd site cd site
npm ci npm ci
npm run update
npm run dev npm run dev
``` ```
and navigate to [localhost:3000](http://localhost:3000). and navigate to [localhost:3000](http://localhost:3000).
The first time you run the site locally, it will update the list of Contributors and REPL dependencies. After this it won't run again unless you force it by running:
```bash
npm run update
```
## Running using the local copy of Svelte ## Running using the local copy of Svelte
By default, the REPL will fetch the most recent version of Svelte from https://unpkg.com/svelte. When running the site locally, you can also use your local copy of Svelte. By default, the REPL will fetch the most recent version of Svelte from https://unpkg.com/svelte. When running the site locally, you can also use your local copy of Svelte.
@ -25,7 +30,6 @@ npm ci
PUBLISH=1 npm run build PUBLISH=1 npm run build
cd site cd site
npm ci npm ci
npm run update
npm run dev npm run dev
``` ```

@ -1851,19 +1851,6 @@
"integrity": "sha512-Se+LaxqXlVXGvmexKGPvnUIYC1jwXu1H6Pkyb3uBM5d8/NELMYCHs/4/roD7721NxrTLyv7e5nXd5/QLBO+10g==", "integrity": "sha512-Se+LaxqXlVXGvmexKGPvnUIYC1jwXu1H6Pkyb3uBM5d8/NELMYCHs/4/roD7721NxrTLyv7e5nXd5/QLBO+10g==",
"dev": true "dev": true
}, },
"cross-spawn": {
"version": "6.0.5",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
"integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==",
"dev": true,
"requires": {
"nice-try": "^1.0.4",
"path-key": "^2.0.1",
"semver": "^5.5.0",
"shebang-command": "^1.2.0",
"which": "^1.2.9"
}
},
"debug": { "debug": {
"version": "4.3.1", "version": "4.3.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
@ -1950,15 +1937,6 @@
"integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==",
"dev": true "dev": true
}, },
"error-ex": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
"integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
"dev": true,
"requires": {
"is-arrayish": "^0.2.1"
}
},
"es-abstract": { "es-abstract": {
"version": "1.18.0-next.1", "version": "1.18.0-next.1",
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.1.tgz", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.1.tgz",
@ -2139,12 +2117,6 @@
"integrity": "sha512-YSwLaGMOgSBx9roJlNLL12c+FRiw7VECphinc6mGucphc/ZxTHgdEz6gmJqH6NOzYEd/yr64hwjom5pZ+tJVpg==", "integrity": "sha512-YSwLaGMOgSBx9roJlNLL12c+FRiw7VECphinc6mGucphc/ZxTHgdEz6gmJqH6NOzYEd/yr64hwjom5pZ+tJVpg==",
"dev": true "dev": true
}, },
"graceful-fs": {
"version": "4.2.4",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz",
"integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==",
"dev": true
},
"growl": { "growl": {
"version": "1.10.5", "version": "1.10.5",
"resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz",
@ -2178,12 +2150,6 @@
"integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
"dev": true "dev": true
}, },
"hosted-git-info": {
"version": "2.8.9",
"resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz",
"integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==",
"dev": true
},
"html-minifier": { "html-minifier": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-4.0.0.tgz", "resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-4.0.0.tgz",
@ -2237,12 +2203,6 @@
"integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==",
"dev": true "dev": true
}, },
"is-arrayish": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
"integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=",
"dev": true
},
"is-buffer": { "is-buffer": {
"version": "2.0.5", "version": "2.0.5",
"resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz",
@ -2396,12 +2356,6 @@
"integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==",
"dev": true "dev": true
}, },
"json-parse-better-errors": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz",
"integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==",
"dev": true
},
"json5": { "json5": {
"version": "2.1.3", "version": "2.1.3",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz", "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz",
@ -2471,18 +2425,6 @@
} }
} }
}, },
"load-json-file": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz",
"integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=",
"dev": true,
"requires": {
"graceful-fs": "^4.1.2",
"parse-json": "^4.0.0",
"pify": "^3.0.0",
"strip-bom": "^3.0.0"
}
},
"locate-path": { "locate-path": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
@ -2569,12 +2511,6 @@
"resolved": "https://registry.npmjs.org/marked/-/marked-1.2.7.tgz", "resolved": "https://registry.npmjs.org/marked/-/marked-1.2.7.tgz",
"integrity": "sha512-No11hFYcXr/zkBvL6qFmAp1z6BKY3zqLMHny/JN/ey+al7qwCM2+CMBL9BOgqMxZU36fz4cCWfn2poWIf7QRXA==" "integrity": "sha512-No11hFYcXr/zkBvL6qFmAp1z6BKY3zqLMHny/JN/ey+al7qwCM2+CMBL9BOgqMxZU36fz4cCWfn2poWIf7QRXA=="
}, },
"memorystream": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz",
"integrity": "sha1-htcJCzDORV1j+64S3aUaR93K+bI=",
"dev": true
},
"merge-stream": { "merge-stream": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
@ -2724,12 +2660,6 @@
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
}, },
"nice-try": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
"integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==",
"dev": true
},
"no-case": { "no-case": {
"version": "2.3.2", "version": "2.3.2",
"resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz", "resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz",
@ -2852,35 +2782,6 @@
} }
} }
}, },
"normalize-package-data": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
"integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==",
"dev": true,
"requires": {
"hosted-git-info": "^2.1.4",
"resolve": "^1.10.0",
"semver": "2 || 3 || 4 || 5",
"validate-npm-package-license": "^3.0.1"
}
},
"npm-run-all": {
"version": "4.1.5",
"resolved": "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.5.tgz",
"integrity": "sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ==",
"dev": true,
"requires": {
"ansi-styles": "^3.2.1",
"chalk": "^2.4.1",
"cross-spawn": "^6.0.5",
"memorystream": "^0.3.1",
"minimatch": "^3.0.4",
"pidtree": "^0.3.0",
"read-pkg": "^3.0.0",
"shell-quote": "^1.6.1",
"string.prototype.padend": "^3.0.0"
}
},
"object-inspect": { "object-inspect": {
"version": "1.9.0", "version": "1.9.0",
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.9.0.tgz", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.9.0.tgz",
@ -3003,16 +2904,6 @@
"integrity": "sha512-QhhZ+DCCit2Coi2vmAKbq5RGTRcQUOE2+REgv8vdyu7MnYx2eZztegqtTx99TZ86GTIwqiy3+4nQTWZ2tgmdCA==", "integrity": "sha512-QhhZ+DCCit2Coi2vmAKbq5RGTRcQUOE2+REgv8vdyu7MnYx2eZztegqtTx99TZ86GTIwqiy3+4nQTWZ2tgmdCA==",
"dev": true "dev": true
}, },
"parse-json": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
"integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=",
"dev": true,
"requires": {
"error-ex": "^1.3.1",
"json-parse-better-errors": "^1.0.1"
}
},
"path-exists": { "path-exists": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
@ -3025,27 +2916,12 @@
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
"dev": true "dev": true
}, },
"path-key": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
"integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=",
"dev": true
},
"path-parse": { "path-parse": {
"version": "1.0.6", "version": "1.0.6",
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
"integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==",
"dev": true "dev": true
}, },
"path-type": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz",
"integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==",
"dev": true,
"requires": {
"pify": "^3.0.0"
}
},
"pg": { "pg": {
"version": "7.18.2", "version": "7.18.2",
"resolved": "https://registry.npmjs.org/pg/-/pg-7.18.2.tgz", "resolved": "https://registry.npmjs.org/pg/-/pg-7.18.2.tgz",
@ -3120,18 +2996,6 @@
"integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==",
"dev": true "dev": true
}, },
"pidtree": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.3.1.tgz",
"integrity": "sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA==",
"dev": true
},
"pify": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
"integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
"dev": true
},
"pixelmatch": { "pixelmatch": {
"version": "4.0.2", "version": "4.0.2",
"resolved": "https://registry.npmjs.org/pixelmatch/-/pixelmatch-4.0.2.tgz", "resolved": "https://registry.npmjs.org/pixelmatch/-/pixelmatch-4.0.2.tgz",
@ -3204,17 +3068,6 @@
"safe-buffer": "^5.1.0" "safe-buffer": "^5.1.0"
} }
}, },
"read-pkg": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz",
"integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=",
"dev": true,
"requires": {
"load-json-file": "^4.0.0",
"normalize-package-data": "^2.3.2",
"path-type": "^3.0.0"
}
},
"readable-stream": { "readable-stream": {
"version": "3.6.0", "version": "3.6.0",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
@ -3441,27 +3294,6 @@
"integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
"dev": true "dev": true
}, },
"shebang-command": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
"integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=",
"dev": true,
"requires": {
"shebang-regex": "^1.0.0"
}
},
"shebang-regex": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
"integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=",
"dev": true
},
"shell-quote": {
"version": "1.7.2",
"resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.2.tgz",
"integrity": "sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg==",
"dev": true
},
"shelljs": { "shelljs": {
"version": "0.8.4", "version": "0.8.4",
"resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.4.tgz", "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.4.tgz",
@ -3519,38 +3351,6 @@
"integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==",
"dev": true "dev": true
}, },
"spdx-correct": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz",
"integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==",
"dev": true,
"requires": {
"spdx-expression-parse": "^3.0.0",
"spdx-license-ids": "^3.0.0"
}
},
"spdx-exceptions": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz",
"integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==",
"dev": true
},
"spdx-expression-parse": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz",
"integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==",
"dev": true,
"requires": {
"spdx-exceptions": "^2.1.0",
"spdx-license-ids": "^3.0.0"
}
},
"spdx-license-ids": {
"version": "3.0.7",
"resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.7.tgz",
"integrity": "sha512-U+MTEOO0AiDzxwFvoa4JVnMV6mZlJKk2sBLt90s7G0Gd0Mlknc7kxEn3nuDPNZRta7O2uy8oLcZLVT+4sqNZHQ==",
"dev": true
},
"split2": { "split2": {
"version": "3.2.2", "version": "3.2.2",
"resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz", "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz",
@ -3581,17 +3381,6 @@
"strip-ansi": "^4.0.0" "strip-ansi": "^4.0.0"
} }
}, },
"string.prototype.padend": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.1.1.tgz",
"integrity": "sha512-eCzTASPnoCr5Ht+Vn1YXgm8SB015hHKgEIMu9Nr9bQmLhRBxKRfmzSj/IQsxDFc8JInJDDFA0qXwK+xxI7wDkg==",
"dev": true,
"requires": {
"call-bind": "^1.0.0",
"define-properties": "^1.1.3",
"es-abstract": "^1.18.0-next.1"
}
},
"string.prototype.trimend": { "string.prototype.trimend": {
"version": "1.0.3", "version": "1.0.3",
"resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.3.tgz", "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.3.tgz",
@ -3629,12 +3418,6 @@
"ansi-regex": "^3.0.0" "ansi-regex": "^3.0.0"
} }
}, },
"strip-bom": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
"integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=",
"dev": true
},
"strip-json-comments": { "strip-json-comments": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
@ -3766,16 +3549,6 @@
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
}, },
"validate-npm-package-license": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
"integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==",
"dev": true,
"requires": {
"spdx-correct": "^3.0.0",
"spdx-expression-parse": "^3.0.0"
}
},
"which": { "which": {
"version": "1.3.1", "version": "1.3.1",
"resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",

@ -3,11 +3,11 @@
"version": "1.0.0", "version": "1.0.0",
"description": "Docs and examples for Svelte", "description": "Docs and examples for Svelte",
"scripts": { "scripts": {
"dev": "npm run copy-workers && sapper dev", "dev": "node scripts/update.js && npm run copy-workers && sapper dev",
"copy-workers": "node scripts/copy-workers.js", "copy-workers": "node scripts/copy-workers.js",
"migrate": "node-pg-migrate -r dotenv/config", "migrate": "node-pg-migrate -r dotenv/config",
"build": "npm run copy-workers && sapper build --legacy", "build": "node scripts/update.js && npm run copy-workers && sapper build --legacy",
"update": "node scripts/update_template.js && node scripts/get-contributors.js", "update": "node scripts/update.js --force=true",
"start": "node __sapper__/build", "start": "node __sapper__/build",
"test": "mocha -r esm test/**", "test": "mocha -r esm test/**",
"deploy": "make deploy" "deploy": "make deploy"
@ -50,7 +50,6 @@
"mocha": "^6.2.0", "mocha": "^6.2.0",
"node-fetch": "^2.6.1", "node-fetch": "^2.6.1",
"node-pg-migrate": "^3.22.0", "node-pg-migrate": "^3.22.0",
"npm-run-all": "^4.1.5",
"rollup": "^2.30.0", "rollup": "^2.30.0",
"rollup-plugin-svelte": "^7.0.0", "rollup-plugin-svelte": "^7.0.0",
"rollup-plugin-terser": "^7.0.0", "rollup-plugin-terser": "^7.0.0",

@ -3,8 +3,16 @@ const fs = require('fs');
const fetch = require('node-fetch'); const fetch = require('node-fetch');
const Jimp = require('jimp'); const Jimp = require('jimp');
const force = process.env.FORCE_UPDATE === 'true';
process.chdir(__dirname); process.chdir(__dirname);
const outputFile = `../src/routes/_contributors.js`;
if (!force && fs.existsSync(outputFile)) {
console.info(`[update/contributors] ${outputFile} exists. Skipping`);
process.exit(0);
}
const base = `https://api.github.com/repos/sveltejs/svelte/contributors`; const base = `https://api.github.com/repos/sveltejs/svelte/contributors`;
const { GITHUB_CLIENT_ID, GITHUB_CLIENT_SECRET } = process.env; const { GITHUB_CLIENT_ID, GITHUB_CLIENT_SECRET } = process.env;
@ -48,7 +56,7 @@ async function main() {
const str = `[\n\t${authors.map(a => `'${a.login}'`).join(',\n\t')}\n]`; const str = `[\n\t${authors.map(a => `'${a.login}'`).join(',\n\t')}\n]`;
fs.writeFileSync(`../src/routes/_contributors.js`, `export default ${str};`); fs.writeFileSync(outputFile, `export default ${str};`);
} }
main(); main();

@ -0,0 +1,8 @@
const sh = require('shelljs');
sh.env['FORCE_UPDATE'] = process.argv.includes('--force=true');
Promise.all([
sh.exec('node ./scripts/get_contributors.js'),
sh.exec('node ./scripts/update_template.js')
]);

@ -1,7 +1,16 @@
const sh = require('shelljs'); const sh = require('shelljs');
const fs = require('fs'); const fs = require('fs');
const path = require('path');
sh.cd(__dirname + '/../'); const force = process.env.FORCE_UPDATE === 'true';
sh.cd(path.join(__dirname, '..'));
const outputFile = 'static/svelte-app.json';
if (!force && fs.existsSync(outputFile)) {
console.info(`[update/template] ${outputFile} exists. Skipping`);
process.exit(0);
}
// fetch svelte app // fetch svelte app
sh.rm('-rf','scripts/svelte-app'); sh.rm('-rf','scripts/svelte-app');
@ -22,4 +31,4 @@ for (const path of sh.find(appPath).filter(p => fs.lstatSync(p).isFile()) ) {
files.push({ path: path.slice(appPath.length + 1), data }); files.push({ path: path.slice(appPath.length + 1), data });
} }
fs.writeFileSync('static/svelte-app.json', JSON.stringify(files)); fs.writeFileSync(outputFile, JSON.stringify(files));

@ -3,13 +3,12 @@ import Component from '../Component';
import Renderer from './Renderer'; import Renderer from './Renderer';
import { CompileOptions, CssResult } from '../../interfaces'; import { CompileOptions, CssResult } from '../../interfaces';
import { walk } from 'estree-walker'; import { walk } from 'estree-walker';
import { extract_names, Scope } from 'periscopic'; import { extract_names, Node as PeriscopicNode, Scope } from 'periscopic';
import { invalidate } from './invalidate'; import { invalidate } from './invalidate';
import Block from './Block'; import Block from './Block';
import { ClassDeclaration, FunctionExpression, Node, Statement, ObjectExpression, Expression } from 'estree'; import { ClassDeclaration, FunctionExpression, Node, Statement, ObjectExpression, Expression } from 'estree';
import { apply_preprocessor_sourcemap } from '../../utils/mapped_code'; import { apply_preprocessor_sourcemap } from '../../utils/mapped_code';
import { RawSourceMap, DecodedSourceMap } from '@ampproject/remapping/dist/types/types'; import { RawSourceMap, DecodedSourceMap } from '@ampproject/remapping/dist/types/types';
import { Node as PeriscopicNode } from 'periscopic';
import { flatten } from '../../utils/flatten'; import { flatten } from '../../utils/flatten';
export default function dom( export default function dom(

@ -126,9 +126,11 @@ export default function(node: Element, renderer: Renderer, options: RenderOption
} else if (binding.name === 'value' && node.name === 'textarea') { } else if (binding.name === 'value' && node.name === 'textarea') {
const snippet = expression.node; const snippet = expression.node;
node_contents = x`${snippet} || ""`; node_contents = x`${snippet} || ""`;
} else if (binding.name === 'value' && node.name === 'select') {
// NOTE: do not add "value" attribute on <select />
} else { } else {
const snippet = expression.node; const snippet = expression.node;
renderer.add_expression(x`@add_attribute("${name}", ${snippet}, 1)`); renderer.add_expression(x`@add_attribute("${name}", ${snippet}, ${boolean_attributes.has(name) ? 1 : 0})`);
} }
}); });

@ -0,0 +1,192 @@
// All parser errors should be listed and accessed from here
import list from '../utils/list';
/**
* @internal
*/
export default {
css_syntax_error: (message) => ({
code: 'css-syntax-error',
message
}),
duplicate_attribute: {
code: 'duplicate-attribute',
message: 'Attributes need to be unique'
},
duplicate_element: (slug: string, name: string) => ({
code: `duplicate-${slug}`,
message: `A component can only have one <${name}> tag`
}),
duplicate_style: {
code: 'duplicate-style',
message: 'You can only have one top-level <style> tag per component'
},
empty_attribute_shorthand: {
code: 'empty-attribute-shorthand',
message: 'Attribute shorthand cannot be empty'
},
empty_directive_name: (type: string) => ({
code: 'empty-directive-name',
message: `${type} name cannot be empty`
}),
empty_global_selector: {
code: 'css-syntax-error',
message: ':global() must contain a selector'
},
expected_block_type: {
code: 'expected-block-type',
message: 'Expected if, each or await'
},
expected_name: {
code: 'expected-name',
message: 'Expected name'
},
invalid_catch_placement_unclosed_block: (block) => ({
code: 'invalid-catch-placement',
message: `Expected to close ${block} before seeing {:catch} block`
}),
invalid_catch_placement_without_await: {
code: 'invalid-catch-placement',
message: 'Cannot have an {:catch} block outside an {#await ...} block'
},
invalid_component_definition: {
code: 'invalid-component-definition',
message: 'invalid component definition'
},
invalid_closing_tag_unopened: (name: string) => ({
code: 'invalid-closing-tag',
message: `</${name}> attempted to close an element that was not open`
}),
invalid_closing_tag_autoclosed: (name: string, reason: string) => ({
code: 'invalid-closing-tag',
message: `</${name}> attempted to close <${name}> that was already automatically closed by <${reason}>`
}),
invalid_debug_args: {
code: 'invalid-debug-args',
message:
'{@debug ...} arguments must be identifiers, not arbitrary expressions'
},
invalid_declaration: {
code: 'invalid-declaration',
message: 'Declaration cannot be empty'
},
invalid_directive_value: {
code: 'invalid-directive-value',
message: 'Directive value must be a JavaScript expression enclosed in curly braces'
},
invalid_elseif: {
code: 'invalid-elseif',
message: '\'elseif\' should be \'else if\''
},
invalid_elseif_placement_outside_if: {
code: 'invalid-elseif-placement',
message: 'Cannot have an {:else if ...} block outside an {#if ...} block'
},
invalid_elseif_placement_unclosed_block: (block) => ({
code: 'invalid-elseif-placement',
message: `Expected to close ${block} before seeing {:else if ...} block`
}),
invalid_else_placement_outside_if: {
code: 'invalid-else-placement',
message: 'Cannot have an {:else} block outside an {#if ...} or {#each ...} block'
},
invalid_else_placement_unclosed_block: (block) => ({
code: 'invalid-else-placement',
message: `Expected to close ${block} before seeing {:else} block`
}),
invalid_element_content: (slug: string, name: string) => ({
code: `invalid-${slug}-content`,
message: `<${name}> cannot have children`
}),
invalid_element_placement: (slug: string, name: string) => ({
code: `invalid-${slug}-placement`,
message: `<${name}> tags cannot be inside elements or blocks`
}),
invalid_ref_directive: (name: string) => ({
code: 'invalid-ref-directive',
message: `The ref directive is no longer supported — use \`bind:this={${name}}\` instead`
}),
invalid_ref_selector: {
code: 'invalid-ref-selector',
message: 'ref selectors are no longer supported'
},
invalid_self_placement: {
code: 'invalid-self-placement',
message: '<svelte:self> components can only exist inside {#if} blocks, {#each} blocks, or slots passed to components'
},
invalid_script_instance: {
code: 'invalid-script',
message: 'A component can only have one instance-level <script> element'
},
invalid_script_module: {
code: 'invalid-script',
message: 'A component can only have one <script context="module"> element'
},
invalid_script_context_attribute: {
code: 'invalid-script',
message: 'context attribute must be static'
},
invalid_script_context_value: {
code: 'invalid-script',
message: 'If the context attribute is supplied, its value must be "module"'
},
invalid_tag_name: {
code: 'invalid-tag-name',
message: 'Expected valid tag name'
},
invalid_tag_name_svelte_element: (tags: string[], match: string) => ({
code: 'invalid-tag-name',
message: `Valid <svelte:...> tag names are ${list(tags)}${
match ? ' (did you mean ' + match + '?)' : ''
}`
}),
invalid_then_placement_unclosed_block: (block) => ({
code: 'invalid-then-placement',
message: `Expected to close ${block} before seeing {:then} block`
}),
invalid_then_placement_without_await: {
code: 'invalid-then-placement',
message: 'Cannot have an {:then} block outside an {#await ...} block'
},
invalid_void_content: (name: string) => ({
code: 'invalid-void-content',
message: `<${name}> is a void element and cannot have children, or a closing tag`
}),
missing_component_definition: {
code: 'missing-component-definition',
message: '<svelte:component> must have a \'this\' attribute'
},
unclosed_script: {
code: 'unclosed-script',
message: '<script> must have a closing tag'
},
unclosed_style: {
code: 'unclosed-style',
message: '<style> must have a closing tag'
},
unclosed_comment: {
code: 'unclosed-comment',
message: 'comment was left open, expected -->'
},
unexpected_block_close: {
code: 'unexpected-block-close',
message: 'Unexpected block closing tag'
},
unexpected_eof: {
code: 'unexpected-eof',
message: 'Unexpected end of input'
},
unexpected_eof_token: (token: string) => ({
code: 'unexpected-eof',
message: `Unexpected ${token}`
}),
unexpected_token: (token: string) => ({
code: 'unexpected-token',
message: `Expected ${token}`
}),
unexpected_token_destructure: {
code: 'unexpected-token',
message: 'Expected identifier or destructure pattern'
}
};

@ -5,6 +5,7 @@ import { reserved } from '../utils/names';
import full_char_code_at from '../utils/full_char_code_at'; import full_char_code_at from '../utils/full_char_code_at';
import { TemplateNode, Ast, ParserOptions, Fragment, Style, Script } from '../interfaces'; import { TemplateNode, Ast, ParserOptions, Fragment, Style, Script } from '../interfaces';
import error from '../utils/error'; import error from '../utils/error';
import parser_errors from './errors';
type ParserState = (parser: Parser) => (ParserState | void); type ParserState = (parser: Parser) => (ParserState | void);
@ -106,17 +107,18 @@ export class Parser {
}); });
} }
eat(str: string, required?: boolean, message?: string) { eat(str: string, required?: boolean, error?: { code: string, message: string }) {
if (this.match(str)) { if (this.match(str)) {
this.index += str.length; this.index += str.length;
return true; return true;
} }
if (required) { if (required) {
this.error({ this.error(error ||
code: `unexpected-${this.index === this.template.length ? 'eof' : 'token'}`, (this.index === this.template.length
message: message || `Expected ${str}` ? parser_errors.unexpected_eof_token(str)
}); : parser_errors.unexpected_token(str))
);
} }
return false; return false;
@ -218,27 +220,18 @@ export default function parse(
// TODO we may want to allow multiple <style> tags — // TODO we may want to allow multiple <style> tags —
// one scoped, one global. for now, only allow one // one scoped, one global. for now, only allow one
if (parser.css.length > 1) { if (parser.css.length > 1) {
parser.error({ parser.error(parser_errors.duplicate_style, parser.css[1].start);
code: 'duplicate-style',
message: 'You can only have one top-level <style> tag per component'
}, parser.css[1].start);
} }
const instance_scripts = parser.js.filter(script => script.context === 'default'); const instance_scripts = parser.js.filter(script => script.context === 'default');
const module_scripts = parser.js.filter(script => script.context === 'module'); const module_scripts = parser.js.filter(script => script.context === 'module');
if (instance_scripts.length > 1) { if (instance_scripts.length > 1) {
parser.error({ parser.error(parser_errors.invalid_script_instance, instance_scripts[1].start);
code: 'invalid-script',
message: 'A component can only have one instance-level <script> element'
}, instance_scripts[1].start);
} }
if (module_scripts.length > 1) { if (module_scripts.length > 1) {
parser.error({ parser.error(parser_errors.invalid_script_module, module_scripts[1].start);
code: 'invalid-script',
message: 'A component can only have one <script context="module"> element'
}, module_scripts[1].start);
} }
return { return {

@ -9,6 +9,7 @@ import {
} from '../utils/bracket'; } from '../utils/bracket';
import { parse_expression_at } from '../acorn'; import { parse_expression_at } from '../acorn';
import { Pattern } from 'estree'; import { Pattern } from 'estree';
import parser_errors from '../errors';
export default function read_context( export default function read_context(
parser: Parser parser: Parser
@ -27,10 +28,7 @@ export default function read_context(
} }
if (!is_bracket_open(code)) { if (!is_bracket_open(code)) {
parser.error({ parser.error(parser_errors.unexpected_token_destructure);
code: 'unexpected-token',
message: 'Expected identifier or destructure pattern'
});
} }
const bracket_stack = [code]; const bracket_stack = [code];
@ -42,12 +40,11 @@ export default function read_context(
bracket_stack.push(code); bracket_stack.push(code);
} else if (is_bracket_close(code)) { } else if (is_bracket_close(code)) {
if (!is_bracket_pair(bracket_stack[bracket_stack.length - 1], code)) { if (!is_bracket_pair(bracket_stack[bracket_stack.length - 1], code)) {
parser.error({ parser.error(
code: 'unexpected-token', parser_errors.unexpected_token(
message: `Expected ${String.fromCharCode( String.fromCharCode(get_bracket_close(bracket_stack[bracket_stack.length - 1]))
get_bracket_close(bracket_stack[bracket_stack.length - 1]) )
)}` );
});
} }
bracket_stack.pop(); bracket_stack.pop();
if (bracket_stack.length === 0) { if (bracket_stack.length === 0) {

@ -2,6 +2,7 @@ import { parse_expression_at } from '../acorn';
import { Parser } from '../index'; import { Parser } from '../index';
import { Node } from 'estree'; import { Node } from 'estree';
import { whitespace } from '../../utils/patterns'; import { whitespace } from '../../utils/patterns';
import parser_errors from '../errors';
export default function read_expression(parser: Parser): Node { export default function read_expression(parser: Parser): Node {
try { try {
@ -20,10 +21,7 @@ export default function read_expression(parser: Parser): Node {
if (char === ')') { if (char === ')') {
num_parens -= 1; num_parens -= 1;
} else if (!whitespace.test(char)) { } else if (!whitespace.test(char)) {
parser.error({ parser.error(parser_errors.unexpected_token(')'), index);
code: 'unexpected-token',
message: 'Expected )'
}, index);
} }
index += 1; index += 1;

@ -2,25 +2,20 @@ import * as acorn from '../acorn';
import { Parser } from '../index'; import { Parser } from '../index';
import { Script } from '../../interfaces'; import { Script } from '../../interfaces';
import { Node, Program } from 'estree'; import { Node, Program } from 'estree';
import parser_errors from '../errors';
function get_context(parser: Parser, attributes: any[], start: number): string { function get_context(parser: Parser, attributes: any[], start: number): string {
const context = attributes.find(attribute => attribute.name === 'context'); const context = attributes.find(attribute => attribute.name === 'context');
if (!context) return 'default'; if (!context) return 'default';
if (context.value.length !== 1 || context.value[0].type !== 'Text') { if (context.value.length !== 1 || context.value[0].type !== 'Text') {
parser.error({ parser.error(parser_errors.invalid_script_context_attribute, start);
code: 'invalid-script',
message: 'context attribute must be static'
}, start);
} }
const value = context.value[0].data; const value = context.value[0].data;
if (value !== 'module') { if (value !== 'module') {
parser.error({ parser.error(parser_errors.invalid_script_context_value, context.start);
code: 'invalid-script',
message: 'If the context attribute is supplied, its value must be "module"'
}, context.start);
} }
return value; return value;
@ -28,13 +23,9 @@ function get_context(parser: Parser, attributes: any[], start: number): string {
export default function read_script(parser: Parser, start: number, attributes: Node[]): Script { export default function read_script(parser: Parser, start: number, attributes: Node[]): Script {
const script_start = parser.index; const script_start = parser.index;
const error_message = { const data = parser.read_until(/<\/script\s*>/, parser_errors.unclosed_script);
code: 'unclosed-script',
message: '<script> must have a closing tag'
};
const data = parser.read_until(/<\/script\s*>/, error_message);
if (parser.index >= parser.template.length) { if (parser.index >= parser.template.length) {
parser.error(error_message); parser.error(parser_errors.unclosed_script);
} }
const source = parser.template.slice(0, script_start).replace(/[^\n]/g, ' ') + data; const source = parser.template.slice(0, script_start).replace(/[^\n]/g, ' ') + data;

@ -3,18 +3,15 @@ import { walk } from 'estree-walker';
import { Parser } from '../index'; import { Parser } from '../index';
import { Node } from 'estree'; import { Node } from 'estree';
import { Style } from '../../interfaces'; import { Style } from '../../interfaces';
import parser_errors from '../errors';
export default function read_style(parser: Parser, start: number, attributes: Node[]): Style { export default function read_style(parser: Parser, start: number, attributes: Node[]): Style {
const content_start = parser.index; const content_start = parser.index;
const error_message = {
code: 'unclosed-style',
message: '<style> must have a closing tag'
};
const styles = parser.read_until(/<\/style\s*>/, error_message); const styles = parser.read_until(/<\/style\s*>/, parser_errors.unclosed_style);
if (parser.index >= parser.template.length) { if (parser.index >= parser.template.length) {
parser.error(error_message); parser.error(parser_errors.unclosed_style);
} }
const content_end = parser.index; const content_end = parser.index;
@ -31,10 +28,7 @@ export default function read_style(parser: Parser, start: number, attributes: No
}); });
} catch (err) { } catch (err) {
if (err.name === 'SyntaxError') { if (err.name === 'SyntaxError') {
parser.error({ parser.error(parser_errors.css_syntax_error(err.message), err.offset);
code: 'css-syntax-error',
message: err.message
}, err.offset);
} else { } else {
throw err; throw err;
} }
@ -52,26 +46,17 @@ export default function read_style(parser: Parser, start: number, attributes: No
const b = node.children[i + 1]; const b = node.children[i + 1];
if (is_ref_selector(a, b)) { if (is_ref_selector(a, b)) {
parser.error({ parser.error(parser_errors.invalid_ref_selector, a.loc.start.offset);
code: 'invalid-ref-selector',
message: 'ref selectors are no longer supported'
}, a.loc.start.offset);
} }
} }
} }
if (node.type === 'Declaration' && node.value.type === 'Value' && node.value.children.length === 0) { if (node.type === 'Declaration' && node.value.type === 'Value' && node.value.children.length === 0) {
parser.error({ parser.error(parser_errors.invalid_declaration, node.start);
code: 'invalid-declaration',
message: 'Declaration cannot be empty'
}, node.start);
} }
if (node.type === 'PseudoClassSelector' && node.name === 'global' && node.children === null) { if (node.type === 'PseudoClassSelector' && node.name === 'global' && node.children === null) {
parser.error({ parser.error(parser_errors.empty_global_selector, node.loc.start.offset);
code: 'css-syntax-error',
message: ':global() must contain a selector'
}, node.loc.start.offset);
} }
if (node.loc) { if (node.loc) {

@ -6,6 +6,7 @@ import { trim_start, trim_end } from '../../utils/trim';
import { to_string } from '../utils/node'; import { to_string } from '../utils/node';
import { Parser } from '../index'; import { Parser } from '../index';
import { TemplateNode } from '../../interfaces'; import { TemplateNode } from '../../interfaces';
import parser_errors from '../errors';
function trim_whitespace(block: TemplateNode, trim_before: boolean, trim_after: boolean) { function trim_whitespace(block: TemplateNode, trim_before: boolean, trim_after: boolean) {
if (!block.children || block.children.length === 0) return; // AwaitBlock if (!block.children || block.children.length === 0) return; // AwaitBlock
@ -66,10 +67,7 @@ export default function mustache(parser: Parser) {
} else if (block.type === 'KeyBlock') { } else if (block.type === 'KeyBlock') {
expected = 'key'; expected = 'key';
} else { } else {
parser.error({ parser.error(parser_errors.unexpected_block_close);
code: 'unexpected-block-close',
message: 'Unexpected block closing tag'
});
} }
parser.eat(expected, true); parser.eat(expected, true);
@ -98,10 +96,7 @@ export default function mustache(parser: Parser) {
parser.stack.pop(); parser.stack.pop();
} else if (parser.eat(':else')) { } else if (parser.eat(':else')) {
if (parser.eat('if')) { if (parser.eat('if')) {
parser.error({ parser.error(parser_errors.invalid_elseif);
code: 'invalid-elseif',
message: "'elseif' should be 'else if'"
});
} }
parser.allow_whitespace(); parser.allow_whitespace();
@ -110,12 +105,11 @@ export default function mustache(parser: Parser) {
if (parser.eat('if')) { if (parser.eat('if')) {
const block = parser.current(); const block = parser.current();
if (block.type !== 'IfBlock') { if (block.type !== 'IfBlock') {
parser.error({ parser.error(
code: 'invalid-elseif-placement', parser.stack.some(block => block.type === 'IfBlock')
message: parser.stack.some(block => block.type === 'IfBlock') ? parser_errors.invalid_elseif_placement_unclosed_block(to_string(block))
? `Expected to close ${to_string(block)} before seeing {:else if ...} block` : parser_errors.invalid_elseif_placement_outside_if
: 'Cannot have an {:else if ...} block outside an {#if ...} block' );
});
} }
parser.require_whitespace(); parser.require_whitespace();
@ -146,12 +140,11 @@ export default function mustache(parser: Parser) {
// :else // :else
const block = parser.current(); const block = parser.current();
if (block.type !== 'IfBlock' && block.type !== 'EachBlock') { if (block.type !== 'IfBlock' && block.type !== 'EachBlock') {
parser.error({ parser.error(
code: 'invalid-else-placement', parser.stack.some(block => block.type === 'IfBlock' || block.type === 'EachBlock')
message: parser.stack.some(block => block.type === 'IfBlock' || block.type === 'EachBlock') ? parser_errors.invalid_else_placement_unclosed_block(to_string(block))
? `Expected to close ${to_string(block)} before seeing {:else} block` : parser_errors.invalid_else_placement_outside_if
: 'Cannot have an {:else} block outside an {#if ...} or {#each ...} block' );
});
} }
parser.allow_whitespace(); parser.allow_whitespace();
@ -172,21 +165,18 @@ export default function mustache(parser: Parser) {
if (is_then) { if (is_then) {
if (block.type !== 'PendingBlock') { if (block.type !== 'PendingBlock') {
parser.error({ parser.error(
code: 'invalid-then-placement', parser.stack.some(block => block.type === 'PendingBlock')
message: parser.stack.some(block => block.type === 'PendingBlock') ? parser_errors.invalid_then_placement_unclosed_block(to_string(block))
? `Expected to close ${to_string(block)} before seeing {:then} block` : parser_errors.invalid_then_placement_without_await
: 'Cannot have an {:then} block outside an {#await ...} block' );
});
} }
} else { } else {
if (block.type !== 'ThenBlock' && block.type !== 'PendingBlock') { if (block.type !== 'ThenBlock' && block.type !== 'PendingBlock') {
parser.error({ parser.error(parser.stack.some(block => block.type === 'ThenBlock' || block.type === 'PendingBlock')
code: 'invalid-catch-placement', ? parser_errors.invalid_catch_placement_unclosed_block(to_string(block))
message: parser.stack.some(block => block.type === 'ThenBlock' || block.type === 'PendingBlock') : parser_errors.invalid_catch_placement_without_await
? `Expected to close ${to_string(block)} before seeing {:catch} block` );
: 'Cannot have an {:catch} block outside an {#await ...} block'
});
} }
} }
@ -224,10 +214,7 @@ export default function mustache(parser: Parser) {
} else if (parser.eat('key')) { } else if (parser.eat('key')) {
type = 'KeyBlock'; type = 'KeyBlock';
} else { } else {
parser.error({ parser.error(parser_errors.expected_block_type);
code: 'expected-block-type',
message: 'Expected if, each, await or key'
});
} }
parser.require_whitespace(); parser.require_whitespace();
@ -286,12 +273,7 @@ export default function mustache(parser: Parser) {
if (parser.eat(',')) { if (parser.eat(',')) {
parser.allow_whitespace(); parser.allow_whitespace();
block.index = parser.read_identifier(); block.index = parser.read_identifier();
if (!block.index) { if (!block.index) parser.error(parser_errors.expected_name);
parser.error({
code: 'expected-name',
message: 'Expected name'
});
}
parser.allow_whitespace(); parser.allow_whitespace();
} }
@ -371,10 +353,7 @@ export default function mustache(parser: Parser) {
identifiers.forEach(node => { identifiers.forEach(node => {
if (node.type !== 'Identifier') { if (node.type !== 'Identifier') {
parser.error({ parser.error(parser_errors.invalid_debug_args, node.start);
code: 'invalid-debug-args',
message: '{@debug ...} arguments must be identifiers, not arbitrary expressions'
}, node.start);
} }
}); });

@ -6,8 +6,8 @@ import { is_void } from '../../utils/names';
import { Parser } from '../index'; import { Parser } from '../index';
import { Directive, DirectiveType, TemplateNode, Text } from '../../interfaces'; import { Directive, DirectiveType, TemplateNode, Text } from '../../interfaces';
import fuzzymatch from '../../utils/fuzzymatch'; import fuzzymatch from '../../utils/fuzzymatch';
import list from '../../utils/list';
import { extract_svelte_ignore } from '../../utils/extract_svelte_ignore'; import { extract_svelte_ignore } from '../../utils/extract_svelte_ignore';
import parser_errors from '../errors';
// eslint-disable-next-line no-useless-escape // eslint-disable-next-line no-useless-escape
const valid_tag_name = /^\!?[a-zA-Z]{1,}:?[a-zA-Z0-9\-]*/; const valid_tag_name = /^\!?[a-zA-Z]{1,}:?[a-zA-Z0-9\-]*/;
@ -59,7 +59,7 @@ export default function tag(parser: Parser) {
if (parser.eat('!--')) { if (parser.eat('!--')) {
const data = parser.read_until(/-->/); const data = parser.read_until(/-->/);
parser.eat('-->', true, 'comment was left open, expected -->'); parser.eat('-->', true, parser_errors.unclosed_comment);
parser.current().children.push({ parser.current().children.push({
start, start,
@ -83,24 +83,18 @@ export default function tag(parser: Parser) {
(name === 'svelte:window' || name === 'svelte:body') && (name === 'svelte:window' || name === 'svelte:body') &&
parser.current().children.length parser.current().children.length
) { ) {
parser.error({ parser.error(
code: `invalid-${slug}-content`, parser_errors.invalid_element_content(slug, name),
message: `<${name}> cannot have children` parser.current().children[0].start
}, parser.current().children[0].start); );
} }
} else { } else {
if (name in parser.meta_tags) { if (name in parser.meta_tags) {
parser.error({ parser.error(parser_errors.duplicate_element(slug, name), start);
code: `duplicate-${slug}`,
message: `A component can only have one <${name}> tag`
}, start);
} }
if (parser.stack.length > 1) { if (parser.stack.length > 1) {
parser.error({ parser.error(parser_errors.invalid_element_placement(slug, name), start);
code: `invalid-${slug}-placement`,
message: `<${name}> tags cannot be inside elements or blocks`
}, start);
} }
parser.meta_tags[name] = true; parser.meta_tags[name] = true;
@ -127,10 +121,7 @@ export default function tag(parser: Parser) {
if (is_closing_tag) { if (is_closing_tag) {
if (is_void(name)) { if (is_void(name)) {
parser.error({ parser.error(parser_errors.invalid_void_content(name), start);
code: 'invalid-void-content',
message: `<${name}> is a void element and cannot have children, or a closing tag`
}, start);
} }
parser.eat('>', true); parser.eat('>', true);
@ -138,13 +129,10 @@ export default function tag(parser: Parser) {
// close any elements that don't have their own closing tags, e.g. <div><p></div> // close any elements that don't have their own closing tags, e.g. <div><p></div>
while (parent.name !== name) { while (parent.name !== name) {
if (parent.type !== 'Element') { if (parent.type !== 'Element') {
const message = parser.last_auto_closed_tag && parser.last_auto_closed_tag.tag === name const error = parser.last_auto_closed_tag && parser.last_auto_closed_tag.tag === name
? `</${name}> attempted to close <${name}> that was already automatically closed by <${parser.last_auto_closed_tag.reason}>` ? parser_errors.invalid_closing_tag_autoclosed(name, parser.last_auto_closed_tag.reason)
: `</${name}> attempted to close an element that was not open`; : parser_errors.invalid_closing_tag_unopened(name);
parser.error({ parser.error(error, start);
code: 'invalid-closing-tag',
message
}, start);
} }
parent.end = start; parent.end = start;
@ -182,18 +170,12 @@ export default function tag(parser: Parser) {
if (name === 'svelte:component') { if (name === 'svelte:component') {
const index = element.attributes.findIndex(attr => attr.type === 'Attribute' && attr.name === 'this'); const index = element.attributes.findIndex(attr => attr.type === 'Attribute' && attr.name === 'this');
if (!~index) { if (!~index) {
parser.error({ parser.error(parser_errors.missing_component_definition, start);
code: 'missing-component-definition',
message: "<svelte:component> must have a 'this' attribute"
}, start);
} }
const definition = element.attributes.splice(index, 1)[0]; const definition = element.attributes.splice(index, 1)[0];
if (definition.value === true || definition.value.length !== 1 || definition.value[0].type === 'Text') { if (definition.value === true || definition.value.length !== 1 || definition.value[0].type === 'Text') {
parser.error({ parser.error(parser_errors.invalid_component_definition, definition.start);
code: 'invalid-component-definition',
message: 'invalid component definition'
}, definition.start);
} }
element.expression = definition.value[0].expression; element.expression = definition.value[0].expression;
@ -258,10 +240,7 @@ function read_tag_name(parser: Parser) {
} }
if (!legal) { if (!legal) {
parser.error({ parser.error(parser_errors.invalid_self_placement, start);
code: 'invalid-self-placement',
message: '<svelte:self> components can only exist inside {#if} blocks, {#each} blocks, or slots passed to components'
}, start);
} }
return 'svelte:self'; return 'svelte:self';
@ -278,20 +257,14 @@ function read_tag_name(parser: Parser) {
if (name.startsWith('svelte:')) { if (name.startsWith('svelte:')) {
const match = fuzzymatch(name.slice(7), valid_meta_tags); const match = fuzzymatch(name.slice(7), valid_meta_tags);
let message = `Valid <svelte:...> tag names are ${list(valid_meta_tags)}`; parser.error(
if (match) message += ` (did you mean '${match}'?)`; parser_errors.invalid_tag_name_svelte_element(valid_meta_tags, match),
start
parser.error({ );
code: 'invalid-tag-name',
message
}, start);
} }
if (!valid_tag_name.test(name)) { if (!valid_tag_name.test(name)) {
parser.error({ parser.error(parser_errors.invalid_tag_name, start);
code: 'invalid-tag-name',
message: 'Expected valid tag name'
}, start);
} }
return name; return name;
@ -302,10 +275,7 @@ function read_attribute(parser: Parser, unique_names: Set<string>) {
function check_unique(name: string) { function check_unique(name: string) {
if (unique_names.has(name)) { if (unique_names.has(name)) {
parser.error({ parser.error(parser_errors.duplicate_attribute, start);
code: 'duplicate-attribute',
message: 'Attributes need to be unique'
}, start);
} }
unique_names.add(name); unique_names.add(name);
} }
@ -333,10 +303,7 @@ function read_attribute(parser: Parser, unique_names: Set<string>) {
parser.eat('}', true); parser.eat('}', true);
if (name === null) { if (name === null) {
parser.error({ parser.error(parser_errors.empty_attribute_shorthand, start);
code: 'empty-attribute-shorthand',
message: 'Attribute shorthand cannot be empty'
}, start);
} }
check_unique(name); check_unique(name);
@ -378,20 +345,14 @@ function read_attribute(parser: Parser, unique_names: Set<string>) {
value = read_attribute_value(parser); value = read_attribute_value(parser);
end = parser.index; end = parser.index;
} else if (parser.match_regex(/["']/)) { } else if (parser.match_regex(/["']/)) {
parser.error({ parser.error(parser_errors.unexpected_token('='), parser.index);
code: 'unexpected-token',
message: 'Expected ='
}, parser.index);
} }
if (type) { if (type) {
const [directive_name, ...modifiers] = name.slice(colon_index + 1).split('|'); const [directive_name, ...modifiers] = name.slice(colon_index + 1).split('|');
if (directive_name === '') { if (directive_name === '') {
parser.error({ parser.error(parser_errors.empty_directive_name(type), start + colon_index + 1);
code: 'empty-directive-name',
message: `${type} name cannot be empty`
}, start + colon_index + 1);
} }
if (type === 'Binding' && directive_name !== 'this') { if (type === 'Binding' && directive_name !== 'this') {
@ -401,18 +362,12 @@ function read_attribute(parser: Parser, unique_names: Set<string>) {
} }
if (type === 'Ref') { if (type === 'Ref') {
parser.error({ parser.error(parser_errors.invalid_ref_directive(directive_name), start);
code: 'invalid-ref-directive',
message: `The ref directive is no longer supported — use \`bind:this={${directive_name}}\` instead`
}, start);
} }
if (value[0]) { if (value[0]) {
if ((value as any[]).length > 1 || value[0].type === 'Text') { if ((value as any[]).length > 1 || value[0].type === 'Text') {
parser.error({ parser.error(parser_errors.invalid_directive_value, value[0].start);
code: 'invalid-directive-value',
message: 'Directive value must be a JavaScript expression enclosed in curly braces'
}, value[0].start);
} }
} }
@ -532,8 +487,5 @@ function read_sequence(parser: Parser, done: () => boolean): TemplateNode[] {
} }
} }
parser.error({ parser.error(parser_errors.unexpected_eof);
code: 'unexpected-eof',
message: 'Unexpected end of input'
});
} }

@ -1,5 +1,5 @@
{ {
"code": "unexpected-eof", "code": "unclosed-comment",
"message": "comment was left open, expected -->", "message": "comment was left open, expected -->",
"start": { "start": {
"line": 1, "line": 1,

@ -9,7 +9,7 @@ export default {
`, `,
ssrHtml: ` ssrHtml: `
<input> <input value="">
<p></p> <p></p>
`, `,

@ -3,11 +3,5 @@ export default {
<select> <select>
<option value="[object Object]">wheeee</option> <option value="[object Object]">wheeee</option>
</select> </select>
`,
ssrHtml: `
<select value="[object Object]">
<option value="[object Object]">wheeee</option>
</select>
` `
}; };

@ -14,16 +14,6 @@ export default {
<p>foo: 2</p> <p>foo: 2</p>
`, `,
ssrHtml: `
<select value=2>
<option value='1'>1</option>
<option value='2'>2</option>
<option value='3'>3</option>
</select>
<p>foo: 2</p>
`,
async test({ assert, component, target, window }) { async test({ assert, component, target, window }) {
const select = target.querySelector('select'); const select = target.querySelector('select');
const options = [...target.querySelectorAll('option')]; const options = [...target.querySelectorAll('option')];

@ -1,17 +1,4 @@
export default { export default {
ssrHtml: `
<select value='hullo'>
<option value='hullo'>Hullo</option>
<option value='world'>World</option>
</select>
<select value='world'>
<option value='hullo'>Hullo</option>
<option value='world'>World</option>
</select>
`,
html: ` html: `
<select> <select>
<option value='hullo'>Hullo</option> <option value='hullo'>Hullo</option>

@ -11,18 +11,6 @@ export default {
<p>selected: b</p> <p>selected: b</p>
`, `,
ssrHtml: `
<p>selected: b</p>
<select value=b>
<option value='a'>a</option>
<option value='b'>b</option>
<option value='c'>c</option>
</select>
<p>selected: b</p>
`,
props: { props: {
selected: 'b' selected: 'b'
}, },

@ -9,11 +9,6 @@ export default {
<p>selected: two</p> <p>selected: two</p>
`, `,
ssrHtml: `
<select value="two"></select>
<p>selected: two</p>
`,
test({ assert, component, target }) { test({ assert, component, target }) {
component.items = [ 'one', 'two', 'three' ]; component.items = [ 'one', 'two', 'three' ];

@ -4,16 +4,6 @@ export default {
selected: [ 'two', 'three' ] selected: [ 'two', 'three' ]
}, },
ssrHtml: `
<select multiple value="two,three">
<option value="one">one</option>
<option value="two">two</option>
<option value="three">three</option>
</select>
<p>selected: two, three</p>
`,
html: ` html: `
<select multiple> <select multiple>
<option value="one">one</option> <option value="one">one</option>

@ -11,18 +11,6 @@ export default {
<p>selected: one</p> <p>selected: one</p>
`, `,
ssrHtml: `
<p>selected: one</p>
<select value=one>
<option value='one'>one</option>
<option value='two'>two</option>
<option value='three'>three</option>
</select>
<p>selected: one</p>
`,
props: { props: {
selected: 'one' selected: 'one'
}, },

@ -1,3 +1,4 @@
export default { export default {
html: '<input type="text">' html: '<input type="text">',
ssrHtml: '<input type="text" value="">'
}; };

@ -3,6 +3,10 @@ export default {
<label>firstname <input></label> <label>firstname <input></label>
<label>lastname <input></label> <label>lastname <input></label>
`, `,
ssrHtml: `
<label>firstname <input value=""></label>
<label>lastname <input value=""></label>
`,
async test({ assert, component, target, window }) { async test({ assert, component, target, window }) {
const input = new window.Event('input'); const input = new window.Event('input');

@ -4,6 +4,11 @@ export default {
<input /> <input />
<div></div> <div></div>
`, `,
ssrHtml: `
<input value=""/>
<input value=""/>
<div></div>
`,
async test({ assert, component, target, window }) { async test({ assert, component, target, window }) {
let count = 0; let count = 0;

@ -4,6 +4,10 @@ export default {
<input> <input>
{"value":""} {"value":""}
`, `,
ssrHtml: `
<input value="">
{"value":""}
`,
async test({ assert, target, window }) { async test({ assert, target, window }) {
const input = target.querySelector('input'); const input = target.querySelector('input');

@ -5,6 +5,12 @@ export default {
<div class="foo"></div> <div class="foo"></div>
</div> </div>
`, `,
ssrHtml: `
<div>
<input value="" />
<div class="foo"></div>
</div>
`,
async test({ assert, component, target }) { async test({ assert, component, target }) {
component.value = 'foo'; component.value = 'foo';

@ -4,7 +4,7 @@ export default {
<input /> <input />
`, `,
ssrHtml: ` ssrHtml: `
<input /> <input value="" />
<input value="hello" /> <input value="hello" />
`, `,

@ -5,6 +5,12 @@ export default {
<div>simple</div> <div>simple</div>
<button>click me</button> <button>click me</button>
`, `,
ssrHtml: `
<input value="">
<div></div>
<div>simple</div>
<button>click me</button>
`,
async test({ assert, component, target, window }) { async test({ assert, component, target, window }) {
const input = target.querySelector('input'); const input = target.querySelector('input');

@ -5,6 +5,12 @@ export default {
<input> <input>
<button>click me</button> <button>click me</button>
`, `,
ssrHtml: `
<div></div>
<div>simple</div>
<input value="">
<button>click me</button>
`,
async test({ assert, component, target, window }) { async test({ assert, component, target, window }) {
const input = target.querySelector('input'); const input = target.querySelector('input');

@ -0,0 +1,5 @@
<script>
export let foo = '';
</script>
<input bind:value={foo} >

@ -0,0 +1,2 @@
<input value="0" type="number">
<input value="0" type="range">

@ -0,0 +1,6 @@
<script>
export let foo = 0;
</script>
<input type="number" bind:value={foo} >
<input type="range" bind:value={foo} >
Loading…
Cancel
Save