diff --git a/.flowconfig b/.flowconfig deleted file mode 100644 index c1961b7a6b7b..000000000000 --- a/.flowconfig +++ /dev/null @@ -1,9 +0,0 @@ -[ignore] -/types/.* - -[include] - -[libs] - -[options] -strip_root=true diff --git a/.gitignore b/.gitignore index 4d7bbc7ac366..923dd5901ede 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/compiler.d.ts b/compiler.d.ts deleted file mode 100644 index e2a3820bc51b..000000000000 --- a/compiler.d.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './types/compiler'; diff --git a/package-lock.json b/package-lock.json index f65fcc07e5ba..aea08689b16a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -49,9 +49,9 @@ "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": { diff --git a/package.json b/package.json index 7106e60d696a..37bd6f75e79c 100644 --- a/package.json +++ b/package.json @@ -21,10 +21,10 @@ "engines": { "node": ">= 8" }, - "types": "types/runtime", + "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", @@ -35,10 +35,8 @@ "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": { @@ -59,7 +57,7 @@ "homepage": "https://github.com/sveltejs/svelte#README", "devDependencies": { "@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", diff --git a/rollup.config.js b/rollup.config.js index 8907ae4e6c69..fb329534a2bf 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 e69e3f5e20b5..000000000000 --- 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', - 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/content/docs/02-template-syntax.md b/site/content/docs/02-template-syntax.md index aad7e3fc1986..a6e17f8bc26e 100644 --- a/site/content/docs/02-template-syntax.md +++ b/site/content/docs/02-template-syntax.md @@ -101,27 +101,7 @@ Text can also contain JavaScript expressions: ``` -### HTML expressions - -```sv -{@html expression} -``` - ---- - -In a text expression, characters like `<` and `>` are escaped. With HTML expressions, they're not. - -> Svelte does not sanitize expressions before injecting HTML. If the data comes from an untrusted source, you must sanitize it, or you are exposing your users to an XSS vulnerability. - -```html -
-

{post.title}

- {@html post.content} -
-``` - - -### If blocks +### {#if ...} ```sv {#if expression}...{/if} @@ -158,7 +138,7 @@ Additional conditions can be added with `{:else if expression}`, optionally endi ``` -### Each blocks +### {#each ...} ```sv {#each expression as name}...{/each} @@ -229,7 +209,7 @@ An each block can also have an `{:else}` clause, which is rendered if the list i ``` -### Await blocks +### {#await ...} ```sv {#await expression}...{:then name}...{:catch name}...{/await} @@ -283,7 +263,80 @@ If you don't care about the pending state, you can also omit the initial block. ``` -### DOM events +### {@html ...} + +```sv +{@html expression} +``` + +--- + +In a text expression, characters like `<` and `>` are escaped. With HTML expressions, they're not. + +> Svelte does not sanitize expressions before injecting HTML. If the data comes from an untrusted source, you must sanitize it, or you are exposing your users to an XSS vulnerability. + +```html +
+

{post.title}

+ {@html post.content} +
+``` + + +### {@debug ...} + +```sv +{@debug} +``` +```sv +{@debug var1, var2, ..., varN} +``` + +--- + +The `{@debug ...}` tag offers an alternative to `console.log(...)`. It logs the values of specific variables whenever they change, and pauses code execution if you have devtools open. + +It accepts a comma-separated list of variable names (not arbitrary expressions). + +```html + + +{@debug user} + +

Hello {user.firstname}!

+``` + +--- + +`{@debug ...}` accepts a comma-separated list of variable names (not arbitrary expressions). + +```html + +{@debug user} +{@debug user1, user2, user3} + + +{@debug user.firstname} +{@debug myArray[0]} +{@debug !isReady} +{@debug typeof user === 'object'} +``` + +The `{@debug}` tag without any arguments will insert a `debugger` statement that gets triggered when *any* state changes, as opposed to the specified variables. + + + +### Element directives + +As well as attributes, elements can have *directives*, which control the element's behaviour in some way. + + +#### [on:*eventname*](on_component_event) ```sv on:eventname={handler} @@ -324,6 +377,13 @@ Handlers can be declared inline with no performance penalty. As with attributes, Add *modifiers* to DOM events with the `|` character. +```html +
+ +
+``` + The following modifiers are available: * `preventDefault` — calls `event.preventDefault()` before running the handler @@ -334,13 +394,6 @@ The following modifiers are available: Modifiers can be chained together, e.g. `on:click|once|capture={...}`. -```html -
- -
-``` - --- If the `on:` directive is used without a value, the component will *forward* the event, meaning that a consumer of the component can listen for it. @@ -370,39 +423,11 @@ It's possible to have multiple event listeners for the same event: ``` -### Component events - -```sv -on:eventname={handler} -``` - ---- - -Components can emit events using [createEventDispatcher](docs#createEventDispatcher), or by forwarding DOM events. Listening for component events looks the same as listening for DOM events: - -```html - -``` - ---- - -As with DOM events, if the `on:` directive is used without a value, the component will *forward* the event, meaning that a consumer of the component can listen for it. - -```html - -``` - -### Element bindings +#### [bind:*property*](bind_element_property) ```sv bind:property={variable} ``` -```sv -bind:group={variable} -``` -```sv -bind:this={dom_node} -``` --- @@ -436,31 +461,8 @@ Numeric input values are coerced; even though `input.value` is a string as far a ``` -#### Binding related elements ---- - -Inputs that work together can use `bind:group`. - -```html - - - - - - - - - - - - -``` - -#### Binding `` value --- @@ -500,7 +502,7 @@ When the value of an `