diff --git a/.gitignore b/.gitignore
index 7aa75b29f4..35888493fa 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,16 +1,17 @@
+.idea
.DS_Store
.nyc_output
node_modules
*.map
/src/compile/internal-exports.ts
-/compiler.js
-/index.js
-/internal.*
-/store.*
-/easing.js
-/motion.*
-/transition.js
-/animate.js
+/compiler.*js
+/index.*js
+/internal.*js
+/store.*js
+/easing.*js
+/motion.*js
+/transition.*js
+/animate.*js
/scratch/
/coverage/
/coverage.lcov/
@@ -20,6 +21,7 @@ node_modules
/test/sourcemaps/samples/*/output.css.map
/yarn-error.log
_actual*.*
+/dist
/site/cypress/screenshots/
/site/__sapper__/
diff --git a/animate.d.ts b/animate.d.ts
new file mode 100644
index 0000000000..3284bfd8c0
--- /dev/null
+++ b/animate.d.ts
@@ -0,0 +1 @@
+export * from './dist/animate';
diff --git a/compiler.d.ts b/compiler.d.ts
new file mode 100644
index 0000000000..977efefb6d
--- /dev/null
+++ b/compiler.d.ts
@@ -0,0 +1 @@
+export * from './dist/compiler';
diff --git a/easing.d.ts b/easing.d.ts
new file mode 100644
index 0000000000..c07764f4f0
--- /dev/null
+++ b/easing.d.ts
@@ -0,0 +1 @@
+export * from './dist/easing';
diff --git a/index.d.ts b/index.d.ts
new file mode 100644
index 0000000000..e4ddc9027e
--- /dev/null
+++ b/index.d.ts
@@ -0,0 +1 @@
+export * from './dist/index';
diff --git a/index.mjs b/index.mjs
deleted file mode 100644
index ee5b575171..0000000000
--- a/index.mjs
+++ /dev/null
@@ -1,10 +0,0 @@
-export {
- onMount,
- onDestroy,
- beforeUpdate,
- afterUpdate,
- setContext,
- getContext,
- tick,
- createEventDispatcher
-} from './internal';
diff --git a/internal.d.ts b/internal.d.ts
new file mode 100644
index 0000000000..be034cd88a
--- /dev/null
+++ b/internal.d.ts
@@ -0,0 +1 @@
+export * from './dist/internal';
diff --git a/motion.d.ts b/motion.d.ts
new file mode 100644
index 0000000000..2fdaa86c4e
--- /dev/null
+++ b/motion.d.ts
@@ -0,0 +1 @@
+export * from './dist/motion';
diff --git a/package-lock.json b/package-lock.json
index bb2b7d7d7e..f87b3610df 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "svelte",
- "version": "3.4.0",
+ "version": "3.4.2",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -4179,9 +4179,9 @@
"dev": true
},
"typescript": {
- "version": "3.2.4",
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.2.4.tgz",
- "integrity": "sha512-0RNDbSdEokBeEAkgNbxJ+BLwSManFy9TeXz8uW+48j/xhEXv1ePME60olyzw2XzUqUBNAYFeJadIqAgNqIACwg==",
+ "version": "3.4.5",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.4.5.tgz",
+ "integrity": "sha512-YycBxUb49UUhdNMU5aJ7z5Ej2XGmaIBL0x34vZ82fn3hGvD+bgrMrVDpatgz2f7YxUMJxMkbWxJZeAvDxVe7Vw==",
"dev": true
},
"uglify-js": {
diff --git a/package.json b/package.json
index 90ec6d27ec..7963e2178d 100644
--- a/package.json
+++ b/package.json
@@ -30,9 +30,10 @@
"prepare": "npm run build && npm run tsd",
"dev": "rollup -cw",
"pretest": "npm run build",
- "posttest": "agadoo src/internal/index.js",
+ "posttest": "agadoo internal.mjs",
"prepublishOnly": "export PUBLISH=true && npm run lint && npm test",
- "tsd": "tsc -d src/store.ts --outDir ."
+ "tsd": "tsc -p . --emitDeclarationOnly",
+ "typecheck": "tsc -p . --noEmit"
},
"repository": {
"type": "git",
@@ -84,7 +85,7 @@
"tiny-glob": "^0.2.1",
"ts-node": "^8.0.2",
"tslib": "^1.8.0",
- "typescript": "^3.0.1"
+ "typescript": "^3.4.0"
},
"nyc": {
"include": [
diff --git a/rollup.config.js b/rollup.config.js
index 0d19e59d4a..9fd49f3e8f 100644
--- a/rollup.config.js
+++ b/rollup.config.js
@@ -9,10 +9,19 @@ import pkg from './package.json';
const is_publish = !!process.env.PUBLISH;
+const tsPlugin = is_publish
+ ? typescript({
+ include: 'src/**',
+ typescript: require('typescript')
+ })
+ : sucrase({
+ transforms: ['typescript']
+ });
+
export default [
/* internal.[m]js */
{
- input: `src/internal/index.js`,
+ input: `src/internal/index.ts`,
output: [
{
file: `internal.mjs`,
@@ -26,19 +35,22 @@ export default [
}
],
external: id => id.startsWith('svelte/'),
- plugins: [{
- generateBundle(options, bundle) {
- const mod = bundle['internal.mjs'];
- if (mod) {
- fs.writeFileSync('src/compile/internal-exports.ts', `// This file is automatically generated\nexport default new Set(${JSON.stringify(mod.exports)});`);
+
+ plugins: [
+ tsPlugin,
+ {
+ generateBundle(options, bundle) {
+ const mod = bundle['internal.mjs'];
+ if (mod) {
+ fs.writeFileSync('src/compile/internal-exports.ts', `// This file is automatically generated\nexport default new Set(${JSON.stringify(mod.exports)});`);
+ }
}
- }
- }]
+ }]
},
/* compiler.js */
{
- input: 'src/index.ts',
+ input: 'src/compiler.ts',
plugins: [
replace({
__VERSION__: pkg.version
@@ -48,15 +60,7 @@ export default [
include: ['node_modules/**']
}),
json(),
- is_publish
- ? typescript({
- include: 'src/**',
- exclude: 'src/internal/**',
- typescript: require('typescript')
- })
- : sucrase({
- transforms: ['typescript']
- })
+ tsPlugin
],
output: {
file: 'compiler.js',
@@ -71,7 +75,7 @@ export default [
/* motion.mjs */
{
- input: `src/motion/index.js`,
+ input: `src/motion/index.ts`,
output: [
{
file: `motion.mjs`,
@@ -84,46 +88,30 @@ export default [
paths: id => id.startsWith('svelte/') && id.replace('svelte', '.')
}
],
+ plugins: [
+ tsPlugin
+ ],
external: id => id.startsWith('svelte/')
},
- /* store.mjs */
- {
- input: `src/store.ts`,
+ // everything else
+ ...['index', 'easing', 'transition', 'animate', 'store'].map(name => ({
+ input: `src/${name}.ts`,
output: [
{
- file: `store.mjs`,
+ file: `${name}.mjs`,
format: 'esm',
paths: id => id.startsWith('svelte/') && id.replace('svelte', '.')
},
{
- file: `store.js`,
+ file: `${name}.js`,
format: 'cjs',
paths: id => id.startsWith('svelte/') && id.replace('svelte', '.')
}
],
plugins: [
- is_publish
- ? typescript({
- include: 'src/**',
- exclude: 'src/internal/**',
- typescript: require('typescript')
- })
- : sucrase({
- transforms: ['typescript']
- })
+ tsPlugin
],
external: id => id.startsWith('svelte/')
- },
-
- // everything else
- ...['index', 'easing', 'transition', 'animate'].map(name => ({
- input: `${name}.mjs`,
- output: {
- file: `${name}.js`,
- format: 'cjs',
- paths: id => id.startsWith('svelte/') && id.replace('svelte', '.')
- },
- external: id => id !== `${name}.mjs`
}))
];
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 1f39fe6642..a0d6ef7f3e 100644
--- a/site/content/examples/19-7guis/05-7guis-crud/App.svelte
+++ b/site/content/examples/19-7guis/05-7guis-crud/App.svelte
@@ -30,10 +30,7 @@
$: selected = filteredPeople[i];
- $: {
- first = selected ? selected.first : '';
- last = selected ? selected.last : '';
- }
+ $: reset_inputs(selected);
function create() {
people = people.concat({ first, last });
@@ -53,7 +50,8 @@
}
function reset_inputs(person) {
- ({ first, last } = person);
+ first = person ? person.first : '';
+ last = person ? person.last : '';
}
diff --git a/site/content/tutorial/10-transitions/03-in-and-out/text.md b/site/content/tutorial/10-transitions/03-in-and-out/text.md
index 21cb221342..1f1ac2c80b 100644
--- a/site/content/tutorial/10-transitions/03-in-and-out/text.md
+++ b/site/content/tutorial/10-transitions/03-in-and-out/text.md
@@ -2,7 +2,13 @@
title: In and out
---
-Instead of the `transition` directive, an element can have an `in` or an `out` directive, or both together:
+Instead of the `transition` directive, an element can have an `in` or an `out` directive, or both together. Import `fade` alongside `fly`...
+
+```js
+import { fade, fly } from 'svelte/transition';
+```
+
+...then replace the `transition` directive with separate `in` and `out` directives:
```html
diff --git a/animate.mjs b/src/animate.ts
similarity index 86%
rename from animate.mjs
rename to src/animate.ts
index f22fabe401..cf64cd060a 100644
--- a/animate.mjs
+++ b/src/animate.ts
@@ -1,5 +1,5 @@
-import { cubicOut } from './easing';
-import { is_function } from './internal';
+import { cubicOut } from 'svelte/easing';
+import { is_function } from 'svelte/internal';
export function flip(node, animation, params) {
const style = getComputedStyle(node);
@@ -22,4 +22,4 @@ export function flip(node, animation, params) {
easing,
css: (t, u) => `transform: ${transform} translate(${u * dx}px, ${u * dy}px);`
};
-}
\ No newline at end of file
+}
diff --git a/src/compile/Component.ts b/src/compile/Component.ts
index a429db41f6..a8145e6b2c 100644
--- a/src/compile/Component.ts
+++ b/src/compile/Component.ts
@@ -1,4 +1,5 @@
import MagicString, { Bundle } from 'magic-string';
+// @ts-ignore
import { walk, childKeys } from 'estree-walker';
import { getLocator } from 'locate-character';
import Stats from '../Stats';
@@ -21,6 +22,7 @@ import { remove_indentation, add_indentation } from '../utils/indentation';
import get_object from './utils/get_object';
import unwrap_parens from './utils/unwrap_parens';
import Slot from './nodes/Slot';
+import { Node as ESTreeNode } from 'estree';
type ComponentOptions = {
namespace?: string;
@@ -758,7 +760,7 @@ export default class Component {
});
}
- if (is_reference(node, parent)) {
+ if (is_reference(node as ESTreeNode, parent as ESTreeNode)) {
const object = get_object(node);
const { name } = object;
@@ -776,7 +778,7 @@ export default class Component {
});
}
- invalidate(name, value) {
+ invalidate(name, value?) {
const variable = this.var_lookup.get(name);
if (variable && (variable.subscribable && variable.reassigned)) {
@@ -1022,7 +1024,7 @@ export default class Component {
scope = map.get(node);
}
- if (is_reference(node, parent)) {
+ if (is_reference(node as ESTreeNode, parent as ESTreeNode)) {
const { name } = flatten_reference(node);
const owner = scope.find_owner(name);
@@ -1113,7 +1115,7 @@ export default class Component {
} else if (node.type === 'UpdateExpression') {
const identifier = get_object(node.argument);
assignees.add(identifier.name);
- } else if (is_reference(node, parent)) {
+ } else if (is_reference(node as ESTreeNode, parent as ESTreeNode)) {
const identifier = get_object(node);
if (!assignee_nodes.has(identifier)) {
const { name } = identifier;
diff --git a/src/compile/index.ts b/src/compile/index.ts
index e80a937932..dac75f23e0 100644
--- a/src/compile/index.ts
+++ b/src/compile/index.ts
@@ -1,4 +1,4 @@
-import { assign } from '../internal';
+import { assign } from '../internal/index';
import Stats from '../Stats';
import parse from '../parse/index';
import render_dom from './render-dom/index';
@@ -55,7 +55,7 @@ function validate_options(options: CompileOptions, warnings: Warning[]) {
}
}
-function get_name(filename) {
+function get_name(filename: string) {
if (!filename) return null;
const parts = filename.split(/[\/\\]/);
@@ -105,4 +105,4 @@ export default function compile(source: string, options: CompileOptions = {}) {
: render_dom(component, options);
return component.generate(js);
-}
\ No newline at end of file
+}
diff --git a/src/compile/nodes/Attribute.ts b/src/compile/nodes/Attribute.ts
index c07960ce47..0b2d3a3700 100644
--- a/src/compile/nodes/Attribute.ts
+++ b/src/compile/nodes/Attribute.ts
@@ -67,6 +67,7 @@ export default class Attribute extends Node {
this.should_cache = this.is_dynamic
? this.chunks.length === 1
+ // @ts-ignore todo: probably error
? this.chunks[0].node.type !== 'Identifier' || scope.names.has(this.chunks[0].node.name)
: true
: false;
@@ -91,8 +92,10 @@ export default class Attribute extends Node {
if (this.chunks.length === 0) return `""`;
if (this.chunks.length === 1) {
+
return this.chunks[0].type === 'Text'
- ? stringify(this.chunks[0].data)
+ ? stringify((this.chunks[0] as Text).data)
+ // @ts-ignore todo: probably error
: this.chunks[0].render(block);
}
@@ -102,6 +105,7 @@ export default class Attribute extends Node {
if (chunk.type === 'Text') {
return stringify(chunk.data);
} else {
+ // @ts-ignore todo: probably error
return chunk.get_precedence() <= 13 ? `(${chunk.render()})` : chunk.render();
}
})
@@ -114,7 +118,8 @@ export default class Attribute extends Node {
return this.is_true
? true
: this.chunks[0]
- ? this.chunks[0].data
+ // method should be called only when `is_static = true`
+ ? (this.chunks[0] as Text).data
: '';
}
}
diff --git a/src/compile/nodes/AwaitBlock.ts b/src/compile/nodes/AwaitBlock.ts
index f8e6896b5d..cd57750d29 100644
--- a/src/compile/nodes/AwaitBlock.ts
+++ b/src/compile/nodes/AwaitBlock.ts
@@ -5,6 +5,7 @@ import CatchBlock from './CatchBlock';
import Expression from './shared/Expression';
export default class AwaitBlock extends Node {
+ type: 'AwaitBlock';
expression: Expression;
value: string;
error: string;
diff --git a/src/compile/nodes/Binding.ts b/src/compile/nodes/Binding.ts
index b03eba0c36..0d666a543f 100644
--- a/src/compile/nodes/Binding.ts
+++ b/src/compile/nodes/Binding.ts
@@ -5,6 +5,7 @@ import Component from '../Component';
import TemplateScope from './shared/TemplateScope';
export default class Binding extends Node {
+ type: 'Binding';
name: string;
expression: Expression;
is_contextual: boolean;
diff --git a/src/compile/nodes/CatchBlock.ts b/src/compile/nodes/CatchBlock.ts
index 23c08a494c..0edc0f76d8 100644
--- a/src/compile/nodes/CatchBlock.ts
+++ b/src/compile/nodes/CatchBlock.ts
@@ -3,6 +3,7 @@ import TemplateScope from './shared/TemplateScope';
import AbstractBlock from './shared/AbstractBlock';
export default class CatchBlock extends AbstractBlock {
+ type: 'CatchBlock';
scope: TemplateScope;
constructor(component, parent, scope, info) {
diff --git a/src/compile/nodes/DebugTag.ts b/src/compile/nodes/DebugTag.ts
index 4d2c3f6ae4..0fbfa592ad 100644
--- a/src/compile/nodes/DebugTag.ts
+++ b/src/compile/nodes/DebugTag.ts
@@ -2,6 +2,7 @@ import Node from './shared/Node';
import Expression from './shared/Expression';
export default class DebugTag extends Node {
+ type: 'DebugTag';
expressions: Expression[];
constructor(component, parent, scope, info) {
@@ -11,4 +12,4 @@ export default class DebugTag extends Node {
return new Expression(component, parent, scope, node);
});
}
-}
\ No newline at end of file
+}
diff --git a/src/compile/nodes/EachBlock.ts b/src/compile/nodes/EachBlock.ts
index b58c023ac9..2f18373137 100644
--- a/src/compile/nodes/EachBlock.ts
+++ b/src/compile/nodes/EachBlock.ts
@@ -6,8 +6,15 @@ import TemplateScope from './shared/TemplateScope';
import AbstractBlock from './shared/AbstractBlock';
import { Node as INode } from '../../interfaces';
import { new_tail } from '../utils/tail';
+import Element from './Element';
-function unpack_destructuring(contexts: Array<{ name: string, tail: string }>, node: INode, tail: string) {
+type Context = {
+ key: INode,
+ name?: string,
+ tail: string
+};
+
+function unpack_destructuring(contexts: Array, node: INode, tail: string) {
if (!node) return;
if (node.type === 'Identifier' || node.type === 'RestIdentifier') {
@@ -53,7 +60,7 @@ export default class EachBlock extends AbstractBlock {
context: string;
key: Expression;
scope: TemplateScope;
- contexts: Array<{ name: string, tail: string }>;
+ contexts: Array;
has_animation: boolean;
has_binding = false;
@@ -82,7 +89,7 @@ export default class EachBlock extends AbstractBlock {
if (this.index) {
// index can only change if this is a keyed each block
- const dependencies = this.key ? this.expression.dependencies : [];
+ const dependencies = this.key ? this.expression.dependencies : new Set([]);
this.scope.add(this.index, dependencies, this);
}
@@ -92,8 +99,8 @@ export default class EachBlock extends AbstractBlock {
if (this.has_animation) {
if (this.children.length !== 1) {
- const child = this.children.find(child => !!child.animation);
- component.error(child.animation, {
+ const child = this.children.find(child => !!(child as Element).animation);
+ component.error((child as Element).animation, {
code: `invalid-animation`,
message: `An element that use the animate directive must be the sole child of a keyed each block`
});
diff --git a/src/compile/nodes/Element.ts b/src/compile/nodes/Element.ts
index ac2b81b3e7..1b2d82188c 100644
--- a/src/compile/nodes/Element.ts
+++ b/src/compile/nodes/Element.ts
@@ -15,6 +15,7 @@ import fuzzymatch from '../../utils/fuzzymatch';
import list from '../../utils/list';
import Let from './Let';
import TemplateScope from './shared/TemplateScope';
+import { INode } from './interfaces';
const svg = /^(?:altGlyph|altGlyphDef|altGlyphItem|animate|animateColor|animateMotion|animateTransform|circle|clipPath|color-profile|cursor|defs|desc|discard|ellipse|feBlend|feColorMatrix|feComponentTransfer|feComposite|feConvolveMatrix|feDiffuseLighting|feDisplacementMap|feDistantLight|feDropShadow|feFlood|feFuncA|feFuncB|feFuncG|feFuncR|feGaussianBlur|feImage|feMerge|feMergeNode|feMorphology|feOffset|fePointLight|feSpecularLighting|feSpotLight|feTile|feTurbulence|filter|font|font-face|font-face-format|font-face-name|font-face-src|font-face-uri|foreignObject|g|glyph|glyphRef|hatch|hatchpath|hkern|image|line|linearGradient|marker|mask|mesh|meshgradient|meshpatch|meshrow|metadata|missing-glyph|mpath|path|pattern|polygon|polyline|radialGradient|rect|set|solidcolor|stop|svg|switch|symbol|text|textPath|tref|tspan|unknown|use|view|vkern)$/;
@@ -101,7 +102,7 @@ export default class Element extends Node {
intro?: Transition = null;
outro?: Transition = null;
animation?: Animation = null;
- children: Node[];
+ children: INode[];
namespace: string;
constructor(component, parent, scope, info: any) {
@@ -136,7 +137,7 @@ export default class Element extends Node {
// Special case — treat these the same way:
//
//
- const value_attribute = info.attributes.find((attribute: Node) => attribute.name === 'value');
+ const value_attribute = info.attributes.find(attribute => attribute.name === 'value');
if (!value_attribute) {
info.attributes.push({
@@ -228,7 +229,7 @@ export default class Element extends Node {
let is_figure_parent = false;
while (parent) {
- if (parent.name === 'figure') {
+ if ((parent as Element).name === 'figure') {
is_figure_parent = true;
break;
}
@@ -253,7 +254,7 @@ export default class Element extends Node {
return true;
});
- const index = children.findIndex(child => child.name === 'figcaption');
+ const index = children.findIndex(child => (child as Element).name === 'figcaption');
if (index !== -1 && (index !== 0 && index !== children.length - 1)) {
this.component.warn(children[index], {
@@ -320,7 +321,9 @@ export default class Element extends Node {
}
const value = attribute.get_static_value();
+ // @ts-ignore
if (value && !aria_role_set.has(value)) {
+ // @ts-ignore
const match = fuzzymatch(value, aria_roles);
let message = `A11y: Unknown role '${value}'`;
if (match) message += ` (did you mean '${match}'?)`;
@@ -359,6 +362,7 @@ export default class Element extends Node {
// tabindex-no-positive
if (name === 'tabindex') {
const value = attribute.get_static_value();
+ // @ts-ignore todo is tabindex=true correct case?
if (!isNaN(value) && +value > 0) {
component.warn(attribute, {
code: `a11y-positive-tabindex`,
@@ -544,7 +548,7 @@ export default class Element extends Node {
message: `'group' binding can only be used with or `
});
}
- } else if (name == 'files') {
+ } else if (name === 'files') {
if (this.name !== 'input') {
component.error(binding, {
code: `invalid-binding`,
@@ -560,6 +564,14 @@ export default class Element extends Node {
message: `'files' binding can only be used with `
});
}
+
+ } else if (name === 'open') {
+ if (this.name !== 'details') {
+ component.error(binding, {
+ code: `invalid-binding`,
+ message: `'${name}' binding can only be used with `
+ });
+ }
} else if (
name === 'currentTime' ||
name === 'duration' ||
diff --git a/src/compile/nodes/ElseBlock.ts b/src/compile/nodes/ElseBlock.ts
index 61c1aa5455..5f3aa29529 100644
--- a/src/compile/nodes/ElseBlock.ts
+++ b/src/compile/nodes/ElseBlock.ts
@@ -1,10 +1,11 @@
import map_children from './shared/map_children';
import AbstractBlock from './shared/AbstractBlock';
+import Component from '../Component';
export default class ElseBlock extends AbstractBlock {
type: 'ElseBlock';
- constructor(component, parent, scope, info) {
+ constructor(component: Component, parent, scope, info) {
super(component, parent, scope, info);
this.children = map_children(component, this, scope, info.children);
diff --git a/src/compile/nodes/EventHandler.ts b/src/compile/nodes/EventHandler.ts
index f5e7e0e898..dab60858d5 100644
--- a/src/compile/nodes/EventHandler.ts
+++ b/src/compile/nodes/EventHandler.ts
@@ -5,6 +5,7 @@ import deindent from '../utils/deindent';
import Block from '../render-dom/Block';
export default class EventHandler extends Node {
+ type: 'EventHandler';
name: string;
modifiers: Set;
expression: Expression;
@@ -65,4 +66,4 @@ export default class EventHandler extends Node {
// this.component.add_reference(this.handler_name);
return `ctx.${this.handler_name}`;
}
-}
\ No newline at end of file
+}
diff --git a/src/compile/nodes/Fragment.ts b/src/compile/nodes/Fragment.ts
index ec25d41a1c..6025b036a6 100644
--- a/src/compile/nodes/Fragment.ts
+++ b/src/compile/nodes/Fragment.ts
@@ -3,10 +3,12 @@ import Component from '../Component';
import map_children from './shared/map_children';
import Block from '../render-dom/Block';
import TemplateScope from './shared/TemplateScope';
+import { INode } from './interfaces';
export default class Fragment extends Node {
+ type: 'Fragment';
block: Block;
- children: Node[];
+ children: INode[];
scope: TemplateScope;
constructor(component: Component, info: any) {
@@ -16,4 +18,4 @@ export default class Fragment extends Node {
this.scope = scope;
this.children = map_children(component, this, scope, info.children);
}
-}
\ No newline at end of file
+}
diff --git a/src/compile/nodes/Head.ts b/src/compile/nodes/Head.ts
index bc6e9bde40..2c08dcd595 100644
--- a/src/compile/nodes/Head.ts
+++ b/src/compile/nodes/Head.ts
@@ -1,5 +1,4 @@
import Node from './shared/Node';
-import Block from '../render-dom/Block';
import map_children from './shared/map_children';
export default class Head extends Node {
diff --git a/src/compile/nodes/InlineComponent.ts b/src/compile/nodes/InlineComponent.ts
index 3359e981ed..8b6cd77282 100644
--- a/src/compile/nodes/InlineComponent.ts
+++ b/src/compile/nodes/InlineComponent.ts
@@ -7,6 +7,7 @@ import Expression from './shared/Expression';
import Component from '../Component';
import Let from './Let';
import TemplateScope from './shared/TemplateScope';
+import { INode } from './interfaces';
export default class InlineComponent extends Node {
type: 'InlineComponent';
@@ -16,7 +17,7 @@ export default class InlineComponent extends Node {
bindings: Binding[] = [];
handlers: EventHandler[] = [];
lets: Let[] = [];
- children: Node[];
+ children: INode[];
scope: TemplateScope;
constructor(component: Component, parent, scope, info) {
diff --git a/src/compile/nodes/MustacheTag.ts b/src/compile/nodes/MustacheTag.ts
index e668987a9c..ac6688d503 100644
--- a/src/compile/nodes/MustacheTag.ts
+++ b/src/compile/nodes/MustacheTag.ts
@@ -1,3 +1,5 @@
import Tag from './shared/Tag';
-export default class MustacheTag extends Tag {}
\ No newline at end of file
+export default class MustacheTag extends Tag {
+ type: 'MustacheTag';
+}
diff --git a/src/compile/nodes/PendingBlock.ts b/src/compile/nodes/PendingBlock.ts
index 0fd71c0221..5ff7352558 100644
--- a/src/compile/nodes/PendingBlock.ts
+++ b/src/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';
constructor(component, parent, scope, info) {
super(component, parent, scope, info);
this.children = map_children(component, parent, scope, info.children);
diff --git a/src/compile/nodes/RawMustacheTag.ts b/src/compile/nodes/RawMustacheTag.ts
index ada3123410..fc63885942 100644
--- a/src/compile/nodes/RawMustacheTag.ts
+++ b/src/compile/nodes/RawMustacheTag.ts
@@ -1,3 +1,5 @@
import Tag from './shared/Tag';
-export default class RawMustacheTag extends Tag {}
\ No newline at end of file
+export default class RawMustacheTag extends Tag {
+ type: 'RawMustacheTag'
+}
diff --git a/src/compile/nodes/Slot.ts b/src/compile/nodes/Slot.ts
index dbb502b41a..a03fe8c026 100644
--- a/src/compile/nodes/Slot.ts
+++ b/src/compile/nodes/Slot.ts
@@ -1,17 +1,17 @@
-import Node from './shared/Node';
import Element from './Element';
import Attribute from './Attribute';
import Component from '../Component';
import TemplateScope from './shared/TemplateScope';
+import { INode } from './interfaces';
export default class Slot extends Element {
type: 'Element';
name: string;
- children: Node[];
+ children: INode[];
slot_name: string;
values: Map = new Map();
- constructor(component: Component, parent: Node, scope: TemplateScope, info: any) {
+ constructor(component: Component, parent: INode, scope: TemplateScope, info: any) {
super(component, parent, scope, info);
info.attributes.forEach(attr => {
@@ -68,4 +68,4 @@ export default class Slot extends Element {
component.slots.set(this.slot_name, this);
}
-}
\ No newline at end of file
+}
diff --git a/src/compile/nodes/Text.ts b/src/compile/nodes/Text.ts
index 1c31c9d83d..7500f5ff30 100644
--- a/src/compile/nodes/Text.ts
+++ b/src/compile/nodes/Text.ts
@@ -1,13 +1,14 @@
import Node from './shared/Node';
import Component from '../Component';
import TemplateScope from './shared/TemplateScope';
+import { INode } from './interfaces';
export default class Text extends Node {
type: 'Text';
data: string;
use_space = false;
- constructor(component: Component, parent: Node, scope: TemplateScope, info: any) {
+ constructor(component: Component, parent: INode, scope: TemplateScope, info: any) {
super(component, parent, scope, info);
this.data = info.data;
@@ -23,4 +24,4 @@ export default class Text extends Node {
this.use_space = true;
}
}
-}
\ No newline at end of file
+}
diff --git a/src/compile/nodes/ThenBlock.ts b/src/compile/nodes/ThenBlock.ts
index 7e4ed0e5da..7f9bbde0f0 100644
--- a/src/compile/nodes/ThenBlock.ts
+++ b/src/compile/nodes/ThenBlock.ts
@@ -3,6 +3,7 @@ import TemplateScope from './shared/TemplateScope';
import AbstractBlock from './shared/AbstractBlock';
export default class ThenBlock extends AbstractBlock {
+ type: 'ThenBlock';
scope: TemplateScope;
constructor(component, parent, scope, info) {
diff --git a/src/compile/nodes/Title.ts b/src/compile/nodes/Title.ts
index fd58d3043d..6ac0848053 100644
--- a/src/compile/nodes/Title.ts
+++ b/src/compile/nodes/Title.ts
@@ -1,12 +1,13 @@
import Node from './shared/Node';
-import map_children from './shared/map_children';
+import map_children, { Children } from './shared/map_children';
+import Component from '../Component';
export default class Title extends Node {
type: 'Title';
- children: any[]; // TODO
+ children: Children;
should_cache: boolean;
- constructor(component, parent, scope, info) {
+ constructor(component: Component, parent, scope, info) {
super(component, parent, scope, info);
this.children = map_children(component, parent, scope, info.children);
@@ -33,4 +34,4 @@ export default class Title extends Node {
)
: true;
}
-}
\ No newline at end of file
+}
diff --git a/src/compile/nodes/interfaces.ts b/src/compile/nodes/interfaces.ts
new file mode 100644
index 0000000000..434b09e5aa
--- /dev/null
+++ b/src/compile/nodes/interfaces.ts
@@ -0,0 +1,64 @@
+import Tag from './shared/Tag';
+
+import Action from './Action';
+import Animation from './Animation';
+import Attribute from './Attribute';
+import AwaitBlock from './AwaitBlock';
+import Binding from './Binding';
+import Body from './Body';
+import CatchBlock from './CatchBlock';
+import Class from './Class';
+import Comment from './Comment';
+import DebugTag from './DebugTag';
+import EachBlock from './EachBlock';
+import Element from './Element';
+import ElseBlock from './ElseBlock';
+import EventHandler from './EventHandler';
+import Fragment from './Fragment';
+import Head from './Head';
+import IfBlock from './IfBlock';
+import InlineComponent from './InlineComponent';
+import Let from './Let';
+import MustacheTag from './MustacheTag';
+import Options from './Options';
+import PendingBlock from './PendingBlock';
+import RawMustacheTag from './RawMustacheTag';
+import Slot from './Slot';
+import Text from './Text';
+import ThenBlock from './ThenBlock';
+import Title from './Title';
+import Transition from './Transition';
+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;
diff --git a/src/compile/nodes/shared/AbstractBlock.ts b/src/compile/nodes/shared/AbstractBlock.ts
index 1dfebd51f0..e1104e4928 100644
--- a/src/compile/nodes/shared/AbstractBlock.ts
+++ b/src/compile/nodes/shared/AbstractBlock.ts
@@ -1,10 +1,11 @@
import Block from '../../render-dom/Block';
import Component from './../../Component';
import Node from './Node';
+import { INode } from '../interfaces';
export default class AbstractBlock extends Node {
block: Block;
- children: Node[];
+ children: INode[];
constructor(component: Component, parent, scope, info: any) {
super(component, parent, scope, info);
diff --git a/src/compile/nodes/shared/Expression.ts b/src/compile/nodes/shared/Expression.ts
index fc188e9673..e7c63dfec2 100644
--- a/src/compile/nodes/shared/Expression.ts
+++ b/src/compile/nodes/shared/Expression.ts
@@ -12,6 +12,7 @@ import TemplateScope from './TemplateScope';
import get_object from '../../utils/get_object';
import { nodes_match } from '../../../utils/nodes_match';
import Block from '../../render-dom/Block';
+import { INode } from '../interfaces';
const binary_operators: Record = {
'**': 15,
@@ -61,10 +62,12 @@ const precedence: Record number> = {
SequenceExpression: () => 0
};
+type Owner = Wrapper | INode;
+
export default class Expression {
- type = 'Expression';
+ type: 'Expression' = 'Expression';
component: Component;
- owner: Wrapper;
+ owner: Owner;
node: any;
snippet: string;
references: Set;
@@ -81,7 +84,8 @@ export default class Expression {
rendered: string;
- constructor(component: Component, owner: Wrapper, template_scope: TemplateScope, info) {
+ // todo: owner type
+ constructor(component: Component, owner: Owner, template_scope: TemplateScope, info) {
// TODO revert to direct property access in prod?
Object.defineProperties(this, {
component: {
@@ -92,6 +96,7 @@ export default class Expression {
this.node = info;
this.template_scope = template_scope;
this.owner = owner;
+ // @ts-ignore
this.is_synthetic = owner.is_synthetic;
const { dependencies, contextual_dependencies } = this;
@@ -218,7 +223,7 @@ export default class Expression {
}
// TODO move this into a render-dom wrapper?
- render(block: Block) {
+ render(block?: Block) {
if (this.rendered) return this.rendered;
const {
@@ -510,4 +515,4 @@ function is_contextual(component: Component, scope: TemplateScope, name: string)
// assume contextual
return true;
-}
\ No newline at end of file
+}
diff --git a/src/compile/nodes/shared/Node.ts b/src/compile/nodes/shared/Node.ts
index b6eaf9965d..b647e3a158 100644
--- a/src/compile/nodes/shared/Node.ts
+++ b/src/compile/nodes/shared/Node.ts
@@ -1,15 +1,17 @@
import Attribute from './../Attribute';
import Component from './../../Component';
+import { INode } from '../interfaces';
+import Text from '../Text';
export default class Node {
readonly start: number;
readonly end: number;
readonly component: Component;
- readonly parent: Node;
+ readonly parent: INode;
readonly type: string;
- prev?: Node;
- next?: Node;
+ prev?: INode;
+ next?: INode;
can_use_innerhtml: boolean;
var: string;
@@ -55,7 +57,7 @@ export default class Node {
if (attribute.chunks.length === 0) return '';
if (attribute.chunks.length === 1 && attribute.chunks[0].type === 'Text') {
- return attribute.chunks[0].data;
+ return (attribute.chunks[0] as Text).data;
}
return null;
diff --git a/src/compile/nodes/shared/Tag.ts b/src/compile/nodes/shared/Tag.ts
index 94971bef11..bc826458d9 100644
--- a/src/compile/nodes/shared/Tag.ts
+++ b/src/compile/nodes/shared/Tag.ts
@@ -2,6 +2,7 @@ import Node from './Node';
import Expression from './Expression';
export default class Tag extends Node {
+ type: 'MustacheTag' | 'RawMustacheTag';
expression: Expression;
should_cache: boolean;
@@ -14,4 +15,4 @@ export default class Tag extends Node {
(this.expression.dependencies.size && scope.names.has(info.expression.name))
);
}
-}
\ No newline at end of file
+}
diff --git a/src/compile/nodes/shared/TemplateScope.ts b/src/compile/nodes/shared/TemplateScope.ts
index abd366642e..5f30d0c883 100644
--- a/src/compile/nodes/shared/TemplateScope.ts
+++ b/src/compile/nodes/shared/TemplateScope.ts
@@ -2,6 +2,7 @@ import EachBlock from '../EachBlock';
import ThenBlock from '../ThenBlock';
import CatchBlock from '../CatchBlock';
import InlineComponent from '../InlineComponent';
+import Element from '../Element';
type NodeWithScope = EachBlock | ThenBlock | CatchBlock | InlineComponent | Element;
@@ -41,4 +42,4 @@ export default class TemplateScope {
const owner = this.get_owner(name);
return owner && (owner.type === 'Element' || owner.type === 'InlineComponent');
}
-}
\ No newline at end of file
+}
diff --git a/src/compile/nodes/shared/map_children.ts b/src/compile/nodes/shared/map_children.ts
index b903853016..71d764a889 100644
--- a/src/compile/nodes/shared/map_children.ts
+++ b/src/compile/nodes/shared/map_children.ts
@@ -14,9 +14,11 @@ import Slot from '../Slot';
import Text from '../Text';
import Title from '../Title';
import Window from '../Window';
-import Node from './Node';
+import { Node } from '../../../interfaces';
-function get_constructor(type): typeof Node {
+export type Children = ReturnType;
+
+function get_constructor(type) {
switch (type) {
case 'AwaitBlock': return AwaitBlock;
case 'Body': return Body;
@@ -38,7 +40,7 @@ function get_constructor(type): typeof Node {
}
}
-export default function map_children(component, parent, scope, children: any[]) {
+export default function map_children(component, parent, scope, children: Node[]) {
let last = null;
return children.map(child => {
const constructor = get_constructor(child.type);
diff --git a/src/compile/render-dom/Block.ts b/src/compile/render-dom/Block.ts
index e40b3ceb55..531826edcb 100644
--- a/src/compile/render-dom/Block.ts
+++ b/src/compile/render-dom/Block.ts
@@ -9,7 +9,7 @@ export interface BlockOptions {
renderer?: Renderer;
comment?: string;
key?: string;
- bindings?: Map { object: string, property: string, snippet: string }>;
+ bindings?: Map;
dependencies?: Set;
}
diff --git a/src/compile/render-dom/Renderer.ts b/src/compile/render-dom/Renderer.ts
index 1d766c6345..ea07c1544f 100644
--- a/src/compile/render-dom/Renderer.ts
+++ b/src/compile/render-dom/Renderer.ts
@@ -3,7 +3,6 @@ import { CompileOptions } from '../../interfaces';
import Component from '../Component';
import FragmentWrapper from './wrappers/Fragment';
import CodeBuilder from '../utils/CodeBuilder';
-import SlotWrapper from './wrappers/Slot';
export default class Renderer {
component: Component; // TODO Maybe Renderer shouldn't know about Component?
@@ -18,6 +17,7 @@ export default class Renderer {
fragment: FragmentWrapper;
file_var: string;
+ locate: (c: number) => { line: number; column: number; };
constructor(component: Component, options: CompileOptions) {
this.component = component;
@@ -58,4 +58,4 @@ export default class Renderer {
this.fragment.render(this.block, null, 'nodes');
}
-}
\ No newline at end of file
+}
diff --git a/src/compile/render-dom/index.ts b/src/compile/render-dom/index.ts
index 0fd0d4b172..1432813e9d 100644
--- a/src/compile/render-dom/index.ts
+++ b/src/compile/render-dom/index.ts
@@ -134,7 +134,6 @@ export default function dom(
});
if (component.compile_options.dev) {
- // TODO check no uunexpected props were passed, as well as
// checking that expected ones were passed
const expected = props.filter(prop => !prop.initialised);
@@ -395,6 +394,16 @@ export default function dom(
return $name;
});
+ let unknown_props_check;
+ if (component.compile_options.dev && writable_props.length) {
+ unknown_props_check = deindent`
+ const writable_props = [${writable_props.map(prop => `'${prop.export_name}'`).join(', ')}];
+ Object.keys($$props).forEach(key => {
+ if (!writable_props.includes(key)) console.warn(\`<${component.tag}> was created with unknown prop '\${key}'\`);
+ });
+ `;
+ }
+
builder.add_block(deindent`
function ${definition}(${args.join(', ')}) {
${reactive_store_declarations.length > 0 && `let ${reactive_store_declarations.join(', ')};`}
@@ -405,6 +414,8 @@ export default function dom(
${component.javascript}
+ ${unknown_props_check}
+
${component.slots.size && `let { $$slots = {}, $$scope } = $$props;`}
${renderer.binding_groups.length > 0 && `const $$binding_groups = [${renderer.binding_groups.map(_ => `[]`).join(', ')}];`}
diff --git a/src/compile/render-dom/wrappers/EachBlock.ts b/src/compile/render-dom/wrappers/EachBlock.ts
index fe5d5746e5..9208c838ad 100644
--- a/src/compile/render-dom/wrappers/EachBlock.ts
+++ b/src/compile/render-dom/wrappers/EachBlock.ts
@@ -8,7 +8,7 @@ import deindent from '../../utils/deindent';
import ElseBlock from '../../nodes/ElseBlock';
import { attach_head } from '../../utils/tail';
-class ElseBlockWrapper extends Wrapper {
+export class ElseBlockWrapper extends Wrapper {
node: ElseBlock;
block: Block;
fragment: FragmentWrapper;
@@ -83,6 +83,7 @@ export default class EachBlockWrapper extends Wrapper {
this.block = block.child({
comment: create_debugging_comment(this.node, this.renderer.component),
name: renderer.component.get_unique_name('create_each_block'),
+ // @ts-ignore todo: probably error
key: node.key as string,
bindings: new Map(block.bindings)
@@ -310,7 +311,9 @@ export default class EachBlockWrapper extends Wrapper {
}
block.builders.init.add_block(deindent`
- const ${get_key} = ctx => ${this.node.key.render()};
+ const ${get_key} = ctx => ${
+ // @ts-ignore todo: probably error
+ this.node.key.render()};
for (var #i = 0; #i < ${this.vars.each_block_value}.${length}; #i += 1) {
let child_ctx = ${this.vars.get_each_context}(ctx, ${this.vars.each_block_value}, #i);
diff --git a/src/compile/render-dom/wrappers/Element/Attribute.ts b/src/compile/render-dom/wrappers/Element/Attribute.ts
index 5007724f34..876496e2f6 100644
--- a/src/compile/render-dom/wrappers/Element/Attribute.ts
+++ b/src/compile/render-dom/wrappers/Element/Attribute.ts
@@ -4,6 +4,7 @@ import fix_attribute_casing from './fix_attribute_casing';
import ElementWrapper from './index';
import { stringify } from '../../../utils/stringify';
import deindent from '../../../utils/deindent';
+import Expression from '../../../nodes/shared/Expression';
export default class AttributeWrapper {
node: Attribute;
@@ -21,7 +22,9 @@ export default class AttributeWrapper {
// special case —
\n"
}
]
@@ -43,8 +45,5 @@
"children": []
}
]
- },
- "css": null,
- "instance": null,
- "module": null
+ }
}
\ No newline at end of file
diff --git a/test/parser/samples/transition-intro-no-params/output.json b/test/parser/samples/transition-intro-no-params/output.json
index edb15457e6..91b50f3ec8 100644
--- a/test/parser/samples/transition-intro-no-params/output.json
+++ b/test/parser/samples/transition-intro-no-params/output.json
@@ -26,13 +26,11 @@
"start": 13,
"end": 21,
"type": "Text",
+ "raw": "fades in",
"data": "fades in"
}
]
}
]
- },
- "css": null,
- "instance": null,
- "module": null
+ }
}
\ No newline at end of file
diff --git a/test/parser/samples/transition-intro/output.json b/test/parser/samples/transition-intro/output.json
index 5583dd89bc..418bb97e16 100644
--- a/test/parser/samples/transition-intro/output.json
+++ b/test/parser/samples/transition-intro/output.json
@@ -54,13 +54,11 @@
"start": 31,
"end": 39,
"type": "Text",
+ "raw": "fades in",
"data": "fades in"
}
]
}
]
- },
- "css": null,
- "instance": null,
- "module": null
+ }
}
\ No newline at end of file
diff --git a/test/parser/samples/unusual-identifier/output.json b/test/parser/samples/unusual-identifier/output.json
index c0d4ecc3ff..e4a2a18619 100644
--- a/test/parser/samples/unusual-identifier/output.json
+++ b/test/parser/samples/unusual-identifier/output.json
@@ -44,8 +44,5 @@
}
}
]
- },
- "css": null,
- "instance": null,
- "module": null
+ }
}
\ No newline at end of file
diff --git a/test/parser/samples/whitespace-leading-trailing/output.json b/test/parser/samples/whitespace-leading-trailing/output.json
index f164af01ba..e4f387856e 100644
--- a/test/parser/samples/whitespace-leading-trailing/output.json
+++ b/test/parser/samples/whitespace-leading-trailing/output.json
@@ -8,6 +8,7 @@
"start": 0,
"end": 6,
"type": "Text",
+ "raw": "\n\n\t\t\t\t",
"data": "\n\n\t\t\t\t"
},
{
@@ -21,13 +22,11 @@
"start": 9,
"end": 32,
"type": "Text",
+ "raw": "just chillin' over here",
"data": "just chillin' over here"
}
]
}
]
- },
- "css": null,
- "instance": null,
- "module": null
+ }
}
\ No newline at end of file
diff --git a/test/parser/samples/whitespace-normal/output.json b/test/parser/samples/whitespace-normal/output.json
index e4ce956331..acbae7ae17 100644
--- a/test/parser/samples/whitespace-normal/output.json
+++ b/test/parser/samples/whitespace-normal/output.json
@@ -15,6 +15,7 @@
"start": 4,
"end": 10,
"type": "Text",
+ "raw": "Hello ",
"data": "Hello "
},
{
@@ -39,6 +40,7 @@
"start": 24,
"end": 26,
"type": "Text",
+ "raw": "! ",
"data": "! "
}
]
@@ -54,6 +56,7 @@
"start": 41,
"end": 53,
"type": "Text",
+ "raw": "How are you?",
"data": "How are you?"
}
]
@@ -61,8 +64,5 @@
]
}
]
- },
- "css": null,
- "instance": null,
- "module": null
+ }
}
\ No newline at end of file
diff --git a/test/parser/samples/yield/output.json b/test/parser/samples/yield/output.json
index 16ea79d8e8..b2e4b9430f 100644
--- a/test/parser/samples/yield/output.json
+++ b/test/parser/samples/yield/output.json
@@ -16,8 +16,5 @@
}
}
]
- },
- "css": null,
- "instance": null,
- "module": null
+ }
}
\ No newline at end of file
diff --git a/test/runtime/index.js b/test/runtime/index.js
index db02ce13d4..fd5ffdef04 100644
--- a/test/runtime/index.js
+++ b/test/runtime/index.js
@@ -3,7 +3,7 @@ import * as path from "path";
import * as fs from "fs";
import { rollup } from 'rollup';
import * as virtual from 'rollup-plugin-virtual';
-import { clear_loops, set_now } from "../../internal.js";
+import { clear_loops, set_now, set_raf } from "../../internal.js";
import {
showOutput,
@@ -101,7 +101,7 @@ describe("runtime", () => {
}
};
set_now(() => raf.time);
- global.requestAnimationFrame = cb => {
+ set_raf(cb => {
let called = false;
raf.callback = () => {
if (!called) {
@@ -109,7 +109,7 @@ describe("runtime", () => {
cb();
}
};
- };
+ });
try {
mod = require(`./samples/${dir}/main.svelte`);
diff --git a/test/runtime/samples/binding-details-open/_config.js b/test/runtime/samples/binding-details-open/_config.js
new file mode 100644
index 0000000000..cf2459c3f1
--- /dev/null
+++ b/test/runtime/samples/binding-details-open/_config.js
@@ -0,0 +1,25 @@
+export default {
+ html: `
+ toggle
+ `,
+
+ async test({ assert, component, target, window }) {
+ const details = target.querySelector('details');
+ const event = new window.Event('toggle');
+
+ details.open = true;
+ await details.dispatchEvent(event);
+ assert.equal(component.visible, true);
+ assert.htmlEqual(target.innerHTML, `
+ toggle
+ hello!
+ `);
+
+ details.open = false;
+ await details.dispatchEvent(event);
+ assert.equal(component.visible, false);
+ assert.htmlEqual(target.innerHTML, `
+ toggle
+ `);
+ }
+};
diff --git a/test/runtime/samples/binding-details-open/main.svelte b/test/runtime/samples/binding-details-open/main.svelte
new file mode 100644
index 0000000000..3a7a08e121
--- /dev/null
+++ b/test/runtime/samples/binding-details-open/main.svelte
@@ -0,0 +1,9 @@
+
+
+toggle
+
+{#if visible}
+ hello!
+{/if}
diff --git a/test/runtime/samples/dev-warning-unknown-props/Foo.svelte b/test/runtime/samples/dev-warning-unknown-props/Foo.svelte
new file mode 100644
index 0000000000..cebe5fd571
--- /dev/null
+++ b/test/runtime/samples/dev-warning-unknown-props/Foo.svelte
@@ -0,0 +1,5 @@
+
+
+{foo}
diff --git a/test/runtime/samples/dev-warning-unknown-props/_config.js b/test/runtime/samples/dev-warning-unknown-props/_config.js
new file mode 100644
index 0000000000..9bff4a2a74
--- /dev/null
+++ b/test/runtime/samples/dev-warning-unknown-props/_config.js
@@ -0,0 +1,9 @@
+export default {
+ compileOptions: {
+ dev: true
+ },
+
+ warnings: [
+ ` was created with unknown prop 'fo'`
+ ]
+};
diff --git a/test/runtime/samples/dev-warning-unknown-props/main.svelte b/test/runtime/samples/dev-warning-unknown-props/main.svelte
new file mode 100644
index 0000000000..1566cf3e41
--- /dev/null
+++ b/test/runtime/samples/dev-warning-unknown-props/main.svelte
@@ -0,0 +1,5 @@
+
+
+
diff --git a/transition.d.ts b/transition.d.ts
new file mode 100644
index 0000000000..54d5f036da
--- /dev/null
+++ b/transition.d.ts
@@ -0,0 +1 @@
+export * from './dist/transition';
diff --git a/tsconfig.json b/tsconfig.json
index fdb7367e05..994bc61b85 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,18 +1,35 @@
{
- "compilerOptions": {
- "target": "ES6",
- "diagnostics": true,
- "noImplicitThis": true,
- "noEmitOnError": true,
- "allowJs": true,
- "lib": ["es5", "es6", "dom"],
- "importHelpers": true,
- "moduleResolution": "node"
- },
- "include": [
- "src"
- ],
- "exclude": [
- "node_modules"
- ]
+ "compilerOptions": {
+ "target": "es2015",
+ "module": "es6",
+ "declarationDir": "./dist",
+ "outDir": "./dist",
+ "declaration": true,
+ "noImplicitThis": true,
+ "noEmitOnError": true,
+ "lib": [
+ "es5",
+ "es6",
+ "dom",
+ "es2015"
+ ],
+ "importHelpers": true,
+ "moduleResolution": "node",
+ "baseUrl": ".",
+ "paths": {
+ "svelte/internal": ["./src/internal"],
+ "svelte/easing": ["./src/easing"],
+ "svelte/motion": ["./src/motion"],
+ "svelte/store": ["./src/store"]
+ },
+ "typeRoots": [
+ "node_modules/@types"
+ ]
+ },
+ "include": [
+ "src/**/*"
+ ],
+ "exclude": [
+ "dist"
+ ]
}