From 7a7804be49d23b705f9429c36e62c6c20d2e68ed Mon Sep 17 00:00:00 2001 From: pngwn Date: Fri, 26 Apr 2019 22:20:33 +0100 Subject: [PATCH 01/87] Document animations. #2532 --- site/content/docs/02-template-syntax.md | 133 +++++++++++++++++++++++- 1 file changed, 132 insertions(+), 1 deletion(-) diff --git a/site/content/docs/02-template-syntax.md b/site/content/docs/02-template-syntax.md index 917673a7b0..a69400f8e3 100644 --- a/site/content/docs/02-template-syntax.md +++ b/site/content/docs/02-template-syntax.md @@ -895,7 +895,138 @@ Local transitions only play when the block they belong to is created or destroye ### Animations -TODO i can't remember how any of this works +```sv +animate:name +``` + +```sv +animate:name={params} +``` + +```js +animation = (node: HTMLElement, { from: DOMRect, to: DOMRect } , params: any) => { + delay?: number, + duration?: number, + easing?: (t: number) => number, + css?: (t: number, u: number) => string, + tick?: (t: number, u: number) => void +} +``` + +```js +DOMRect { + bottom: number, + height: number, + ​​left: number, + right: number, + ​top: number, + width: number, + x: number, + y:number +} +``` + +--- + +An animation is triggered when the contents of a [keyed each block](docs#Each_blocks) are re-ordered. Animations do not run when an element is removed, only when the each block's data is reordered. Animate directives must be on an element that is an *immediate* child of a keyed each block. + +Animations can be used with Svelte's [built-in animation functions](docs#svelte_animate) or [custom animation functions](docs#Custom_animation_functions). + +```html + +{#each list as item, index (item)} +
  • {item}
  • +{/each} +``` + +#### Animation Parameters + +--- + +As with actions and transitions, animations can have parameters. + +(The double `{{curlies}}` aren't a special syntax; this is an object literal inside an expression tag.) + +```html +{#each list as item, index (item)} +
  • {item}
  • +{/each} +``` + +#### Custom animation functions + +--- + +Animations can use custom functions that provide the `node`, an `animation` object and any `paramaters` as arguments. The `animation` parameter is an object containing `from` and `to` properties each containing a [DOMRect](https://developer.mozilla.org/en-US/docs/Web/API/DOMRect#Properties) describing the geometry of the element in its `start` and `end` positions. The `from` property is the DOMRect of the element in its starting position, the `to` property is the DOMRect of the element in its final position after the list has been reordered and the DOM updated. + +If the returned object has a `css` method, Svelte will create a CSS animation that plays on the element. + +The `t` argument passed to `css` is a value that goes from `0` and `1` after the `easing` function has been applied. The `u` argument is equal to `1 - t`. + +The function is called repeatedly *before* the animation begins, with different `t` and `u` arguments. + + +```html + + +{#each list as item, index (item)} +
    {item}
    +{/each} +``` + +--- + + +A custom animation function can also return a `tick` function, which is called *during* the animation with the same `t` and `u` arguments. + +> If it's possible to use `css` instead of `tick`, do so — CSS animations can run off the main thread, preventing jank on slower devices. + +```html + + +{#each list as item, index (item)} +
    {item}
    +{/each} +``` + ### Slots From 342389863e6856515fa002fc9d8c0b5cfe23faa9 Mon Sep 17 00:00:00 2001 From: Benjamin Milde Date: Sun, 5 May 2019 19:33:00 +0200 Subject: [PATCH 02/87] Allow multiple event listeners on a single node --- src/parse/state/tag.ts | 25 ++--- .../input.svelte | 1 + .../output.json | 96 +++++++++++++++++++ 3 files changed, 110 insertions(+), 12 deletions(-) create mode 100644 test/parser/samples/non-unique-attribute-event-handler/input.svelte create mode 100644 test/parser/samples/non-unique-attribute-event-handler/output.json diff --git a/src/parse/state/tag.ts b/src/parse/state/tag.ts index 3747d2d482..f02eed037c 100644 --- a/src/parse/state/tag.ts +++ b/src/parse/state/tag.ts @@ -131,8 +131,8 @@ export default function tag(parser: Parser) { const type = meta_tags.has(name) ? meta_tags.get(name) : (/[A-Z]/.test(name[0]) || name === 'svelte:self' || name === 'svelte:component') ? 'InlineComponent' - : name === 'title' && parent_is_head(parser.stack) ? 'Title' - : name === 'slot' && !parser.customElement ? 'Slot' : 'Element'; + : name === 'title' && parent_is_head(parser.stack) ? 'Title' + : name === 'slot' && !parser.customElement ? 'Slot' : 'Element'; const element: Node = { start, @@ -360,14 +360,6 @@ function read_attribute(parser: Parser, unique_names: Set) { let name = parser.read_until(/(\s|=|\/|>)/); if (!name) return null; - if (unique_names.has(name)) { - parser.error({ - code: `duplicate-attribute`, - message: 'Attributes need to be unique' - }, start); - } - - unique_names.add(name); let end = parser.index; @@ -376,6 +368,15 @@ function read_attribute(parser: Parser, unique_names: Set) { const colon_index = name.indexOf(':'); const type = colon_index !== -1 && get_directive_type(name.slice(0, colon_index)); + if (unique_names.has(name) && type != "EventHandler") { + parser.error({ + code: `duplicate-attribute`, + message: 'Attributes need to be unique' + }, start); + } + + unique_names.add(name); + let value: any[] | true = true; if (parser.eat('=')) { value = read_attribute_value(parser); @@ -453,8 +454,8 @@ function read_attribute_value(parser: Parser) { const regex = ( quote_mark === `'` ? /'/ : - quote_mark === `"` ? /"/ : - /(\/>|[\s"'=<>`])/ + quote_mark === `"` ? /"/ : + /(\/>|[\s"'=<>`])/ ); const value = read_sequence(parser, () => !!parser.match_regex(regex)); diff --git a/test/parser/samples/non-unique-attribute-event-handler/input.svelte b/test/parser/samples/non-unique-attribute-event-handler/input.svelte new file mode 100644 index 0000000000..b13403f77d --- /dev/null +++ b/test/parser/samples/non-unique-attribute-event-handler/input.svelte @@ -0,0 +1 @@ + diff --git a/test/parser/samples/non-unique-attribute-event-handler/output.json b/test/parser/samples/non-unique-attribute-event-handler/output.json new file mode 100644 index 0000000000..9579fe5b4c --- /dev/null +++ b/test/parser/samples/non-unique-attribute-event-handler/output.json @@ -0,0 +1,96 @@ +{ + "html": { + "start": 0, + "end": 87, + "type": "Fragment", + "children": [ + { + "start": 0, + "end": 87, + "type": "Element", + "name": "button", + "attributes": [ + { + "start": 8, + "end": 45, + "type": "EventHandler", + "name": "click", + "modifiers": [], + "expression": { + "type": "ArrowFunctionExpression", + "start": 19, + "end": 43, + "id": null, + "expression": true, + "generator": false, + "async": false, + "params": [], + "body": { + "type": "AssignmentExpression", + "start": 25, + "end": 43, + "operator": "=", + "left": { + "type": "Identifier", + "start": 25, + "end": 32, + "name": "visible" + }, + "right": { + "type": "UnaryExpression", + "start": 35, + "end": 43, + "operator": "!", + "prefix": true, + "argument": { + "type": "Identifier", + "start": 36, + "end": 43, + "name": "visible" + } + } + } + } + }, + { + "start": 46, + "end": 77, + "type": "EventHandler", + "name": "click", + "modifiers": [], + "expression": { + "type": "ArrowFunctionExpression", + "start": 57, + "end": 75, + "id": null, + "expression": true, + "generator": false, + "async": false, + "params": [], + "body": { + "type": "AssignmentExpression", + "start": 63, + "end": 75, + "operator": "=", + "left": { + "type": "Identifier", + "start": 63, + "end": 67, + "name": "ajax" + }, + "right": { + "type": "Literal", + "start": 70, + "end": 75, + "value": false, + "raw": "false" + } + } + } + } + ], + "children": [] + } + ] + } +} From fdc51de0906cfa45b2ec37b429a5a8696dd1d1bb Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Thu, 9 May 2019 21:18:13 -0400 Subject: [PATCH 03/87] allow derivers to return cleanup functions - fixes #2553 --- store.mjs | 4 ++++ test/store/index.js | 31 +++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/store.mjs b/store.mjs index bc9bc46ed1..624ede3dde 100644 --- a/store.mjs +++ b/store.mjs @@ -51,11 +51,14 @@ export function derived(stores, fn, initial_value) { const values = []; let pending = 0; + let cleanup = noop; const sync = () => { if (pending) return; + cleanup(); const result = fn(single ? values[0] : values, set); if (auto) set(result); + else cleanup = result || noop; }; const unsubscribers = stores.map((store, i) => store.subscribe( @@ -74,6 +77,7 @@ export function derived(stores, fn, initial_value) { return function stop() { run_all(unsubscribers); + cleanup(); }; }); } diff --git a/test/store/index.js b/test/store/index.js index 44617d6d00..5f9176cffb 100644 --- a/test/store/index.js +++ b/test/store/index.js @@ -211,6 +211,37 @@ describe('store', () => { unsubscribe(); }); + + it('calls a cleanup function', () => { + const num = writable(1); + + const values = []; + const cleaned_up = []; + + const d = derived(num, ($num, set) => { + set($num * 2); + + return function cleanup() { + cleaned_up.push($num); + }; + }); + + num.set(2); + + const unsubscribe = d.subscribe(value => { + values.push(value); + }); + + num.set(3); + num.set(4); + + assert.deepEqual(values, [4, 6, 8]); + assert.deepEqual(cleaned_up, [2, 3]); + + unsubscribe(); + + assert.deepEqual(cleaned_up, [2, 3, 4]); + }); }); describe('get', () => { From 9eec0fcd983ac14f525db42413dcd582c2fac98a Mon Sep 17 00:00:00 2001 From: Benjamin Milde Date: Sat, 11 May 2019 17:42:36 +0200 Subject: [PATCH 04/87] Implement suggestions --- src/parse/state/tag.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/parse/state/tag.ts b/src/parse/state/tag.ts index f02eed037c..365085ca08 100644 --- a/src/parse/state/tag.ts +++ b/src/parse/state/tag.ts @@ -368,14 +368,16 @@ function read_attribute(parser: Parser, unique_names: Set) { const colon_index = name.indexOf(':'); const type = colon_index !== -1 && get_directive_type(name.slice(0, colon_index)); - if (unique_names.has(name) && type != "EventHandler") { + if (unique_names.has(name)) { parser.error({ code: `duplicate-attribute`, message: 'Attributes need to be unique' }, start); } - unique_names.add(name); + if (type !== "EventHandler") { + unique_names.add(name); + } let value: any[] | true = true; if (parser.eat('=')) { From abe486e7e38d5ed103af603bfd5348f7db355948 Mon Sep 17 00:00:00 2001 From: Benjamin Milde Date: Sat, 11 May 2019 17:42:59 +0200 Subject: [PATCH 05/87] Switch test to runtime test --- .../input.svelte | 1 - .../output.json | 96 ------------------- .../samples/event-handler-multiple/_config.js | 14 +++ .../event-handler-multiple/main.svelte | 6 ++ 4 files changed, 20 insertions(+), 97 deletions(-) delete mode 100644 test/parser/samples/non-unique-attribute-event-handler/input.svelte delete mode 100644 test/parser/samples/non-unique-attribute-event-handler/output.json create mode 100644 test/runtime/samples/event-handler-multiple/_config.js create mode 100644 test/runtime/samples/event-handler-multiple/main.svelte diff --git a/test/parser/samples/non-unique-attribute-event-handler/input.svelte b/test/parser/samples/non-unique-attribute-event-handler/input.svelte deleted file mode 100644 index b13403f77d..0000000000 --- a/test/parser/samples/non-unique-attribute-event-handler/input.svelte +++ /dev/null @@ -1 +0,0 @@ - diff --git a/test/parser/samples/non-unique-attribute-event-handler/output.json b/test/parser/samples/non-unique-attribute-event-handler/output.json deleted file mode 100644 index 9579fe5b4c..0000000000 --- a/test/parser/samples/non-unique-attribute-event-handler/output.json +++ /dev/null @@ -1,96 +0,0 @@ -{ - "html": { - "start": 0, - "end": 87, - "type": "Fragment", - "children": [ - { - "start": 0, - "end": 87, - "type": "Element", - "name": "button", - "attributes": [ - { - "start": 8, - "end": 45, - "type": "EventHandler", - "name": "click", - "modifiers": [], - "expression": { - "type": "ArrowFunctionExpression", - "start": 19, - "end": 43, - "id": null, - "expression": true, - "generator": false, - "async": false, - "params": [], - "body": { - "type": "AssignmentExpression", - "start": 25, - "end": 43, - "operator": "=", - "left": { - "type": "Identifier", - "start": 25, - "end": 32, - "name": "visible" - }, - "right": { - "type": "UnaryExpression", - "start": 35, - "end": 43, - "operator": "!", - "prefix": true, - "argument": { - "type": "Identifier", - "start": 36, - "end": 43, - "name": "visible" - } - } - } - } - }, - { - "start": 46, - "end": 77, - "type": "EventHandler", - "name": "click", - "modifiers": [], - "expression": { - "type": "ArrowFunctionExpression", - "start": 57, - "end": 75, - "id": null, - "expression": true, - "generator": false, - "async": false, - "params": [], - "body": { - "type": "AssignmentExpression", - "start": 63, - "end": 75, - "operator": "=", - "left": { - "type": "Identifier", - "start": 63, - "end": 67, - "name": "ajax" - }, - "right": { - "type": "Literal", - "start": 70, - "end": 75, - "value": false, - "raw": "false" - } - } - } - } - ], - "children": [] - } - ] - } -} diff --git a/test/runtime/samples/event-handler-multiple/_config.js b/test/runtime/samples/event-handler-multiple/_config.js new file mode 100644 index 0000000000..cf17c61f60 --- /dev/null +++ b/test/runtime/samples/event-handler-multiple/_config.js @@ -0,0 +1,14 @@ +export default { + html: ` + + `, + + async test({ assert, component, target, window }) { + const button = target.querySelector('button'); + const event = new window.MouseEvent('click'); + + await button.dispatchEvent(event); + assert.equal(component.clickHandlerOne, 1); + assert.equal(component.clickHandlerTwo, 1); + } +}; diff --git a/test/runtime/samples/event-handler-multiple/main.svelte b/test/runtime/samples/event-handler-multiple/main.svelte new file mode 100644 index 0000000000..f327a7fd2a --- /dev/null +++ b/test/runtime/samples/event-handler-multiple/main.svelte @@ -0,0 +1,6 @@ + + + From 5e8383cf37601523a1c930ac354de0af4e752f7e Mon Sep 17 00:00:00 2001 From: "Daniel J. Wilson" Date: Sat, 11 May 2019 23:42:32 -0400 Subject: [PATCH 06/87] Replace tag with attribute for alt Being an attribute, alt should be mentioned as such. --- .../tutorial/01-introduction/03-dynamic-attributes/text.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site/content/tutorial/01-introduction/03-dynamic-attributes/text.md b/site/content/tutorial/01-introduction/03-dynamic-attributes/text.md index 6deaad5837..1fd6774b8a 100644 --- a/site/content/tutorial/01-introduction/03-dynamic-attributes/text.md +++ b/site/content/tutorial/01-introduction/03-dynamic-attributes/text.md @@ -16,7 +16,7 @@ That's better. But Svelte is giving us a warning: When building web apps, it's important to make sure that they're *accessible* to the broadest possible userbase, including people with (for example) impaired vision or motion, or people without powerful hardware or good internet connections. Accessibility (shortened to a11y) isn't always easy to get right, but Svelte will help by warning you if you write inaccessible markup. -In this case, we're missing the `alt` tag that describes the image for people using screenreaders, or people with slow or flaky internet connections that can't download the image. Let's add one: +In this case, we're missing the `alt` attribute that describes the image for people using screenreaders, or people with slow or flaky internet connections that can't download the image. Let's add one: ```html A man dancing From 66a4c1a9bccbdbbfad986d14f6efab801d807681 Mon Sep 17 00:00:00 2001 From: "Daniel J. Wilson" Date: Sun, 12 May 2019 00:19:53 -0400 Subject: [PATCH 07/87] Pluralize elements --- site/content/tutorial/06-bindings/01-text-inputs/text.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/site/content/tutorial/06-bindings/01-text-inputs/text.md b/site/content/tutorial/06-bindings/01-text-inputs/text.md index 0082586133..cb11b3b58a 100644 --- a/site/content/tutorial/06-bindings/01-text-inputs/text.md +++ b/site/content/tutorial/06-bindings/01-text-inputs/text.md @@ -4,7 +4,7 @@ title: Text inputs As a general rule, data flow in Svelte is *top down* — a parent component can set props on a child component, and a component can set attributes on an element, but not the other way around. -Sometimes it's useful to break that rule. Take the case of the `` element in this component — we *could* add an `on:input` event handler that set the value of `name` to `event.target.value`, but it's a bit... boilerplatey. It gets even worse with other kinds of form element, as we'll see. +Sometimes it's useful to break that rule. Take the case of the `` element in this component — we *could* add an `on:input` event handler that set the value of `name` to `event.target.value`, but it's a bit... boilerplatey. It gets even worse with other kinds of form elements, as we'll see. Instead, we can use the `bind:value` directive: @@ -12,4 +12,4 @@ Instead, we can use the `bind:value` directive: ``` -This means that not only will changes to the value of `name` update the input value, but changes to the input value will update `name`. \ No newline at end of file +This means that not only will changes to the value of `name` update the input value, but changes to the input value will update `name`. From 1b4446030b8641a2859b507522f3016f579cea20 Mon Sep 17 00:00:00 2001 From: pngwn Date: Sun, 12 May 2019 10:13:52 +0100 Subject: [PATCH 08/87] Update animate example to use animate directive and built-in crossfade function. --- .../10-animations/00-animate/App.svelte | 7 +- .../10-animations/00-animate/crossfade.js | 65 ------------------- 2 files changed, 5 insertions(+), 67 deletions(-) delete mode 100644 site/content/examples/10-animations/00-animate/crossfade.js diff --git a/site/content/examples/10-animations/00-animate/App.svelte b/site/content/examples/10-animations/00-animate/App.svelte index c46096c204..3b9da92a27 100644 --- a/site/content/examples/10-animations/00-animate/App.svelte +++ b/site/content/examples/10-animations/00-animate/App.svelte @@ -1,8 +1,9 @@ + +

    foo {foo}

    \ No newline at end of file diff --git a/test/runtime/samples/component-namespaced/_config.js b/test/runtime/samples/component-namespaced/_config.js new file mode 100644 index 0000000000..e5f4c680da --- /dev/null +++ b/test/runtime/samples/component-namespaced/_config.js @@ -0,0 +1,16 @@ +export default { + props: { + a: 1 + }, + + html: ` +

    foo 1

    + `, + + test({ assert, component, target }) { + component.a = 2; + assert.htmlEqual(target.innerHTML, ` +

    foo 2

    + `); + } +}; \ No newline at end of file diff --git a/test/runtime/samples/component-namespaced/components.js b/test/runtime/samples/component-namespaced/components.js new file mode 100644 index 0000000000..832d2412ee --- /dev/null +++ b/test/runtime/samples/component-namespaced/components.js @@ -0,0 +1,3 @@ +import Foo from './Foo.svelte'; + +export default { Foo }; \ No newline at end of file diff --git a/test/runtime/samples/component-namespaced/main.svelte b/test/runtime/samples/component-namespaced/main.svelte new file mode 100644 index 0000000000..541b68e47e --- /dev/null +++ b/test/runtime/samples/component-namespaced/main.svelte @@ -0,0 +1,7 @@ + + + \ No newline at end of file diff --git a/test/server-side-rendering/index.js b/test/server-side-rendering/index.js index 6a546b0b7b..2806a1b5c2 100644 --- a/test/server-side-rendering/index.js +++ b/test/server-side-rendering/index.js @@ -96,10 +96,11 @@ describe("ssr", () => { (config.skip ? it.skip : config.solo ? it.only : it)(dir, () => { const cwd = path.resolve("test/runtime/samples", dir); - glob('**/*.svelte', { cwd: `test/runtime/samples/${dir}` }).forEach(file => { - const resolved = require.resolve(`../runtime/samples/${dir}/${file}`); - delete require.cache[resolved]; - }); + Object.keys(require.cache) + .filter(x => x.startsWith(cwd)) + .forEach(file => { + delete require.cache[file]; + }); const compileOptions = Object.assign({ sveltePath }, config.compileOptions, { generate: 'ssr' From debf1ce17ae2e356cbe9bd99af6816afef333364 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Sun, 12 May 2019 14:21:52 -0400 Subject: [PATCH 15/87] fix tests --- test/runtime/index.js | 2 +- test/runtime/samples/component-namespaced/_config.js | 6 ++++++ test/server-side-rendering/index.js | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/test/runtime/index.js b/test/runtime/index.js index d8660e67fd..64d7f3ae51 100644 --- a/test/runtime/index.js +++ b/test/runtime/index.js @@ -75,7 +75,7 @@ describe("runtime", () => { compileOptions.accessors = 'accessors' in config ? config.accessors : true; Object.keys(require.cache) - .filter(x => x.startsWith(cwd)) + .filter(x => x.endsWith('.svelte')) .forEach(file => { delete require.cache[file]; }); diff --git a/test/runtime/samples/component-namespaced/_config.js b/test/runtime/samples/component-namespaced/_config.js index e5f4c680da..b91795d6c8 100644 --- a/test/runtime/samples/component-namespaced/_config.js +++ b/test/runtime/samples/component-namespaced/_config.js @@ -1,3 +1,5 @@ +import * as path from 'path'; + export default { props: { a: 1 @@ -7,6 +9,10 @@ export default {

    foo 1

    `, + before_test() { + delete require.cache[path.resolve(__dirname, 'components.js')]; + }, + test({ assert, component, target }) { component.a = 2; assert.htmlEqual(target.innerHTML, ` diff --git a/test/server-side-rendering/index.js b/test/server-side-rendering/index.js index 2806a1b5c2..9f67ee06e9 100644 --- a/test/server-side-rendering/index.js +++ b/test/server-side-rendering/index.js @@ -97,7 +97,7 @@ describe("ssr", () => { const cwd = path.resolve("test/runtime/samples", dir); Object.keys(require.cache) - .filter(x => x.startsWith(cwd)) + .filter(x => x.endsWith('.svelte')) .forEach(file => { delete require.cache[file]; }); From 830e3d01cf439f446e1cabcdd44e53310316195d Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Sun, 12 May 2019 14:24:19 -0400 Subject: [PATCH 16/87] failing vars test --- .../vars/samples/component-namespaced/_config.js | 16 ++++++++++++++++ .../samples/component-namespaced/input.svelte | 5 +++++ 2 files changed, 21 insertions(+) create mode 100644 test/vars/samples/component-namespaced/_config.js create mode 100644 test/vars/samples/component-namespaced/input.svelte diff --git a/test/vars/samples/component-namespaced/_config.js b/test/vars/samples/component-namespaced/_config.js new file mode 100644 index 0000000000..ac63873967 --- /dev/null +++ b/test/vars/samples/component-namespaced/_config.js @@ -0,0 +1,16 @@ +export default { + test(assert, vars) { + assert.deepEqual(vars, [ + { + name: 'NS', + export_name: null, + injected: false, + module: false, + mutated: false, + reassigned: false, + referenced: true, + writable: false + } + ]); + } +}; \ No newline at end of file diff --git a/test/vars/samples/component-namespaced/input.svelte b/test/vars/samples/component-namespaced/input.svelte new file mode 100644 index 0000000000..996d2d8769 --- /dev/null +++ b/test/vars/samples/component-namespaced/input.svelte @@ -0,0 +1,5 @@ + + + \ No newline at end of file From f9a66e558b3ca6f851ad1738bed8c4baac96d60f Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Sun, 12 May 2019 14:25:44 -0400 Subject: [PATCH 17/87] failing missing-declaration test --- test/validator/samples/component-namespaced/input.svelte | 5 +++++ test/validator/samples/component-namespaced/warnings.json | 1 + 2 files changed, 6 insertions(+) create mode 100644 test/validator/samples/component-namespaced/input.svelte create mode 100644 test/validator/samples/component-namespaced/warnings.json diff --git a/test/validator/samples/component-namespaced/input.svelte b/test/validator/samples/component-namespaced/input.svelte new file mode 100644 index 0000000000..996d2d8769 --- /dev/null +++ b/test/validator/samples/component-namespaced/input.svelte @@ -0,0 +1,5 @@ + + + \ No newline at end of file diff --git a/test/validator/samples/component-namespaced/warnings.json b/test/validator/samples/component-namespaced/warnings.json new file mode 100644 index 0000000000..0637a088a0 --- /dev/null +++ b/test/validator/samples/component-namespaced/warnings.json @@ -0,0 +1 @@ +[] \ No newline at end of file From 85543f54dd74cc6c67a3be50878e87ffadde92f7 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Sun, 12 May 2019 14:31:11 -0400 Subject: [PATCH 18/87] fix vars/warnings --- src/compile/Component.ts | 6 ++---- src/compile/nodes/Action.ts | 2 +- src/compile/nodes/Animation.ts | 2 +- src/compile/nodes/InlineComponent.ts | 5 +++-- src/compile/nodes/Transition.ts | 2 +- src/compile/nodes/shared/Expression.ts | 2 +- 6 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/compile/Component.ts b/src/compile/Component.ts index aad5e98413..dd41a0a645 100644 --- a/src/compile/Component.ts +++ b/src/compile/Component.ts @@ -759,7 +759,7 @@ export default class Component { const { name } = object; if (name[0] === '$' && !scope.has(name)) { - component.warn_if_undefined(object, null); + component.warn_if_undefined(name, object, null); } } }, @@ -1202,9 +1202,7 @@ export default class Component { return `ctx.${name}`; } - warn_if_undefined(node, template_scope: TemplateScope) { - let { name } = node; - + warn_if_undefined(name: string, node, template_scope: TemplateScope) { if (name[0] === '$') { name = name.slice(1); this.has_reactive_assignments = true; // TODO does this belong here? diff --git a/src/compile/nodes/Action.ts b/src/compile/nodes/Action.ts index feec3fada8..77b9e3c846 100644 --- a/src/compile/nodes/Action.ts +++ b/src/compile/nodes/Action.ts @@ -11,7 +11,7 @@ export default class Action extends Node { constructor(component: Component, parent, scope, info) { super(component, parent, scope, info); - component.warn_if_undefined(info, scope); + component.warn_if_undefined(info.name, info, scope); this.name = info.name; component.qualify(info.name); diff --git a/src/compile/nodes/Animation.ts b/src/compile/nodes/Animation.ts index 638a88b169..6ccdbb0803 100644 --- a/src/compile/nodes/Animation.ts +++ b/src/compile/nodes/Animation.ts @@ -10,7 +10,7 @@ export default class Animation extends Node { constructor(component: Component, parent, scope, info) { super(component, parent, scope, info); - component.warn_if_undefined(info, scope); + component.warn_if_undefined(info.name, info, scope); this.name = info.name; component.qualify(info.name); diff --git a/src/compile/nodes/InlineComponent.ts b/src/compile/nodes/InlineComponent.ts index 0d8801aad1..3359e981ed 100644 --- a/src/compile/nodes/InlineComponent.ts +++ b/src/compile/nodes/InlineComponent.ts @@ -23,8 +23,9 @@ export default class InlineComponent extends Node { super(component, parent, scope, info); if (info.name !== 'svelte:component' && info.name !== 'svelte:self') { - component.warn_if_undefined(info, scope); - component.add_reference(info.name); + const name = info.name.split('.')[0]; // accommodate namespaces + component.warn_if_undefined(name, info, scope); + component.add_reference(name); } this.name = info.name; diff --git a/src/compile/nodes/Transition.ts b/src/compile/nodes/Transition.ts index c3f22d888e..82eb578f0f 100644 --- a/src/compile/nodes/Transition.ts +++ b/src/compile/nodes/Transition.ts @@ -12,7 +12,7 @@ export default class Transition extends Node { constructor(component: Component, parent, scope, info) { super(component, parent, scope, info); - component.warn_if_undefined(info, scope); + component.warn_if_undefined(info.name, info, scope); this.name = info.name; component.qualify(info.name); diff --git a/src/compile/nodes/shared/Expression.ts b/src/compile/nodes/shared/Expression.ts index 22cb403f75..fc188e9673 100644 --- a/src/compile/nodes/shared/Expression.ts +++ b/src/compile/nodes/shared/Expression.ts @@ -149,7 +149,7 @@ export default class Expression { } component.add_reference(name); - component.warn_if_undefined(nodes[0], template_scope); + component.warn_if_undefined(name, nodes[0], template_scope); } this.skip(); From c72e863a7f832b318e84513b7f34332281835a28 Mon Sep 17 00:00:00 2001 From: pngwn Date: Sun, 12 May 2019 20:27:19 +0100 Subject: [PATCH 19/87] Document svelte/transition - fade, fly, slide, scale, draw. --- site/content/docs/03-run-time.md | 200 ++++++++++++++++++++++++++++++- 1 file changed, 197 insertions(+), 3 deletions(-) diff --git a/site/content/docs/03-run-time.md b/site/content/docs/03-run-time.md index fe981896b9..dde8d18bcf 100644 --- a/site/content/docs/03-run-time.md +++ b/site/content/docs/03-run-time.md @@ -517,10 +517,204 @@ Both `set` and `update` can take a second argument — an object with `hard` or ### `svelte/transition` -TODO +The `svelte/transition` module exports six functions: `fade`, `fly`, `slide`, `scale`, `draw` and `crossfade`. They are for use with svelte [`transitions`](docs#Transitions). + +#### `fade` + +```sv +transition:fade={params} +``` +```sv +in:fade={params} +``` +```sv +out:fade={params} +``` + +--- + +Animates the opacity of an element from 0 to the current opacity for `in` transitions and from the current opacity to 0 for `out` transitions. + +`fade` accepts the following parameters: + +* `delay` (`number`, default 0) — milliseconds before starting +* `duration` (`number`, default 400) — milliseconds the transition lasts + +You can see the `fade` transition in action in the [transition tutorial](tutorial/transition). + +```html + + +{#if condition} +
    + fades in and out +
    +{/if} +``` + +#### `fly` + +```sv +transition:fly={params} +``` +```sv +in:fly={params} +``` +```sv +out:fly={params} +``` + +--- + +Animates the x and y positions and the opacity of an element. `in` transitions animate from an element's current (default) values to the provided values, passed as parameters. `out` transitions animate from the provided values to an element's default values. + +`fly` accepts the following parameters: + +* `delay` (`number`, default 0) — milliseconds before starting +* `duration` (`number`, default 400) — milliseconds the transition lasts +* `easing` (`function`, default `cubicOut`) — an [easing function](docs#svelte_easing) +* `x` (`number`, default 0) - the x offset to animate out to and in from +* `y` (`number`, default 0) - the y offset to animate out to and in from +* `opacity` (`number`, default 0) - the opacity value to animate out to and in from + +You can see the `fly` transition in action in the [transition tutorial](tutorial/adding-parameters-to-transitions). + +```html + + +{#if condition} +
    + flies in and out +
    +{/if} +``` + +#### `slide` + +```sv +transition:slide={params} +``` +```sv +in:slide={params} +``` +```sv +out:slide={params} +``` + +--- + +Slides an element in and out. + +`slide` accepts the following parameters: + +* `delay` (`number`, default 0) — milliseconds before starting +* `duration` (`number`, default 400) — milliseconds the transition lasts +* `easing` (`function`, default `cubicOut`) — an [easing function](docs#svelte_easing) + +```html + + +{#if condition} +
    + flies in and out +
    +{/if} +``` + +#### `scale` + +```sv +transition:scale={params} +``` +```sv +in:scale={params} +``` +```sv +out:scale={params} +``` + +--- + +Animates the opacity and scale of an element. `in` transitions animate from an element's current (default) values to the provided values, passed as parameters. `out` transitions animate from the provided values to an element's default values. + +`scale` accepts the following parameters: + +* `delay` (`number`, default 0) — milliseconds before starting +* `duration` (`number`, default 400) — milliseconds the transition lasts +* `easing` (`function`, default `cubicOut`) — an [easing function](docs#svelte_easing) +* `start` (`number`, default 0) - the scale value to animate out to and in from +* `opacity` (`number`, default 0) - the opacity value to animate out to and in from + +```html + + +{#if condition} +
    + scales in and out +
    +{/if} +``` + +#### `draw` + +```sv +transition:draw={params} +``` +```sv +in:draw={params} +``` +```sv +out:draw={params} +``` + +--- + +Animates the stroke of an SVG path, like a snake in a tube. `in` transitions being with the path invisible and draw the path to the screen over time. `out` transitions start in a visible state and gradually erases the path. `draw` only works with SVG Path elements. + +`scale` accepts the following parameters: + +* `delay` (`number`, default 0) — milliseconds before starting +* `speed` (`number`, default undefined) - the speed of the animation, see below. +* `duration` (`number` | `function`, default 800) — milliseconds the transition lasts +* `easing` (`function`, default `cubicInOut`) — an [easing function](docs#svelte_easing) + +The `speed` parameter is a means of setting the duration of the transition relative to the path's length. It is modifier that is applied to the length of the path: `duration = length / speed`. A path that is 1000 pixels with a speed of 1 will have a duration of `1000ms`, setting the speed to `0.5` will halve that duration and setting it to `2` will double it. + +```html + + + + {#if condition} + + {/if} + + +``` + + + + -* fade, fly, slide, scale, draw -* crossfade... ### `svelte/animate` From 0c76b9637a0110fc75974b9d8ccf17d89cc27606 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Sun, 12 May 2019 16:22:37 -0400 Subject: [PATCH 20/87] minor correction --- site/content/docs/03-run-time.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site/content/docs/03-run-time.md b/site/content/docs/03-run-time.md index dde8d18bcf..dc52a9dec0 100644 --- a/site/content/docs/03-run-time.md +++ b/site/content/docs/03-run-time.md @@ -680,7 +680,7 @@ out:draw={params} --- -Animates the stroke of an SVG path, like a snake in a tube. `in` transitions being with the path invisible and draw the path to the screen over time. `out` transitions start in a visible state and gradually erases the path. `draw` only works with SVG Path elements. +Animates the stroke of an SVG element, like a snake in a tube. `in` transitions being with the path invisible and draw the path to the screen over time. `out` transitions start in a visible state and gradually erase the path. `draw` only works with elements that have a `getTotalLength` method, like `` and ``. `scale` accepts the following parameters: From 438acdc09ac93d217f5de4a517217db6570d7dbc Mon Sep 17 00:00:00 2001 From: Conduitry Date: Sun, 12 May 2019 16:32:22 -0400 Subject: [PATCH 21/87] typo --- site/content/docs/03-run-time.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site/content/docs/03-run-time.md b/site/content/docs/03-run-time.md index dc52a9dec0..1beacc4169 100644 --- a/site/content/docs/03-run-time.md +++ b/site/content/docs/03-run-time.md @@ -680,7 +680,7 @@ out:draw={params} --- -Animates the stroke of an SVG element, like a snake in a tube. `in` transitions being with the path invisible and draw the path to the screen over time. `out` transitions start in a visible state and gradually erase the path. `draw` only works with elements that have a `getTotalLength` method, like `` and ``. +Animates the stroke of an SVG element, like a snake in a tube. `in` transitions begin with the path invisible and draw the path to the screen over time. `out` transitions start in a visible state and gradually erase the path. `draw` only works with elements that have a `getTotalLength` method, like `` and ``. `scale` accepts the following parameters: From 3b4c6ed4ebb31e2cd662548024967100783100ad Mon Sep 17 00:00:00 2001 From: Sander Hahn Date: Fri, 10 May 2019 18:56:54 +0200 Subject: [PATCH 22/87] typescript version of store --- .gitignore | 2 +- package.json | 3 +- rollup.config.js | 31 ++++++++++- src/store.ts | 130 +++++++++++++++++++++++++++++++++++++++++++++++ store.mjs | 85 ------------------------------- tsconfig.json | 3 +- 6 files changed, 165 insertions(+), 89 deletions(-) create mode 100644 src/store.ts delete mode 100644 store.mjs diff --git a/.gitignore b/.gitignore index 06671edc2b..7aa75b29f4 100644 --- a/.gitignore +++ b/.gitignore @@ -6,7 +6,7 @@ node_modules /compiler.js /index.js /internal.* -/store.js +/store.* /easing.js /motion.* /transition.js diff --git a/package.json b/package.json index ccbedde168..e0364bfa3a 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,8 @@ "dev": "rollup -cw", "pretest": "npm run build", "posttest": "agadoo src/internal/index.js", - "prepublishOnly": "export PUBLISH=true && npm run lint && npm test" + "prepublishOnly": "export PUBLISH=true && npm run lint && npm test", + "tsd": "tsc -d src/store.ts --outDir ." }, "repository": { "type": "git", diff --git a/rollup.config.js b/rollup.config.js index f7b2d07d4b..0d19e59d4a 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -87,8 +87,37 @@ export default [ external: id => id.startsWith('svelte/') }, + /* store.mjs */ + { + input: `src/store.ts`, + output: [ + { + file: `store.mjs`, + format: 'esm', + paths: id => id.startsWith('svelte/') && id.replace('svelte', '.') + }, + { + file: `store.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'] + }) + ], + external: id => id.startsWith('svelte/') + }, + // everything else - ...['index', 'store', 'easing', 'transition', 'animate'].map(name => ({ + ...['index', 'easing', 'transition', 'animate'].map(name => ({ input: `${name}.mjs`, output: { file: `${name}.js`, diff --git a/src/store.ts b/src/store.ts new file mode 100644 index 0000000000..e27059a4d7 --- /dev/null +++ b/src/store.ts @@ -0,0 +1,130 @@ +import { run_all, noop, safe_not_equal } from './internal/utils'; + +type Subscriber = (value: T) => void; + +type Unsubscriber = () => void; + +type Updater = (value: T) => T; + +type Invalidater = (value?: T) => void; + +type StartStopNotifier = (set: Subscriber) => Unsubscriber | void; + +export interface ReadableStore { + subscribe(run: Subscriber, invalidate?: Invalidater): Unsubscriber; +} + +export interface WritableStore extends ReadableStore { + set(value: T): void; + update(updater: Updater): void; +} + +type SubscribeInvalidateTuple = [Subscriber, Invalidater]; + +export function readable(value: T, start: StartStopNotifier): ReadableStore { + return { + subscribe: writable(value, start).subscribe, + }; +} + +export function writable(value: T, start: StartStopNotifier = noop): WritableStore { + let stop: Unsubscriber; + const subscribers: Array> = []; + + function set(new_value: T): void { + if (safe_not_equal(value, new_value)) { + value = new_value; + if (!stop) { + return; // not ready + } + subscribers.forEach((s) => s[1]()); + subscribers.forEach((s) => s[0](value)); + } + } + + function update(fn: Updater): void { + set(fn(value)); + } + + function subscribe(run: Subscriber, invalidate: Invalidater = noop): Unsubscriber { + const subscriber: SubscribeInvalidateTuple = [run, invalidate]; + subscribers.push(subscriber); + if (subscribers.length === 1) { + stop = start(set) || noop; + } + run(value); + + return () => { + const index = subscribers.indexOf(subscriber); + if (index !== -1) { + subscribers.splice(index, 1); + } + if (subscribers.length === 0) { + stop(); + } + }; + } + + return { set, update, subscribe }; +} + +export function derived( + stores: ReadableStore | Array>, + fn: (values: T | T[], set?: Subscriber) => T | Unsubscriber | void, + initial_value: T): ReadableStore { + + const single = !Array.isArray(stores); + const stores_array: Array> = single + ? [stores as ReadableStore] + : stores as Array>; + + const auto = fn.length < 2; + + return readable(initial_value, (set) => { + let inited = false; + const values: T[] = []; + + let pending = 0; + let cleanup = noop; + + const sync = () => { + if (pending) { + return; + } + cleanup(); + const result = fn(single ? values[0] : values, set); + if (auto) { + set(result as T); + } else { + cleanup = result as Unsubscriber || noop; + } + }; + + const unsubscribers = stores_array.map((store, i) => store.subscribe( + (value) => { + values[i] = value; + pending &= ~(1 << i); + if (inited) { + sync(); + } + }, + () => { + pending |= (1 << i); + }), + ); + + inited = true; + sync(); + + return function stop() { + run_all(unsubscribers); + cleanup(); + }; + }); +} + +export function get(store: ReadableStore): T { + let value: T | undefined; + store.subscribe((_: T) => value = _)(); + return value as T; +} diff --git a/store.mjs b/store.mjs deleted file mode 100644 index 624ede3dde..0000000000 --- a/store.mjs +++ /dev/null @@ -1,85 +0,0 @@ -import { run_all, noop, get_store_value, safe_not_equal } from './internal'; - -export function readable(value, start) { - return { - subscribe: writable(value, start).subscribe - }; -} - -export function writable(value, start = noop) { - let stop; - const subscribers = []; - - function set(new_value) { - if (safe_not_equal(value, new_value)) { - value = new_value; - if (!stop) return; // not ready - subscribers.forEach(s => s[1]()); - subscribers.forEach(s => s[0](value)); - } - } - - function update(fn) { - set(fn(value)); - } - - function subscribe(run, invalidate = noop) { - const subscriber = [run, invalidate]; - subscribers.push(subscriber); - if (subscribers.length === 1) stop = start(set) || noop; - run(value); - - return () => { - const index = subscribers.indexOf(subscriber); - if (index !== -1) subscribers.splice(index, 1); - if (subscribers.length === 0) stop(); - }; - } - - return { set, update, subscribe }; -} - -export function derived(stores, fn, initial_value) { - const single = !Array.isArray(stores); - if (single) stores = [stores]; - - const auto = fn.length < 2; - let value = {}; - - return readable(initial_value, set => { - let inited = false; - const values = []; - - let pending = 0; - let cleanup = noop; - - const sync = () => { - if (pending) return; - cleanup(); - const result = fn(single ? values[0] : values, set); - if (auto) set(result); - else cleanup = result || noop; - }; - - const unsubscribers = stores.map((store, i) => store.subscribe( - value => { - values[i] = value; - pending &= ~(1 << i); - if (inited) sync(); - }, - () => { - pending |= (1 << i); - }) - ); - - inited = true; - sync(); - - return function stop() { - run_all(unsubscribers); - cleanup(); - }; - }); -} - -export { get_store_value as get }; diff --git a/tsconfig.json b/tsconfig.json index fdb7367e05..5da2d13a01 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -7,7 +7,8 @@ "allowJs": true, "lib": ["es5", "es6", "dom"], "importHelpers": true, - "moduleResolution": "node" + "moduleResolution": "node", + "strict": true }, "include": [ "src" From b6b7c621d062752121aced2a9108b1cc3c777179 Mon Sep 17 00:00:00 2001 From: Sander Hahn Date: Mon, 13 May 2019 00:25:32 +0200 Subject: [PATCH 23/87] run tsd on prepare --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e0364bfa3a..24feedd1e7 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "precodecov": "npm run coverage", "lint": "eslint src test/*.js", "build": "rollup -c", - "prepare": "npm run build", + "prepare": "npm run build && npm run tsd", "dev": "rollup -cw", "pretest": "npm run build", "posttest": "agadoo src/internal/index.js", From fbb6c9fd4e4197f0edf598f56eeb1066fa52b915 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Mon, 13 May 2019 09:27:28 -0400 Subject: [PATCH 24/87] -> v3.3.0 --- CHANGELOG.md | 6 ++++++ package.json | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 239f2d28e3..1d6a7b34dd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Svelte changelog +## 3.3.0 + +* Allow multiple event listeners on a single node ([#2688](https://github.com/sveltejs/svelte/issues/2688)) +* Allow derivers to return a cleanup function ([#2553](https://github.com/sveltejs/svelte/issues/2553)) +* Support namespaced components (``) ([#2743](https://github.com/sveltejs/svelte/pull/2743)) + ## 3.2.2 * Add `window` and `document` to expected globals ([#2722](https://github.com/sveltejs/svelte/pull/2722)) diff --git a/package.json b/package.json index ccbedde168..437eef8d0e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "svelte", - "version": "3.2.2", + "version": "3.3.0", "description": "Cybernetically enhanced web apps", "module": "index.mjs", "main": "index", From 690f163e889f9c93146419b9c03aadfd0f5176e5 Mon Sep 17 00:00:00 2001 From: Colin Casey Date: Mon, 13 May 2019 15:16:51 -0300 Subject: [PATCH 25/87] FIX #2417: allows custom element to be defined without a tag * warning given on compile if tag is absent * no warning if tag is set to `null` --- src/compile/Component.ts | 14 +++++++++----- src/compile/render-dom/index.ts | 8 ++++++-- test/custom-elements/index.js | 15 +++++++++++++++ .../samples/no-tag-warning/_config.js | 17 +++++++++++++++++ .../samples/no-tag-warning/main.svelte | 7 +++++++ .../samples/no-tag-warning/test.js | 12 ++++++++++++ test/custom-elements/samples/no-tag/_config.js | 3 +++ test/custom-elements/samples/no-tag/main.svelte | 7 +++++++ test/custom-elements/samples/no-tag/test.js | 12 ++++++++++++ 9 files changed, 88 insertions(+), 7 deletions(-) create mode 100644 test/custom-elements/samples/no-tag-warning/_config.js create mode 100644 test/custom-elements/samples/no-tag-warning/main.svelte create mode 100644 test/custom-elements/samples/no-tag-warning/test.js create mode 100644 test/custom-elements/samples/no-tag/_config.js create mode 100644 test/custom-elements/samples/no-tag/main.svelte create mode 100644 test/custom-elements/samples/no-tag/test.js diff --git a/src/compile/Component.ts b/src/compile/Component.ts index dd41a0a645..cbebeede49 100644 --- a/src/compile/Component.ts +++ b/src/compile/Component.ts @@ -152,10 +152,14 @@ export default class Component { this.namespace = namespaces[this.component_options.namespace] || this.component_options.namespace; if (compile_options.customElement) { - this.tag = this.component_options.tag || compile_options.tag; - if (!this.tag) { - throw new Error(`Cannot compile to a custom element without specifying a tag name via options.tag or `); + if (this.component_options.tag === undefined && compile_options.tag === undefined) { + const svelteOptions = ast.html.children.find(child => child.name === 'svelte:options'); + this.warn(svelteOptions, { + code: 'custom-element-no-tag', + message: `No custom element 'tag' option was specified. To automatically register a custom element, specify a name with a hyphen in it, e.g. . To hide this warning, use ` + }); } + this.tag = this.component_options.tag || compile_options.tag; } else { this.tag = this.name; } @@ -1265,9 +1269,9 @@ function process_component_options(component: Component, nodes) { const message = `'tag' must be a string literal`; const tag = get_value(attribute, code, message); - if (typeof tag !== 'string') component.error(attribute, { code, message }); + if (typeof tag !== 'string' && tag !== null) component.error(attribute, { code, message }); - if (!/^[a-zA-Z][a-zA-Z0-9]*-[a-zA-Z0-9-]+$/.test(tag)) { + if (tag && !/^[a-zA-Z][a-zA-Z0-9]*-[a-zA-Z0-9-]+$/.test(tag)) { component.error(attribute, { code: `invalid-tag-property`, message: `tag name must be two or more words joined by the '-' character` diff --git a/src/compile/render-dom/index.ts b/src/compile/render-dom/index.ts index 0a0743b2a0..8d456a050d 100644 --- a/src/compile/render-dom/index.ts +++ b/src/compile/render-dom/index.ts @@ -462,9 +462,13 @@ export default function dom( ${body.length > 0 && body.join('\n\n')} } - - customElements.define("${component.tag}", ${name}); `); + + if (component.tag != null) { + builder.add_block(deindent` + customElements.define("${component.tag}", ${name}); + `); + } } else { const superclass = options.dev ? 'SvelteComponentDev' : 'SvelteComponent'; diff --git a/test/custom-elements/index.js b/test/custom-elements/index.js index 32e95266ec..5ac0b73bbf 100644 --- a/test/custom-elements/index.js +++ b/test/custom-elements/index.js @@ -5,6 +5,7 @@ import { rollup } from 'rollup'; import * as virtual from 'rollup-plugin-virtual'; import * as puppeteer from 'puppeteer'; import { addLineNumbers, loadConfig, loadSvelte } from "../helpers.js"; +import { deepEqual } from 'assert'; const page = ` @@ -59,9 +60,11 @@ describe('custom-elements', function() { const skip = /\.skip$/.test(dir); const internal = path.resolve('internal.mjs'); const index = path.resolve('index.mjs'); + const warnings = []; (solo ? it.only : skip ? it.skip : it)(dir, async () => { const config = loadConfig(`./custom-elements/samples/${dir}/_config.js`); + const expected_warnings = config.warnings || []; const bundle = await rollup({ input: `test/custom-elements/samples/${dir}/test.js`, @@ -84,6 +87,8 @@ describe('custom-elements', function() { dev: config.dev }); + compiled.warnings.forEach(w => warnings.push(w)); + return compiled.js; } } @@ -112,6 +117,16 @@ describe('custom-elements', function() { } catch (err) { console.log(addLineNumbers(code)); throw err; + } finally { + if (expected_warnings) { + deepEqual(warnings.map(w => ({ + code: w.code, + message: w.message, + pos: w.pos, + start: w.start, + end: w.end + })), expected_warnings); + } } }); }); diff --git a/test/custom-elements/samples/no-tag-warning/_config.js b/test/custom-elements/samples/no-tag-warning/_config.js new file mode 100644 index 0000000000..7cdfdbaec6 --- /dev/null +++ b/test/custom-elements/samples/no-tag-warning/_config.js @@ -0,0 +1,17 @@ +export default { + warnings: [{ + code: "custom-element-no-tag", + message: "No custom element 'tag' option was specified. To automatically register a custom element, specify a name with a hyphen in it, e.g. . To hide this warning, use ", + pos: 0, + start: { + character: 0, + column: 0, + line: 1 + }, + end: { + character: 18, + column: 18, + line: 1 + } + }] +}; diff --git a/test/custom-elements/samples/no-tag-warning/main.svelte b/test/custom-elements/samples/no-tag-warning/main.svelte new file mode 100644 index 0000000000..4f7cdc52ca --- /dev/null +++ b/test/custom-elements/samples/no-tag-warning/main.svelte @@ -0,0 +1,7 @@ + + + + +

    Hello {name}!

    diff --git a/test/custom-elements/samples/no-tag-warning/test.js b/test/custom-elements/samples/no-tag-warning/test.js new file mode 100644 index 0000000000..c77f035088 --- /dev/null +++ b/test/custom-elements/samples/no-tag-warning/test.js @@ -0,0 +1,12 @@ +import * as assert from 'assert'; +import CustomElement from './main.svelte'; + +export default function (target) { + customElements.define('no-tag', CustomElement); + target.innerHTML = ``; + + const el = target.querySelector('no-tag'); + const h1 = el.shadowRoot.querySelector('h1'); + + assert.equal(h1.textContent, 'Hello world!'); +} diff --git a/test/custom-elements/samples/no-tag/_config.js b/test/custom-elements/samples/no-tag/_config.js new file mode 100644 index 0000000000..c81f1a9f82 --- /dev/null +++ b/test/custom-elements/samples/no-tag/_config.js @@ -0,0 +1,3 @@ +export default { + warnings: [] +}; diff --git a/test/custom-elements/samples/no-tag/main.svelte b/test/custom-elements/samples/no-tag/main.svelte new file mode 100644 index 0000000000..031bd93694 --- /dev/null +++ b/test/custom-elements/samples/no-tag/main.svelte @@ -0,0 +1,7 @@ + + + + +

    Hello {name}!

    diff --git a/test/custom-elements/samples/no-tag/test.js b/test/custom-elements/samples/no-tag/test.js new file mode 100644 index 0000000000..c77f035088 --- /dev/null +++ b/test/custom-elements/samples/no-tag/test.js @@ -0,0 +1,12 @@ +import * as assert from 'assert'; +import CustomElement from './main.svelte'; + +export default function (target) { + customElements.define('no-tag', CustomElement); + target.innerHTML = ``; + + const el = target.querySelector('no-tag'); + const h1 = el.shadowRoot.querySelector('h1'); + + assert.equal(h1.textContent, 'Hello world!'); +} From 97184b789caa8885e8f6233ca7c538135c4193db Mon Sep 17 00:00:00 2001 From: Emil Tholin Date: Tue, 14 May 2019 11:32:37 +0200 Subject: [PATCH 26/87] Set quote_mark to null when closing quote mark is found --- src/compile/render-dom/wrappers/Element/StyleAttribute.ts | 4 ++-- test/runtime/samples/attribute-url/_config.js | 8 ++++++++ test/runtime/samples/attribute-url/main.svelte | 6 ++++++ 3 files changed, 16 insertions(+), 2 deletions(-) create mode 100644 test/runtime/samples/attribute-url/_config.js create mode 100644 test/runtime/samples/attribute-url/main.svelte diff --git a/src/compile/render-dom/wrappers/Element/StyleAttribute.ts b/src/compile/render-dom/wrappers/Element/StyleAttribute.ts index b0a3663c63..43524ff372 100644 --- a/src/compile/render-dom/wrappers/Element/StyleAttribute.ts +++ b/src/compile/render-dom/wrappers/Element/StyleAttribute.ts @@ -122,7 +122,7 @@ function get_style_value(chunks: Node[]) { } else if (char === '\\') { escaped = true; } else if (char === quote_mark) { - quote_mark === null; + quote_mark = null; } else if (char === '"' || char === "'") { quote_mark = char; } else if (char === ')' && in_url) { @@ -173,4 +173,4 @@ function get_style_value(chunks: Node[]) { function is_dynamic(value: Node[]) { return value.length > 1 || value[0].type !== 'Text'; -} \ No newline at end of file +} diff --git a/test/runtime/samples/attribute-url/_config.js b/test/runtime/samples/attribute-url/_config.js new file mode 100644 index 0000000000..28bc1bcb0c --- /dev/null +++ b/test/runtime/samples/attribute-url/_config.js @@ -0,0 +1,8 @@ +export default { + test({ assert, target }) { + const div = target.querySelector( 'div' ); + + assert.equal( div.style.backgroundImage, 'url(https://example.com/foo.jpg)'); + assert.equal( div.style.color, 'red' ); + } +}; diff --git a/test/runtime/samples/attribute-url/main.svelte b/test/runtime/samples/attribute-url/main.svelte new file mode 100644 index 0000000000..357a352aaa --- /dev/null +++ b/test/runtime/samples/attribute-url/main.svelte @@ -0,0 +1,6 @@ + + +
    {color}
    From de60ffb497fc7635a152dee4e2f0c6e37876d898 Mon Sep 17 00:00:00 2001 From: Steven Weathers Date: Tue, 14 May 2019 20:42:08 -0400 Subject: [PATCH 27/87] Add Thunderdome Link to Who's Using --- .../routes/_components/WhosUsingSvelte.svelte | 1 + site/static/organisations/thunderdome.svg | 154 ++++++++++++++++++ 2 files changed, 155 insertions(+) create mode 100644 site/static/organisations/thunderdome.svg diff --git a/site/src/routes/_components/WhosUsingSvelte.svelte b/site/src/routes/_components/WhosUsingSvelte.svelte index 1700312055..21c57d065a 100644 --- a/site/src/routes/_components/WhosUsingSvelte.svelte +++ b/site/src/routes/_components/WhosUsingSvelte.svelte @@ -54,5 +54,6 @@ The New York Times logo Razorpay logo Stone Payments logo + Thunderdome logo + your company? diff --git a/site/static/organisations/thunderdome.svg b/site/static/organisations/thunderdome.svg new file mode 100644 index 0000000000..c8cbdaf039 --- /dev/null +++ b/site/static/organisations/thunderdome.svg @@ -0,0 +1,154 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 011b33181ee566c1566082dc645da2bb5e412f7e Mon Sep 17 00:00:00 2001 From: Conduitry Date: Tue, 14 May 2019 23:59:07 -0400 Subject: [PATCH 28/87] site: fix immutable tutorial and example on Firefox (#2601) --- .../20-miscellaneous/02-immutable-data/flash.js | 16 +++++++++------- .../07-svelte-options/app-a/flash.js | 16 +++++++++------- .../07-svelte-options/app-b/flash.js | 16 +++++++++------- 3 files changed, 27 insertions(+), 21 deletions(-) diff --git a/site/content/examples/20-miscellaneous/02-immutable-data/flash.js b/site/content/examples/20-miscellaneous/02-immutable-data/flash.js index 8dff9cbe2f..c788cc6d35 100644 --- a/site/content/examples/20-miscellaneous/02-immutable-data/flash.js +++ b/site/content/examples/20-miscellaneous/02-immutable-data/flash.js @@ -1,11 +1,13 @@ export default function flash(element) { - element.style.transition = 'none'; - element.style.color = 'rgba(255,62,0,1)'; - element.style.backgroundColor = 'rgba(255,62,0,0.2)'; + requestAnimationFrame(() => { + element.style.transition = 'none'; + element.style.color = 'rgba(255,62,0,1)'; + element.style.backgroundColor = 'rgba(255,62,0,0.2)'; - setTimeout(() => { - element.style.transition = 'color 1s, background 1s'; - element.style.color = ''; - element.style.backgroundColor = ''; + setTimeout(() => { + element.style.transition = 'color 1s, background 1s'; + element.style.color = ''; + element.style.backgroundColor = ''; + }); }); } \ No newline at end of file diff --git a/site/content/tutorial/16-special-elements/07-svelte-options/app-a/flash.js b/site/content/tutorial/16-special-elements/07-svelte-options/app-a/flash.js index 8dff9cbe2f..c788cc6d35 100644 --- a/site/content/tutorial/16-special-elements/07-svelte-options/app-a/flash.js +++ b/site/content/tutorial/16-special-elements/07-svelte-options/app-a/flash.js @@ -1,11 +1,13 @@ export default function flash(element) { - element.style.transition = 'none'; - element.style.color = 'rgba(255,62,0,1)'; - element.style.backgroundColor = 'rgba(255,62,0,0.2)'; + requestAnimationFrame(() => { + element.style.transition = 'none'; + element.style.color = 'rgba(255,62,0,1)'; + element.style.backgroundColor = 'rgba(255,62,0,0.2)'; - setTimeout(() => { - element.style.transition = 'color 1s, background 1s'; - element.style.color = ''; - element.style.backgroundColor = ''; + setTimeout(() => { + element.style.transition = 'color 1s, background 1s'; + element.style.color = ''; + element.style.backgroundColor = ''; + }); }); } \ No newline at end of file diff --git a/site/content/tutorial/16-special-elements/07-svelte-options/app-b/flash.js b/site/content/tutorial/16-special-elements/07-svelte-options/app-b/flash.js index 8dff9cbe2f..c788cc6d35 100644 --- a/site/content/tutorial/16-special-elements/07-svelte-options/app-b/flash.js +++ b/site/content/tutorial/16-special-elements/07-svelte-options/app-b/flash.js @@ -1,11 +1,13 @@ export default function flash(element) { - element.style.transition = 'none'; - element.style.color = 'rgba(255,62,0,1)'; - element.style.backgroundColor = 'rgba(255,62,0,0.2)'; + requestAnimationFrame(() => { + element.style.transition = 'none'; + element.style.color = 'rgba(255,62,0,1)'; + element.style.backgroundColor = 'rgba(255,62,0,0.2)'; - setTimeout(() => { - element.style.transition = 'color 1s, background 1s'; - element.style.color = ''; - element.style.backgroundColor = ''; + setTimeout(() => { + element.style.transition = 'color 1s, background 1s'; + element.style.color = ''; + element.style.backgroundColor = ''; + }); }); } \ No newline at end of file From 85073dbb723796465cce6f31654f9f1166bd9e71 Mon Sep 17 00:00:00 2001 From: Peter Varholak Date: Tue, 14 May 2019 22:09:20 -0700 Subject: [PATCH 29/87] add @debug API docs --- site/content/docs/02-template-syntax.md | 43 +++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/site/content/docs/02-template-syntax.md b/site/content/docs/02-template-syntax.md index c6fd5c8b2d..44256b52e7 100644 --- a/site/content/docs/02-template-syntax.md +++ b/site/content/docs/02-template-syntax.md @@ -1261,3 +1261,46 @@ The `` element provides a place to specify per-component compile ```html ``` + + +### @debug + +```sv +{@debug variable} +``` +```sv +{@debug var1, var2, ..., varN} +``` + +--- + +The `{@debug ...}` tag offers an alternative to `console.log(...)`. It allows you to inspect the value of a specific variable, but additionally pauses code execution when you have devtools open. + +```html + + +{@debug user} + +

    Hello {user.firstname}!

    +``` + +--- + +`{@debug ...}` can also accept a comma-separated list of values, however it accepts only variable identifiers, and as such does not support inspecting of expressions. + +```sv +# Compiles +{@debug user} +{@debug user1, user2, user3} + +# WON'T compile +{@debug user.firstname} +{@debug myArray[0]} +{@debug !isReady} +{@debug typeof user === 'object'} +``` From 52eda23a53061a951fee06050733556a7ad42773 Mon Sep 17 00:00:00 2001 From: Sander Hahn Date: Wed, 15 May 2019 07:34:06 +0200 Subject: [PATCH 30/87] advanced type for derived --- src/store.ts | 32 ++++++++++++++++++------------- test/{store/index.js => store.ts} | 28 ++++++++++++++++++++++----- tsconfig.json | 3 +-- 3 files changed, 43 insertions(+), 20 deletions(-) rename test/{store/index.js => store.ts} (88%) diff --git a/src/store.ts b/src/store.ts index e27059a4d7..462f155c2a 100644 --- a/src/store.ts +++ b/src/store.ts @@ -10,24 +10,24 @@ type Invalidater = (value?: T) => void; type StartStopNotifier = (set: Subscriber) => Unsubscriber | void; -export interface ReadableStore { +export interface Readable { subscribe(run: Subscriber, invalidate?: Invalidater): Unsubscriber; } -export interface WritableStore extends ReadableStore { +export interface Writable extends Readable { set(value: T): void; update(updater: Updater): void; } type SubscribeInvalidateTuple = [Subscriber, Invalidater]; -export function readable(value: T, start: StartStopNotifier): ReadableStore { +export function readable(value: T, start: StartStopNotifier): Readable { return { subscribe: writable(value, start).subscribe, }; } -export function writable(value: T, start: StartStopNotifier = noop): WritableStore { +export function writable(value: T, start: StartStopNotifier = noop): Writable { let stop: Unsubscriber; const subscribers: Array> = []; @@ -68,21 +68,27 @@ export function writable(value: T, start: StartStopNotifier = noop): Writa return { set, update, subscribe }; } -export function derived( - stores: ReadableStore | Array>, - fn: (values: T | T[], set?: Subscriber) => T | Unsubscriber | void, - initial_value: T): ReadableStore { +type Stores = Readable | [Readable, ...Array>]; + +type StoresValues = T extends Readable ? U : + { [K in keyof T]: T[K] extends Readable ? U : never }; + +export function derived( + stores: S, + fn: (values: StoresValues, set?: Subscriber) => T | Unsubscriber | void, + initial_value?: T, +): Readable { const single = !Array.isArray(stores); - const stores_array: Array> = single - ? [stores as ReadableStore] - : stores as Array>; + const stores_array: Array> = single + ? [stores as Readable] + : stores as Array>; const auto = fn.length < 2; return readable(initial_value, (set) => { let inited = false; - const values: T[] = []; + const values: StoresValues = [] as StoresValues; let pending = 0; let cleanup = noop; @@ -123,7 +129,7 @@ export function derived( }); } -export function get(store: ReadableStore): T { +export function get(store: Readable): T { let value: T | undefined; store.subscribe((_: T) => value = _)(); return value as T; diff --git a/test/store/index.js b/test/store.ts similarity index 88% rename from test/store/index.js rename to test/store.ts index 5f9176cffb..9b3d5d1788 100644 --- a/test/store/index.js +++ b/test/store.ts @@ -1,5 +1,5 @@ import * as assert from 'assert'; -import { readable, writable, derived, get } from '../../store.js'; +import { readable, writable, derived, get } from '../store'; describe('store', () => { describe('writable', () => { @@ -30,10 +30,10 @@ describe('store', () => { return () => called -= 1; }); - const unsubscribe1 = store.subscribe(() => {}); + const unsubscribe1 = store.subscribe(() => { }); assert.equal(called, 1); - const unsubscribe2 = store.subscribe(() => {}); + const unsubscribe2 = store.subscribe(() => { }); assert.equal(called, 1); unsubscribe1(); @@ -73,7 +73,7 @@ describe('store', () => { set(0); return () => { - tick = () => {}; + tick = () => { }; running = false; }; }); @@ -242,11 +242,29 @@ describe('store', () => { assert.deepEqual(cleaned_up, [2, 3, 4]); }); + + it('allows derived with different types', () => { + const a = writable('one'); + const b = writable(1); + const c = derived([a, b], ([a, b]) => `${a} ${b}`); + + const values: string[] = []; + + const unsubscribe = c.subscribe(value => { + values.push(value); + }); + + a.set('two'); + b.set(2); + assert.deepEqual(values, 'two 2'); + + unsubscribe(); + }); }); describe('get', () => { it('gets the current value of a store', () => { - const store = readable(42, () => {}); + const store = readable(42, () => { }); assert.equal(get(store), 42); }); }); diff --git a/tsconfig.json b/tsconfig.json index 5da2d13a01..fdb7367e05 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -7,8 +7,7 @@ "allowJs": true, "lib": ["es5", "es6", "dom"], "importHelpers": true, - "moduleResolution": "node", - "strict": true + "moduleResolution": "node" }, "include": [ "src" From 643aa41b9aa0fcc2a1ba1566388ec0564a57cee4 Mon Sep 17 00:00:00 2001 From: Emil Tholin Date: Tue, 14 May 2019 13:15:59 +0200 Subject: [PATCH 31/87] Set mutated const variables as reactive dependencies --- src/compile/Component.ts | 4 +++- src/compile/render-dom/index.ts | 2 +- .../reactive-value-mutate-const/_config.js | 17 +++++++++++++++++ .../reactive-value-mutate-const/main.svelte | 9 +++++++++ 4 files changed, 30 insertions(+), 2 deletions(-) create mode 100644 test/runtime/samples/reactive-value-mutate-const/_config.js create mode 100644 test/runtime/samples/reactive-value-mutate-const/main.svelte diff --git a/src/compile/Component.ts b/src/compile/Component.ts index dd41a0a645..259144d691 100644 --- a/src/compile/Component.ts +++ b/src/compile/Component.ts @@ -1114,9 +1114,11 @@ export default class Component { if (!assignee_nodes.has(identifier)) { const { name } = identifier; const owner = scope.find_owner(name); + const component_var = component.var_lookup.get(name); + const is_writable_or_mutated = component_var && (component_var.writable || component_var.mutated); if ( (!owner || owner === component.instance_scope) && - (name[0] === '$' || component.var_lookup.has(name) && component.var_lookup.get(name).writable) + (name[0] === '$' || is_writable_or_mutated) ) { dependencies.add(name); } diff --git a/src/compile/render-dom/index.ts b/src/compile/render-dom/index.ts index 0a0743b2a0..1cd0664ecf 100644 --- a/src/compile/render-dom/index.ts +++ b/src/compile/render-dom/index.ts @@ -364,7 +364,7 @@ export default function dom( } const variable = component.var_lookup.get(n); - return variable && variable.writable; + return variable && (variable.writable || variable.mutated); }) .map(n => `$$dirty.${n}`).join(' || '); diff --git a/test/runtime/samples/reactive-value-mutate-const/_config.js b/test/runtime/samples/reactive-value-mutate-const/_config.js new file mode 100644 index 0000000000..da0a19dd28 --- /dev/null +++ b/test/runtime/samples/reactive-value-mutate-const/_config.js @@ -0,0 +1,17 @@ +export default { + html: ` + +
    {}
    + `, + + async test({ assert, target }) { + const button = target.querySelector('button'); + const click = new window.MouseEvent('click'); + + await button.dispatchEvent(click); + assert.htmlEqual(target.innerHTML, ` + +
    {"foo":42}
    + `); + } +}; diff --git a/test/runtime/samples/reactive-value-mutate-const/main.svelte b/test/runtime/samples/reactive-value-mutate-const/main.svelte new file mode 100644 index 0000000000..403544e5f1 --- /dev/null +++ b/test/runtime/samples/reactive-value-mutate-const/main.svelte @@ -0,0 +1,9 @@ + + + +
    {JSON.stringify(b)}
    + From e45aa0f85f0833ce2daab593425b717baf84149b Mon Sep 17 00:00:00 2001 From: Sander Hahn Date: Wed, 15 May 2019 09:26:54 +0200 Subject: [PATCH 32/87] simplify test --- test/store.ts | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/test/store.ts b/test/store.ts index 9b3d5d1788..f931a841d7 100644 --- a/test/store.ts +++ b/test/store.ts @@ -248,17 +248,11 @@ describe('store', () => { const b = writable(1); const c = derived([a, b], ([a, b]) => `${a} ${b}`); - const values: string[] = []; - - const unsubscribe = c.subscribe(value => { - values.push(value); - }); + assert.deepEqual(get(c), 'one 1'); a.set('two'); b.set(2); - assert.deepEqual(values, 'two 2'); - - unsubscribe(); + assert.deepEqual(get(c), 'two 2'); }); }); From 9cd0b0761b4c6f9954b05bca6d0e82cfbb7fc1d0 Mon Sep 17 00:00:00 2001 From: Emil Tholin Date: Wed, 15 May 2019 11:04:07 +0200 Subject: [PATCH 33/87] Don't get hoisted variable from ctx when using @debug --- src/compile/render-dom/wrappers/DebugTag.ts | 21 +++++--- test/js/samples/debug-hoisted/_config.js | 5 ++ test/js/samples/debug-hoisted/expected.js | 56 +++++++++++++++++++++ test/js/samples/debug-hoisted/input.svelte | 6 +++ 4 files changed, 81 insertions(+), 7 deletions(-) create mode 100644 test/js/samples/debug-hoisted/_config.js create mode 100644 test/js/samples/debug-hoisted/expected.js create mode 100644 test/js/samples/debug-hoisted/input.svelte diff --git a/src/compile/render-dom/wrappers/DebugTag.ts b/src/compile/render-dom/wrappers/DebugTag.ts index 06fef90a62..bdad6d2493 100644 --- a/src/compile/render-dom/wrappers/DebugTag.ts +++ b/src/compile/render-dom/wrappers/DebugTag.ts @@ -25,7 +25,7 @@ export default class DebugTagWrapper extends Wrapper { if (!renderer.options.dev) return; - const { code } = component; + const { code, var_lookup } = component; if (this.node.expressions.length === 0) { // Debug all @@ -50,23 +50,30 @@ export default class DebugTagWrapper extends Wrapper { const condition = Array.from(dependencies).map(d => `changed.${d}`).join(' || '); - const identifiers = this.node.expressions.map(e => e.node.name).join(', '); + const ctx_identifiers = this.node.expressions + .filter(e => { + const looked_up_var = var_lookup.get(e.node.name); + return !(looked_up_var && looked_up_var.hoistable); + }) + .map(e => e.node.name) + .join(', '); + const logged_identifiers = this.node.expressions.map(e => e.node.name).join(', '); block.builders.update.add_block(deindent` if (${condition}) { - const { ${identifiers} } = ctx; - console.${log}({ ${identifiers} }); + const { ${ctx_identifiers} } = ctx; + console.${log}({ ${logged_identifiers} }); debugger; } `); block.builders.create.add_block(deindent` { - const { ${identifiers} } = ctx; - console.${log}({ ${identifiers} }); + const { ${ctx_identifiers} } = ctx; + console.${log}({ ${logged_identifiers} }); debugger; } `); } } -} \ No newline at end of file +} diff --git a/test/js/samples/debug-hoisted/_config.js b/test/js/samples/debug-hoisted/_config.js new file mode 100644 index 0000000000..414b026a97 --- /dev/null +++ b/test/js/samples/debug-hoisted/_config.js @@ -0,0 +1,5 @@ +export default { + options: { + dev: true + } +}; diff --git a/test/js/samples/debug-hoisted/expected.js b/test/js/samples/debug-hoisted/expected.js new file mode 100644 index 0000000000..153f92bad8 --- /dev/null +++ b/test/js/samples/debug-hoisted/expected.js @@ -0,0 +1,56 @@ +/* generated by Svelte vX.Y.Z */ +import { + SvelteComponentDev, + init, + noop, + safe_not_equal +} from "svelte/internal"; + +const file = undefined; + +function create_fragment(ctx) { + return { + c: function create() { + { + const { obj } = ctx; + console.log({ obj, kobzol }); + debugger; + } + }, + + l: function claim(nodes) { + throw new Error("options.hydrate only works if the component was compiled with the `hydratable: true` option"); + }, + + m: noop, + + p: function update(changed, ctx) { + if (changed.obj || changed.kobzol) { + const { obj } = ctx; + console.log({ obj, kobzol }); + debugger; + } + }, + + i: noop, + o: noop, + d: noop + }; +} + +let kobzol = 5; + +function instance($$self) { + let obj = { x: 5 }; + + return { obj }; +} + +class Component extends SvelteComponentDev { + constructor(options) { + super(options); + init(this, options, instance, create_fragment, safe_not_equal, []); + } +} + +export default Component; diff --git a/test/js/samples/debug-hoisted/input.svelte b/test/js/samples/debug-hoisted/input.svelte new file mode 100644 index 0000000000..94d584ccac --- /dev/null +++ b/test/js/samples/debug-hoisted/input.svelte @@ -0,0 +1,6 @@ + + +{@debug obj, kobzol} From 66e39d52d47ecf1ce73b387a531ff37a978f69be Mon Sep 17 00:00:00 2001 From: Hongarc Date: Wed, 15 May 2019 20:53:19 +0700 Subject: [PATCH 34/87] Remove whitespace at end of line --- site/content/examples/10-animations/00-animate/App.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site/content/examples/10-animations/00-animate/App.svelte b/site/content/examples/10-animations/00-animate/App.svelte index e8637c98c3..6f0163e4b8 100644 --- a/site/content/examples/10-animations/00-animate/App.svelte +++ b/site/content/examples/10-animations/00-animate/App.svelte @@ -1,6 +1,6 @@
    - +

    todo

    From 3f312231863237b8240c23775563e95ec4a7ea7d Mon Sep 17 00:00:00 2001 From: Emil Tholin Date: Wed, 15 May 2019 17:26:57 +0200 Subject: [PATCH 36/87] Add error for missing equals after attribute name --- src/parse/state/tag.ts | 7 ++++++- .../samples/attribute-expected-equals/errors.json | 15 +++++++++++++++ .../attribute-expected-equals/input.svelte | 5 +++++ 3 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 test/validator/samples/attribute-expected-equals/errors.json create mode 100644 test/validator/samples/attribute-expected-equals/input.svelte diff --git a/src/parse/state/tag.ts b/src/parse/state/tag.ts index 365085ca08..56195549d8 100644 --- a/src/parse/state/tag.ts +++ b/src/parse/state/tag.ts @@ -358,7 +358,7 @@ function read_attribute(parser: Parser, unique_names: Set) { } } - let name = parser.read_until(/(\s|=|\/|>)/); + let name = parser.read_until(/[\s=\/>"']/); if (!name) return null; let end = parser.index; @@ -383,6 +383,11 @@ function read_attribute(parser: Parser, unique_names: Set) { if (parser.eat('=')) { value = read_attribute_value(parser); end = parser.index; + } else if (parser.match_regex(/["']/)) { + parser.error({ + code: `unexpected-token`, + message: `Expected =` + }, parser.index); } if (type) { diff --git a/test/validator/samples/attribute-expected-equals/errors.json b/test/validator/samples/attribute-expected-equals/errors.json new file mode 100644 index 0000000000..a3fa9d3cac --- /dev/null +++ b/test/validator/samples/attribute-expected-equals/errors.json @@ -0,0 +1,15 @@ +[{ + "code": "unexpected-token", + "message": "Expected =", + "start": { + "line": 5, + "column": 9, + "character": 50 + }, + "end": { + "line": 5, + "column": 9, + "character": 50 + }, + "pos": 50 +}] diff --git a/test/validator/samples/attribute-expected-equals/input.svelte b/test/validator/samples/attribute-expected-equals/input.svelte new file mode 100644 index 0000000000..91f4b0ca7b --- /dev/null +++ b/test/validator/samples/attribute-expected-equals/input.svelte @@ -0,0 +1,5 @@ + + +

    Hello {name}!

    From 98122bc577f4b23ae92bd372f893b8544eb71e34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Terczy=C5=84ski?= Date: Wed, 15 May 2019 20:31:30 +0200 Subject: [PATCH 37/87] Fix link to license --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ac0e4ff366..4d03eca934 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ Cybernetically enhanced web apps: Svelte - + npm version @@ -16,7 +16,7 @@ alt="build status"> - + license

    From 51be7cf8e3d440f9195e17ab7defa789e110a911 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Wed, 15 May 2019 18:04:25 -0400 Subject: [PATCH 38/87] explain how debug tag without args fires on all state changes --- site/content/docs/02-template-syntax.md | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/site/content/docs/02-template-syntax.md b/site/content/docs/02-template-syntax.md index 44256b52e7..5b8a22f9bf 100644 --- a/site/content/docs/02-template-syntax.md +++ b/site/content/docs/02-template-syntax.md @@ -1266,7 +1266,7 @@ The `` element provides a place to specify per-component compile ### @debug ```sv -{@debug variable} +{@debug} ``` ```sv {@debug var1, var2, ..., varN} @@ -1274,7 +1274,9 @@ The `` element provides a place to specify per-component compile --- -The `{@debug ...}` tag offers an alternative to `console.log(...)`. It allows you to inspect the value of a specific variable, but additionally pauses code execution when you have devtools open. +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 + +

    {$x}

    \ No newline at end of file diff --git a/test/server-side-rendering/index.js b/test/server-side-rendering/index.js index 9f67ee06e9..4b648c0591 100644 --- a/test/server-side-rendering/index.js +++ b/test/server-side-rendering/index.js @@ -102,6 +102,8 @@ describe("ssr", () => { delete require.cache[file]; }); + delete global.window; + const compileOptions = Object.assign({ sveltePath }, config.compileOptions, { generate: 'ssr' }); From 53a80524eb685fc4fdfc577801cd2d682c191902 Mon Sep 17 00:00:00 2001 From: Clark Du Date: Thu, 16 May 2019 15:36:13 +0100 Subject: [PATCH 44/87] chore(npm): fix vulnerabilities from npm audit --- package-lock.json | 45 +++++++++++++++++++++------------------------ 1 file changed, 21 insertions(+), 24 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7c7363db2e..bb2b7d7d7e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "svelte", - "version": "3.1.0", + "version": "3.4.0", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -246,15 +246,6 @@ "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", "dev": true }, - "async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.2.tgz", - "integrity": "sha512-H1qVYh1MYhEEFLsP97cVKqCGo7KfCyTt6uEWqsTBr9SO84oK9Uwbyd/yCW+6rKJLHksBNUVWZDAjfS+Ccx0Bbg==", - "dev": true, - "requires": { - "lodash": "^4.17.11" - } - }, "async-limiter": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", @@ -1550,12 +1541,12 @@ "dev": true }, "handlebars": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.1.0.tgz", - "integrity": "sha512-l2jRuU1NAWK6AW5qqcTATWQJvNPEwkM7NEKSiv/gqOsoSQbVoWyqVEY5GS+XPQ88zLNmqASRpzfdm8d79hJS+w==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.1.2.tgz", + "integrity": "sha512-nvfrjqvt9xQ8Z/w0ijewdD/vvWDTOweBUm96NTr66Wfvo1mJenBLwcYmPs3TIBP5ruzYGD7Hx/DaM9RmhroGPw==", "dev": true, "requires": { - "async": "^2.5.0", + "neo-async": "^2.6.0", "optimist": "^0.6.1", "source-map": "^0.6.1", "uglify-js": "^3.1.4" @@ -1996,9 +1987,9 @@ "dev": true }, "js-yaml": { - "version": "3.12.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.1.tgz", - "integrity": "sha512-um46hB9wNOKlwkHgiuyEVAybXBjwFUV0Z/RaHJblRd9DXltue9FTYvzCr9ErQrK9Adz5MU4gHWVaNUfdmrC8qA==", + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", "dev": true, "requires": { "argparse": "^1.0.7", @@ -2448,6 +2439,12 @@ "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", "dev": true }, + "neo-async": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz", + "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==", + "dev": true + }, "nice-try": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", @@ -4188,20 +4185,20 @@ "dev": true }, "uglify-js": { - "version": "3.4.9", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.9.tgz", - "integrity": "sha512-8CJsbKOtEbnJsTyv6LE6m6ZKniqMiFWmm9sRbopbkGs3gMPPfd3Fh8iIA4Ykv5MgaTbqHr4BaoGLJLZNhsrW1Q==", + "version": "3.5.12", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.5.12.tgz", + "integrity": "sha512-KeQesOpPiZNgVwJj8Ge3P4JYbQHUdZzpx6Fahy6eKAYRSV4zhVmLXoC+JtOeYxcHCHTve8RG1ZGdTvpeOUM26Q==", "dev": true, "optional": true, "requires": { - "commander": "~2.17.1", + "commander": "~2.20.0", "source-map": "~0.6.1" }, "dependencies": { "commander": { - "version": "2.17.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz", - "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==", + "version": "2.20.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz", + "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==", "dev": true, "optional": true } From 562f32cf076cad90b523c6ab90f53fb0308a5d43 Mon Sep 17 00:00:00 2001 From: Clark Du Date: Thu, 16 May 2019 16:08:00 +0100 Subject: [PATCH 45/87] refactor: remove unnecessary super.render in style attribute --- src/compile/render-dom/wrappers/Element/StyleAttribute.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/compile/render-dom/wrappers/Element/StyleAttribute.ts b/src/compile/render-dom/wrappers/Element/StyleAttribute.ts index 43524ff372..829d9ac714 100644 --- a/src/compile/render-dom/wrappers/Element/StyleAttribute.ts +++ b/src/compile/render-dom/wrappers/Element/StyleAttribute.ts @@ -17,7 +17,6 @@ export default class StyleAttributeWrapper extends AttributeWrapper { render(block: Block) { const style_props = optimize_style(this.node.chunks); - if (!style_props) return super.render(block); style_props.forEach((prop: StyleProp) => { let value; @@ -93,7 +92,6 @@ function optimize_style(value: Node[]) { } const result = get_style_value(chunks); - if (!result) return null; props.push({ key, value: result.value }); chunks = result.chunks; From c9085b26836cee4302e6fdeed3150d1953dc83a1 Mon Sep 17 00:00:00 2001 From: Clark Du Date: Thu, 16 May 2019 16:33:35 +0100 Subject: [PATCH 46/87] fix: add super.render back --- src/compile/render-dom/wrappers/Element/StyleAttribute.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/compile/render-dom/wrappers/Element/StyleAttribute.ts b/src/compile/render-dom/wrappers/Element/StyleAttribute.ts index 829d9ac714..8d59585cad 100644 --- a/src/compile/render-dom/wrappers/Element/StyleAttribute.ts +++ b/src/compile/render-dom/wrappers/Element/StyleAttribute.ts @@ -17,6 +17,7 @@ export default class StyleAttributeWrapper extends AttributeWrapper { render(block: Block) { const style_props = optimize_style(this.node.chunks); + if (!style_props) return super.render(block); style_props.forEach((prop: StyleProp) => { let value; From 298ae8ec236ee778710b0c1bf0858541b9191667 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Thu, 16 May 2019 11:43:08 -0400 Subject: [PATCH 47/87] -> v3.4.1 --- CHANGELOG.md | 5 +++++ package.json | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6b609578b6..cf044812a2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Svelte changelog +## 3.4.1 + +* Handle non-falsy non-function return values from derivers ([#2780](https://github.com/sveltejs/svelte/issues/2780)) +* Allow `spring` to work server-side ([#2773](https://github.com/sveltejs/svelte/issues/2773)) + ## 3.4.0 * Allow custom element to be defined without a `tag` ([#2417](https://github.com/sveltejs/svelte/issues/2417)) diff --git a/package.json b/package.json index 26f357ccd8..12a5cac083 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "svelte", - "version": "3.4.0", + "version": "3.4.1", "description": "Cybernetically enhanced web apps", "module": "index.mjs", "main": "index", From 393d948f873ca379a53865602bce09e9a4c48db6 Mon Sep 17 00:00:00 2001 From: Jacky Efendi Date: Fri, 17 May 2019 10:11:23 +0700 Subject: [PATCH 48/87] Add Tokopedia logo --- .../routes/_components/WhosUsingSvelte.svelte | 1 + site/static/organisations/tokopedia.png | Bin 0 -> 32383 bytes 2 files changed, 1 insertion(+) create mode 100644 site/static/organisations/tokopedia.png diff --git a/site/src/routes/_components/WhosUsingSvelte.svelte b/site/src/routes/_components/WhosUsingSvelte.svelte index 21c57d065a..65d818a8bb 100644 --- a/site/src/routes/_components/WhosUsingSvelte.svelte +++ b/site/src/routes/_components/WhosUsingSvelte.svelte @@ -55,5 +55,6 @@ Razorpay logo Stone Payments logo Thunderdome logo + Tokopedia logo + your company?
    diff --git a/site/static/organisations/tokopedia.png b/site/static/organisations/tokopedia.png new file mode 100644 index 0000000000000000000000000000000000000000..bc5231cd5ac5f3e053ff3de9b0fd49a6615bda0e GIT binary patch literal 32383 zcmZU)1yr0r&^NlfxVsgH;tnk?i$ifJP$<^oUSM%|iaW&@Dbf~qr&MrQyttNKr0C*y z_y4~4-1D99?s?AUNhX>6W-`end6JL1+NuP&&u{?%0D-!il0E={1p@$pZP;k2l;uI$ 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 literal 0 HcmV?d00001 From c15d7ea2e159b864ec63d666f54cbfee09c6ef67 Mon Sep 17 00:00:00 2001 From: trbrc Date: Fri, 17 May 2019 13:19:51 +0200 Subject: [PATCH 49/87] Docs: Exporting function expression vs declaration Current docs give the impression that functions can not be default values for props. Suggestion to make the distinction between expressions and declarations clearer. --- site/content/docs/01-component-format.md | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/site/content/docs/01-component-format.md b/site/content/docs/01-component-format.md index 1472ff3d6c..ddd2667075 100644 --- a/site/content/docs/01-component-format.md +++ b/site/content/docs/01-component-format.md @@ -47,11 +47,14 @@ Svelte uses the `export` keyword to mark a variable declaration as a *property* // Values that are passed in as props // are immediately available console.log(foo, bar); - - // function declarations cannot be set externally, - // but can be accessed from outside - export function instanceMethod() { - alert(foo); + + // Function expressions can also be props + export let format = (number) => (number.toFixed(2)); + + // Function declarations are added as methods + // on the component, rather than props + export function greetMethod() { + alert(`I'm a <${this.constructor.name}>!`); } // you can also use export { ... as ... } to have From 2cb81f0d5d9cbe25a629758c00f14224b4d6bd81 Mon Sep 17 00:00:00 2001 From: Sander Hahn Date: Fri, 17 May 2019 14:15:52 +0200 Subject: [PATCH 50/87] add docstrings to store --- src/store.ts | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/src/store.ts b/src/store.ts index 1f00503af2..ef86130f56 100644 --- a/src/store.ts +++ b/src/store.ts @@ -1,32 +1,64 @@ import { run_all, noop, safe_not_equal, is_function } from './internal/utils'; +/** Callback to inform of a value updates. */ type Subscriber = (value: T) => void; +/** Unsubscribes from value updates. */ type Unsubscriber = () => void; +/** Callback to update a value. */ type Updater = (value: T) => T; +/** Cleanup logic callback. */ type Invalidater = (value?: T) => void; +/** Start and stop notification callbacks. */ type StartStopNotifier = (set: Subscriber) => Unsubscriber | void; +/** Readable interface for subscribing. */ export interface Readable { + /** + * Subscribe on value changes. + * @param run subscription callback + * @param invalidate cleanup callback + */ subscribe(run: Subscriber, invalidate?: Invalidater): Unsubscriber; } +/** Writable interface for both updating and subscribing. */ export interface Writable extends Readable { + /** + * Set value and inform subscribers. + * @param value to set + */ set(value: T): void; + + /** + * Update value using callback and inform subscribers. + * @param updater callback + */ update(updater: Updater): void; } +/** Pair of subscriber and invalidator. */ type SubscribeInvalidateTuple = [Subscriber, Invalidater]; +/** + * Creates a `Readable` store that allows reading by subscription. + * @param value initial value + * @param start start and stop notifications for subscriptions + */ export function readable(value: T, start: StartStopNotifier): Readable { return { subscribe: writable(value, start).subscribe, }; } +/** + * Create a `Writable` store that allows both updating and reading by subscription. + * @param value initial value + * @param start start and stop notifications for subscriptions + */ export function writable(value: T, start: StartStopNotifier = noop): Writable { let stop: Unsubscriber; const subscribers: Array> = []; @@ -68,11 +100,20 @@ export function writable(value: T, start: StartStopNotifier = noop): Writa return { set, update, subscribe }; } +/** One or more `Readable`s. */ type Stores = Readable | [Readable, ...Array>]; +/** One or more values from `Readable` stores. */ type StoresValues = T extends Readable ? U : { [K in keyof T]: T[K] extends Readable ? U : never }; +/** + * Derived value store by synchronizing one or more readable stores and + * applying an aggration function over its input values. + * @param stores input stores + * @param fn function callback that aggregates the values + * @param initial_value when used asynchronously + */ export function derived( stores: S, fn: (values: StoresValues, set?: Subscriber) => T | Unsubscriber | void, @@ -129,6 +170,10 @@ export function derived( }); } +/** + * Get the current value from a store by subscribing and immediately unsubscribing. + * @param store readable + */ export function get(store: Readable): T { let value: T | undefined; store.subscribe((_: T) => value = _)(); From 335f77cc4806bd911b66c3e733bef193e42c5a84 Mon Sep 17 00:00:00 2001 From: Christian Kaisermann Date: Fri, 17 May 2019 15:23:47 -0300 Subject: [PATCH 51/87] =?UTF-8?q?fix:=20=F0=9F=90=9B=20data=20attributes?= =?UTF-8?q?=20without=20value=20outputting=20as=20"true"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/compile/render-dom/wrappers/Element/Attribute.ts | 2 +- .../runtime/samples/attribute-dataset-without-value/_config.js | 3 +++ .../samples/attribute-dataset-without-value/main.svelte | 1 + 3 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 test/runtime/samples/attribute-dataset-without-value/_config.js create mode 100644 test/runtime/samples/attribute-dataset-without-value/main.svelte diff --git a/src/compile/render-dom/wrappers/Element/Attribute.ts b/src/compile/render-dom/wrappers/Element/Attribute.ts index 9841f4e85d..5007724f34 100644 --- a/src/compile/render-dom/wrappers/Element/Attribute.ts +++ b/src/compile/render-dom/wrappers/Element/Attribute.ts @@ -187,7 +187,7 @@ export default class AttributeWrapper { : property_name ? `${element.var}.${property_name} = ${value};` : is_dataset - ? `${element.var}.dataset.${camel_case_name} = ${value};` + ? `${element.var}.dataset.${camel_case_name} = ${value === true ? '""' : value};` : `${method}(${element.var}, "${name}", ${value === true ? '""' : value});` ); diff --git a/test/runtime/samples/attribute-dataset-without-value/_config.js b/test/runtime/samples/attribute-dataset-without-value/_config.js new file mode 100644 index 0000000000..934f44eb06 --- /dev/null +++ b/test/runtime/samples/attribute-dataset-without-value/_config.js @@ -0,0 +1,3 @@ +export default { + html: '
    ', +}; diff --git a/test/runtime/samples/attribute-dataset-without-value/main.svelte b/test/runtime/samples/attribute-dataset-without-value/main.svelte new file mode 100644 index 0000000000..ed7d532652 --- /dev/null +++ b/test/runtime/samples/attribute-dataset-without-value/main.svelte @@ -0,0 +1 @@ +
    From 481ac14e7e504f8ff5c0d487262e436b426e4505 Mon Sep 17 00:00:00 2001 From: Peter Varholak Date: Fri, 17 May 2019 11:25:44 -0700 Subject: [PATCH 52/87] Fix setup command in getting started blog --- .../content/blog/2017-08-07-the-easiest-way-to-get-started.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/site/content/blog/2017-08-07-the-easiest-way-to-get-started.md b/site/content/blog/2017-08-07-the-easiest-way-to-get-started.md index 596c469433..9d4c661615 100644 --- a/site/content/blog/2017-08-07-the-easiest-way-to-get-started.md +++ b/site/content/blog/2017-08-07-the-easiest-way-to-get-started.md @@ -44,9 +44,11 @@ In the terminal, you can instantly create a new project like so: npx degit sveltejs/template my-svelte-project cd my-svelte-project npm install -npm run dev & open http://localhost:5000 +npm run dev ``` +This will create a new project in the `my-svelte-project` directory, install its dependencies, and start a server on http://localhost:5000. + Once you've tinkered a bit and understood how everything fits together, you can fork [sveltejs/template](https://github.com/sveltejs/template) and start doing this instead: ```bash From 2255aadf369a36fa64fdf4be44d003b06b852a07 Mon Sep 17 00:00:00 2001 From: Sander Hahn Date: Fri, 17 May 2019 19:15:18 +0200 Subject: [PATCH 53/87] Fixes for #2799 --- site/src/routes/index.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site/src/routes/index.svelte b/site/src/routes/index.svelte index 539f522b4e..cbbdf43e95 100644 --- a/site/src/routes/index.svelte +++ b/site/src/routes/index.svelte @@ -89,7 +89,7 @@ npx degit sveltejs/template my-svelte-project cd my-svelte-project npm install -npm run dev & open http://localhost:5000 +npm run dev

    See the quickstart guide for more information.

    From 7265fd4e834d57ad266aae2953b83116861c8a2e Mon Sep 17 00:00:00 2001 From: Conduitry Date: Sat, 18 May 2019 09:43:50 -0400 Subject: [PATCH 54/87] site: fix binary template files in REPL zips (#2812) --- site/scripts/build-svelte-app-json.js | 11 ----------- site/scripts/update_template.js | 7 +++++-- 2 files changed, 5 insertions(+), 13 deletions(-) delete mode 100644 site/scripts/build-svelte-app-json.js diff --git a/site/scripts/build-svelte-app-json.js b/site/scripts/build-svelte-app-json.js deleted file mode 100644 index 59a4b4a07b..0000000000 --- a/site/scripts/build-svelte-app-json.js +++ /dev/null @@ -1,11 +0,0 @@ -const fs = require('fs'); - -const files = []; - -for (const path of process.argv.slice(2)) { - if (!path.includes('/.')) { - files.push({ path: path.slice(19), data: fs.readFileSync(path).toString() }); - } -} - -fs.writeFileSync('static/svelte-app.json', JSON.stringify(files)); diff --git a/site/scripts/update_template.js b/site/scripts/update_template.js index 814d402f5e..9d897c064f 100644 --- a/site/scripts/update_template.js +++ b/site/scripts/update_template.js @@ -1,7 +1,7 @@ const sh = require('shelljs'); const fs = require('fs'); -sh.cd(__dirname+'/../'); +sh.cd(__dirname + '/../'); // fetch svelte app sh.rm('-rf','scripts/svelte-app'); @@ -16,7 +16,10 @@ const appPath = 'scripts/svelte-app'; const files = []; for (const path of sh.find(appPath).filter(p => fs.lstatSync(p).isFile()) ) { - files.push({ path: path.slice(appPath.length + 1), data: fs.readFileSync(path).toString() }); + const bytes = fs.readFileSync(path); + const string = bytes.toString(); + const data = bytes.compare(Buffer.from(string)) === 0 ? string : [...bytes]; + files.push({ path: path.slice(appPath.length + 1), data }); } fs.writeFileSync('static/svelte-app.json', JSON.stringify(files)); \ No newline at end of file From a6d75b85e6a8e93182f94e7bb768307995e878ef Mon Sep 17 00:00:00 2001 From: Conduitry Date: Sun, 19 May 2019 07:17:30 -0400 Subject: [PATCH 55/87] site: improve instructions for using local copy of Svelte --- site/README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/site/README.md b/site/README.md index c438bda5ca..59380feffc 100644 --- a/site/README.md +++ b/site/README.md @@ -13,7 +13,11 @@ Start the server with `npm run dev`, and navigate to [localhost:3000](http://loc ## Using a local copy of Svelte -By default, the REPL will fetch the most recent version of Svelte from https://unpkg.com/svelte. To use the local copy of the compiler and runtime from this repo, you can navigate to [localhost:3000/repl?version=local](http://localhost:3000/repl?version=local). To produce the proper browser-compatible UMD build, you will need to run `npm run build` with the `PUBLISH` environment variable set (to any non-empty string). +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. + +To produce the proper browser-compatible UMD build of the compiler, you will need to run `npm run build` (or `npm run dev`) in the root of this repository with the `PUBLISH` environment variable set to any non-empty string. + +Then visit the REPL at [localhost:3000/repl?version=local](http://localhost:3000/repl?version=local). ## REPL GitHub integration From 7ebf3477a4a6570fa2c246eb72ab779ae4142cac Mon Sep 17 00:00:00 2001 From: Conduitry Date: Sun, 19 May 2019 16:00:21 -0400 Subject: [PATCH 56/87] site: bump @sveltejs/svelte-repl --- site/package-lock.json | 6 +++--- site/package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/site/package-lock.json b/site/package-lock.json index 1fce7fa115..a905818214 100644 --- a/site/package-lock.json +++ b/site/package-lock.json @@ -1362,9 +1362,9 @@ } }, "@sveltejs/svelte-repl": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/@sveltejs/svelte-repl/-/svelte-repl-0.0.10.tgz", - "integrity": "sha512-PYXCN8OC2q3WzwtMcbFinLGzFI7RlD3cHqjkUuQWDaIMHriKYuALun4H/FxP8w3B3hNe9OBprgGmBzlkPuGEJw==", + "version": "0.0.11", + "resolved": "https://registry.npmjs.org/@sveltejs/svelte-repl/-/svelte-repl-0.0.11.tgz", + "integrity": "sha512-F284f8qaUs1rp8akqWXcB6oovlaso7qmsUz1rqm80FwUKLffjYIWy2a1p6+Yo1kRy6Q+fW8kj21JLEqv7pjOwA==", "dev": true, "requires": { "codemirror": "^5.45.0", diff --git a/site/package.json b/site/package.json index f5ef1ba258..70748dad77 100644 --- a/site/package.json +++ b/site/package.json @@ -38,7 +38,7 @@ "@babel/runtime": "^7.4.4", "@sindresorhus/slugify": "^0.9.1", "@sveltejs/site-kit": "^1.0.4", - "@sveltejs/svelte-repl": "0.0.10", + "@sveltejs/svelte-repl": "0.0.11", "degit": "^2.1.3", "dotenv": "^8.0.0", "eslint-plugin-svelte3": "^1.0.0", From 1e919113c1cb96417d1bca4664ddc262fd12318c Mon Sep 17 00:00:00 2001 From: Conduitry Date: Mon, 20 May 2019 10:22:01 -0400 Subject: [PATCH 57/87] site: document additional arguments in svelte.walk --- site/content/docs/04-compile-time.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/site/content/docs/04-compile-time.md b/site/content/docs/04-compile-time.md index b019b9437b..c219bae497 100644 --- a/site/content/docs/04-compile-time.md +++ b/site/content/docs/04-compile-time.md @@ -308,8 +308,8 @@ const { code } = svelte.preprocess(source, [ ```js walk(ast: Node, { - enter(node: Node, parent: Node)?: void, - leave(node: Node, parent: Node)?: void + enter(node: Node, parent: Node, prop: string, index: number)?: void, + leave(node: Node, parent: Node, prop: string, index: number)?: void }) ``` @@ -323,13 +323,13 @@ The walker takes an abstract syntax tree to walk and an object with two optional ```js const svelte = require('svelte/compiler'); svelte.walk(ast, { - enter(node, parent) { + enter(node, parent, prop, index) { do_something(node); if (should_skip_children(node)) { this.skip(); } }, - leave(node, parent) { + leave(node, parent, prop, index) { do_something_else(node); } }); From 394a166a4198ab27c4a2f3b51b042e1830c6bb09 Mon Sep 17 00:00:00 2001 From: Emanuele Date: Mon, 20 May 2019 18:46:27 +0100 Subject: [PATCH 58/87] docs: multiple event listeners on single node (#2825) --- site/content/docs/02-template-syntax.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/site/content/docs/02-template-syntax.md b/site/content/docs/02-template-syntax.md index 5b8a22f9bf..167d1fa3a2 100644 --- a/site/content/docs/02-template-syntax.md +++ b/site/content/docs/02-template-syntax.md @@ -351,6 +351,24 @@ If the `on:` directive is used without a value, the component will *forward* the ``` +--- + +It's possible to have multiple event listeners for the same event: + +```html + + + +``` ### Component events From 0247cca84a850f86dd65f0f698b93cf9aa7a379e Mon Sep 17 00:00:00 2001 From: Colin Casey Date: Mon, 20 May 2019 17:05:57 -0300 Subject: [PATCH 59/87] Allow custom element to be declared with no tag and no options --- src/compile/Component.ts | 2 +- .../samples/no-svelte-options/_config.js | 17 +++++++++++++++++ .../samples/no-svelte-options/main.svelte | 5 +++++ .../samples/no-svelte-options/test.js | 12 ++++++++++++ 4 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 test/custom-elements/samples/no-svelte-options/_config.js create mode 100644 test/custom-elements/samples/no-svelte-options/main.svelte create mode 100644 test/custom-elements/samples/no-svelte-options/test.js diff --git a/src/compile/Component.ts b/src/compile/Component.ts index 86b43c1b64..a429db41f6 100644 --- a/src/compile/Component.ts +++ b/src/compile/Component.ts @@ -153,7 +153,7 @@ export default class Component { if (compile_options.customElement) { if (this.component_options.tag === undefined && compile_options.tag === undefined) { - const svelteOptions = ast.html.children.find(child => child.name === 'svelte:options'); + const svelteOptions = ast.html.children.find(child => child.name === 'svelte:options') || { start: 0, end: 0 }; this.warn(svelteOptions, { code: 'custom-element-no-tag', message: `No custom element 'tag' option was specified. To automatically register a custom element, specify a name with a hyphen in it, e.g. . To hide this warning, use ` diff --git a/test/custom-elements/samples/no-svelte-options/_config.js b/test/custom-elements/samples/no-svelte-options/_config.js new file mode 100644 index 0000000000..e45582a127 --- /dev/null +++ b/test/custom-elements/samples/no-svelte-options/_config.js @@ -0,0 +1,17 @@ +export default { + warnings: [{ + code: "custom-element-no-tag", + message: "No custom element 'tag' option was specified. To automatically register a custom element, specify a name with a hyphen in it, e.g. . To hide this warning, use ", + pos: 0, + start: { + character: 0, + column: 0, + line: 1 + }, + end: { + character: 0, + column: 0, + line: 1 + } + }] +}; diff --git a/test/custom-elements/samples/no-svelte-options/main.svelte b/test/custom-elements/samples/no-svelte-options/main.svelte new file mode 100644 index 0000000000..538dc970e9 --- /dev/null +++ b/test/custom-elements/samples/no-svelte-options/main.svelte @@ -0,0 +1,5 @@ + + +

    Hello {name}!

    diff --git a/test/custom-elements/samples/no-svelte-options/test.js b/test/custom-elements/samples/no-svelte-options/test.js new file mode 100644 index 0000000000..c77f035088 --- /dev/null +++ b/test/custom-elements/samples/no-svelte-options/test.js @@ -0,0 +1,12 @@ +import * as assert from 'assert'; +import CustomElement from './main.svelte'; + +export default function (target) { + customElements.define('no-tag', CustomElement); + target.innerHTML = ``; + + const el = target.querySelector('no-tag'); + const h1 = el.shadowRoot.querySelector('h1'); + + assert.equal(h1.textContent, 'Hello world!'); +} From 832259f952fa818ed7ce9d0daffa3fd17e5a51f8 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Mon, 20 May 2019 21:13:24 -0400 Subject: [PATCH 60/87] Update store.ts --- src/store.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/store.ts b/src/store.ts index ef86130f56..b0ee41fc8d 100644 --- a/src/store.ts +++ b/src/store.ts @@ -109,7 +109,7 @@ type StoresValues = T extends Readable ? U : /** * Derived value store by synchronizing one or more readable stores and - * applying an aggration function over its input values. + * applying an aggregation function over its input values. * @param stores input stores * @param fn function callback that aggregates the values * @param initial_value when used asynchronously From 4f324ce1cfda2c980fc6da6652b8b35912e25455 Mon Sep 17 00:00:00 2001 From: Rai Talha Rehman Date: Tue, 21 May 2019 06:16:31 +0500 Subject: [PATCH 61/87] update clone with https (#2787) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4d03eca934..7d0af8ac2e 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ Pull requests are encouraged and always welcome. [Pick an issue](https://github. To install and work on Svelte locally: ```bash -git clone git@github.com:sveltejs/svelte.git +git clone https://github.com/sveltejs/svelte.git cd svelte npm install ``` From a0b876f99f8f5799f684a243999964078352734d Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Mon, 20 May 2019 22:13:34 -0400 Subject: [PATCH 62/87] -> v3.4.2 --- CHANGELOG.md | 6 ++++++ package.json | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cf044812a2..02d42ddc8c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Svelte changelog +## 3.4.2 + +* Use empty string for empty data attributes ([#2804](https://github.com/sveltejs/svelte/pull/2804)) +* Support `customElement: true` with no `` ([#2821](https://github.com/sveltejs/svelte/issues/2821)) +* Add docstrings to `svelte/store` ([#2795](https://github.com/sveltejs/svelte/pull/2795)) + ## 3.4.1 * Handle non-falsy non-function return values from derivers ([#2780](https://github.com/sveltejs/svelte/issues/2780)) diff --git a/package.json b/package.json index 12a5cac083..90ec6d27ec 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "svelte", - "version": "3.4.1", + "version": "3.4.2", "description": "Cybernetically enhanced web apps", "module": "index.mjs", "main": "index", From d548a5a5f40451331610c51c0bd9319b69bb3c61 Mon Sep 17 00:00:00 2001 From: Conduitry Date: Tue, 21 May 2019 00:20:25 -0400 Subject: [PATCH 63/87] site: bump sapper --- site/package-lock.json | 54 ++++++++++++++++-------------------------- site/package.json | 2 +- 2 files changed, 21 insertions(+), 35 deletions(-) diff --git a/site/package-lock.json b/site/package-lock.json index a905818214..b61cee722e 100644 --- a/site/package-lock.json +++ b/site/package-lock.json @@ -2556,26 +2556,18 @@ "dev": true }, "html-minifier": { - "version": "3.5.21", - "resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-3.5.21.tgz", - "integrity": "sha512-LKUKwuJDhxNa3uf/LPR/KVjm/l3rBqtYeCOAekvG8F1vItxMUpueGd94i/asDDr8/1u7InxzFA5EeGjhhG5mMA==", - "dev": true, - "requires": { - "camel-case": "3.0.x", - "clean-css": "4.2.x", - "commander": "2.17.x", - "he": "1.2.x", - "param-case": "2.1.x", - "relateurl": "0.2.x", - "uglify-js": "3.4.x" - }, - "dependencies": { - "commander": { - "version": "2.17.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz", - "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==", - "dev": true - } + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-4.0.0.tgz", + "integrity": "sha512-aoGxanpFPLg7MkIl/DDFYtb0iWz7jMFGqFhvEDZga6/4QTjneiD8I/NXL1x5aaoCp7FSIT6h/OhykDdPsbtMig==", + "dev": true, + "requires": { + "camel-case": "^3.0.0", + "clean-css": "^4.2.1", + "commander": "^2.19.0", + "he": "^1.2.0", + "param-case": "^2.1.1", + "relateurl": "^0.2.7", + "uglify-js": "^3.5.1" } }, "http-link-header": { @@ -4210,12 +4202,12 @@ } }, "sapper": { - "version": "0.26.1", - "resolved": "https://registry.npmjs.org/sapper/-/sapper-0.26.1.tgz", - "integrity": "sha512-ogc0C/RA+L2O6ymdVsNN9kgWUYEb/toOsT7uMQhqBjI98nfNIONRSYW1ne+US0vZHPxyqz0lXE8v0BSizcDJcg==", + "version": "0.27.1", + "resolved": "https://registry.npmjs.org/sapper/-/sapper-0.27.1.tgz", + "integrity": "sha512-RH0K1uQ3zJ1IXvowxr2SuboGXV69q22KaPMhhoM5VNDv9fsUlVHtluZE8WTcGxckiO2L1xFfgM7v/aINkSZpcw==", "dev": true, "requires": { - "html-minifier": "^3.5.21", + "html-minifier": "^4.0.0", "http-link-header": "^1.0.2", "shimport": "^1.0.0", "sourcemap-codec": "^1.4.4", @@ -4808,21 +4800,15 @@ } }, "uglify-js": { - "version": "3.4.10", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.10.tgz", - "integrity": "sha512-Y2VsbPVs0FIshJztycsO2SfPk7/KAF/T72qzv9u5EpQ4kB2hQoHlhNQTsNyy6ul7lQtqJN/AoWeS23OzEiEFxw==", + "version": "3.5.14", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.5.14.tgz", + "integrity": "sha512-dgyjIw8KFK6AyVl5vm2tEqPewv5TKGEiiVFLI1LbF+oHua/Njd8tZk3lIbF1AWU1rNdEg7scaceADb4zqCcWXg==", "dev": true, "requires": { - "commander": "~2.19.0", + "commander": "~2.20.0", "source-map": "~0.6.1" }, "dependencies": { - "commander": { - "version": "2.19.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.19.0.tgz", - "integrity": "sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==", - "dev": true - }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", diff --git a/site/package.json b/site/package.json index 70748dad77..d9de5a217e 100644 --- a/site/package.json +++ b/site/package.json @@ -56,7 +56,7 @@ "rollup-plugin-replace": "^2.2.0", "rollup-plugin-svelte": "^5.0.3", "rollup-plugin-terser": "^4.0.4", - "sapper": "^0.26.0", + "sapper": "^0.27.1", "shelljs": "^0.8.3", "svelte": "^3.0.0" }, From b1a24c853b571a3ee1f1ec78afa6baee9a299f93 Mon Sep 17 00:00:00 2001 From: Bogdan Savluk Date: Tue, 21 May 2019 17:51:36 +0200 Subject: [PATCH 64/87] ignore .idea folder --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 7aa75b29f4..3d1322c33e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +.idea .DS_Store .nyc_output node_modules From 6fdaa803c77a6bb1d0eb5c20906cc2783da430da Mon Sep 17 00:00:00 2001 From: Bogdan Savluk Date: Tue, 21 May 2019 17:54:06 +0200 Subject: [PATCH 65/87] improve parser typings --- src/interfaces.ts | 45 ++++++++++++++++++++++++++++++++++-- src/parse/read/expression.ts | 9 ++++---- src/parse/state/tag.ts | 14 +++++------ 3 files changed, 55 insertions(+), 13 deletions(-) diff --git a/src/interfaces.ts b/src/interfaces.ts index 68fef7472e..90ee60d1be 100644 --- a/src/interfaces.ts +++ b/src/interfaces.ts @@ -1,10 +1,51 @@ -export interface Node { +interface BaseNode { start: number; end: number; type: string; + children?: Node[]; [prop_name: string]: any; } +export interface Text extends BaseNode { + type: 'Text', + data: string; +} + +export interface MustacheTag extends BaseNode { + type: 'MustacheTag', + expresion: Node; +} + +export type DirectiveType = 'Action' + | 'Animation' + | 'Binding' + | 'Class' + | 'EventHandler' + | 'Let' + | 'Ref' + | 'Transition'; + +interface BaseDirective extends BaseNode { + type: DirectiveType; + expression: null|Node; + name: string; + modifiers: string[] +} + +export interface Transition extends BaseDirective{ + type: 'Transition', + intro: boolean; + outro: boolean; +} + +export type Directive = BaseDirective | Transition; + +export type Node = Text + | MustacheTag + | BaseNode + | Directive + | Transition; + export interface Parser { readonly template: string; readonly filename?: string; @@ -92,4 +133,4 @@ export interface Var { initialised?: boolean; hoistable?: boolean; subscribable?: boolean; -} \ No newline at end of file +} diff --git a/src/parse/read/expression.ts b/src/parse/read/expression.ts index 4d1de89fe7..615f270112 100644 --- a/src/parse/read/expression.ts +++ b/src/parse/read/expression.ts @@ -1,9 +1,10 @@ import { parse_expression_at } from '../acorn'; import { Parser } from '../index'; +import { Identifier, Node, SimpleLiteral } from 'estree'; const literals = new Map([['true', true], ['false', false], ['null', null]]); -export default function read_expression(parser: Parser) { +export default function read_expression(parser: Parser): Node { const start = parser.index; const name = parser.read_until(/\s*}/); @@ -17,7 +18,7 @@ export default function read_expression(parser: Parser) { end, value: literals.get(name), raw: name, - }; + } as SimpleLiteral; } return { @@ -25,7 +26,7 @@ export default function read_expression(parser: Parser) { start, end: start + name.length, name, - }; + } as Identifier; } parser.index = start; @@ -34,7 +35,7 @@ export default function read_expression(parser: Parser) { const node = parse_expression_at(parser.template, parser.index); parser.index = node.end; - return node; + return node as Node; } catch (err) { parser.acorn_error(err); } diff --git a/src/parse/state/tag.ts b/src/parse/state/tag.ts index 56195549d8..f7f5a93574 100644 --- a/src/parse/state/tag.ts +++ b/src/parse/state/tag.ts @@ -4,7 +4,7 @@ import read_style from '../read/style'; import { decode_character_references } from '../utils/html'; import { is_void } from '../../utils/names'; import { Parser } from '../index'; -import { Node } from '../../interfaces'; +import { Directive, DirectiveType, Node, Text } from '../../interfaces'; import fuzzymatch from '../../utils/fuzzymatch'; import list from '../../utils/list'; @@ -401,7 +401,7 @@ function read_attribute(parser: Parser, unique_names: Set) { } if (value[0]) { - if (value.length > 1 || value[0].type === 'Text') { + if ((value as Array).length > 1 || value[0].type === 'Text') { parser.error({ code: `invalid-directive-value`, message: `Directive value must be a JavaScript expression enclosed in curly braces` @@ -409,7 +409,7 @@ function read_attribute(parser: Parser, unique_names: Set) { } } - const directive = { + const directive: Directive = { start, end, type, @@ -445,7 +445,7 @@ function read_attribute(parser: Parser, unique_names: Set) { }; } -function get_directive_type(name) { +function get_directive_type(name: string):DirectiveType { if (name === 'use') return 'Action'; if (name === 'animate') return 'Animation'; if (name === 'bind') return 'Binding'; @@ -471,15 +471,15 @@ function read_attribute_value(parser: Parser) { return value; } -function read_sequence(parser: Parser, done: () => boolean) { - let current_chunk: Node = { +function read_sequence(parser: Parser, done: () => boolean): Node[] { + let current_chunk: Text = { start: parser.index, end: null, type: 'Text', data: '', }; - const chunks = []; + const chunks: Node[] = []; while (parser.index < parser.template.length) { const index = parser.index; From b7ec99e8c7442c5ef85fde2e4e3382e48fd2ecd8 Mon Sep 17 00:00:00 2001 From: Bogdan Savluk Date: Tue, 21 May 2019 20:55:04 +0200 Subject: [PATCH 66/87] fix compile/nodes typings --- src/compile/nodes/Attribute.ts | 9 +++- src/compile/nodes/AwaitBlock.ts | 1 + src/compile/nodes/Binding.ts | 1 + src/compile/nodes/CatchBlock.ts | 1 + src/compile/nodes/DebugTag.ts | 3 +- src/compile/nodes/EachBlock.ts | 17 +++++-- src/compile/nodes/Element.ts | 16 +++--- src/compile/nodes/ElseBlock.ts | 3 +- src/compile/nodes/EventHandler.ts | 3 +- src/compile/nodes/Fragment.ts | 6 ++- src/compile/nodes/Head.ts | 1 - src/compile/nodes/InlineComponent.ts | 3 +- src/compile/nodes/MustacheTag.ts | 4 +- src/compile/nodes/PendingBlock.ts | 2 +- src/compile/nodes/RawMustacheTag.ts | 4 +- src/compile/nodes/Slot.ts | 8 +-- src/compile/nodes/Text.ts | 8 +-- src/compile/nodes/ThenBlock.ts | 1 + src/compile/nodes/Title.ts | 10 ++-- src/compile/nodes/interfaces.ts | 62 +++++++++++++++++++++++ src/compile/nodes/shared/AbstractBlock.ts | 3 +- src/compile/nodes/shared/Expression.ts | 13 +++-- src/compile/nodes/shared/Node.ts | 12 +++-- src/compile/nodes/shared/Tag.ts | 3 +- src/compile/nodes/shared/TemplateScope.ts | 3 +- src/compile/nodes/shared/map_children.ts | 8 +-- src/compile/utils/add_to_set.ts | 5 +- src/compile/utils/scope.ts | 4 +- src/compile/utils/stringify_attribute.ts | 5 +- 29 files changed, 163 insertions(+), 56 deletions(-) create mode 100644 src/compile/nodes/interfaces.ts 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..aa7c14a679 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; } @@ -249,11 +250,11 @@ export default class Element extends Node { if (this.name === 'figure') { const children = this.children.filter(node => { if (node.type === 'Comment') return false; - if (node.type === 'Text') return /\S/.test(node.data); + if (node.type === 'Text') return /\S/.test((node as Text).data ); 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`, @@ -387,7 +391,7 @@ export default class Element extends Node { let ancestor = this.parent; do { if (ancestor.type === 'InlineComponent') break; - if (ancestor.type === 'Element' && /-/.test(ancestor.name)) break; + if (ancestor.type === 'Element' && /-/.test((ancestor as Element).name)) break; if (ancestor.type === 'IfBlock' || ancestor.type === 'EachBlock') { const type = ancestor.type === 'IfBlock' ? 'if' : 'each'; 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..a3b9241ce2 100644 --- a/src/compile/nodes/Text.ts +++ b/src/compile/nodes/Text.ts @@ -1,20 +1,22 @@ import Node from './shared/Node'; import Component from '../Component'; import TemplateScope from './shared/TemplateScope'; +import { INode } from './interfaces'; +import Element from './Element'; 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; if (!component.component_options.preserveWhitespace && !/\S/.test(info.data)) { let node = parent; while (node) { - if (node.type === 'Element' && node.name === 'pre') { + if (node.type === 'Element' && (node as Element).name === 'pre') { return; } node = node.parent; @@ -23,4 +25,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..4c459c181f 100644 --- a/src/compile/nodes/Title.ts +++ b/src/compile/nodes/Title.ts @@ -1,12 +1,14 @@ 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 + should_cache: boolean; + children: Children; - 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 +35,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..6613d39769 --- /dev/null +++ b/src/compile/nodes/interfaces.ts @@ -0,0 +1,62 @@ +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'; + +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..f7c9582115 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; @@ -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..daba0d62b2 100644 --- a/src/compile/nodes/shared/Node.ts +++ b/src/compile/nodes/shared/Node.ts @@ -1,21 +1,23 @@ 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; attributes: Attribute[]; - constructor(component: Component, parent, scope, info: any) { + constructor(component: Component, parent: any, scope: any, info: { start: number; end: number; type: string; }) { this.start = info.start; this.end = info.end; this.type = info.type; @@ -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/utils/add_to_set.ts b/src/compile/utils/add_to_set.ts index 262d7d32e7..b37e0db931 100644 --- a/src/compile/utils/add_to_set.ts +++ b/src/compile/utils/add_to_set.ts @@ -1,5 +1,6 @@ -export default function add_to_set(a: Set, b: Set) { +export default function add_to_set(a: Set, b: Set | Array) { + // @ts-ignore b.forEach(item => { a.add(item); }); -} \ No newline at end of file +} diff --git a/src/compile/utils/scope.ts b/src/compile/utils/scope.ts index 6488986d83..a3e341be49 100644 --- a/src/compile/utils/scope.ts +++ b/src/compile/utils/scope.ts @@ -9,7 +9,7 @@ export function create_scopes(expression: Node) { let scope = new Scope(null, false); walk(expression, { - enter(node: Node, parent: Node) { + enter(node, parent) { if (node.type === 'ImportDeclaration') { node.specifiers.forEach(specifier => { scope.declarations.set(specifier.local.name, specifier); @@ -25,7 +25,7 @@ export function create_scopes(expression: Node) { if (node.id) scope.declarations.set(node.id.name, node); } - node.params.forEach((param: Node) => { + node.params.forEach((param) => { extract_names(param).forEach(name => { scope.declarations.set(name, node); }); diff --git a/src/compile/utils/stringify_attribute.ts b/src/compile/utils/stringify_attribute.ts index 9df2d18344..ee3450edbb 100644 --- a/src/compile/utils/stringify_attribute.ts +++ b/src/compile/utils/stringify_attribute.ts @@ -1,11 +1,10 @@ import Attribute from '../nodes/Attribute'; -import Node from '../nodes/shared/Node'; import { escape_template, escape } from './stringify'; import { snip } from './snip'; export function stringify_attribute(attribute: Attribute, is_ssr: boolean) { return attribute.chunks - .map((chunk: Node) => { + .map((chunk) => { if (chunk.type === 'Text') { return escape_template(escape(chunk.data).replace(/"/g, '"')); } @@ -15,4 +14,4 @@ export function stringify_attribute(attribute: Attribute, is_ssr: boolean) { : '${' + snip(chunk) + '}'; }) .join(''); -} \ No newline at end of file +} From 231603df7bbf0ff9bb5ecf573ccabaa9211bfea5 Mon Sep 17 00:00:00 2001 From: Bogdan Savluk Date: Tue, 21 May 2019 20:56:01 +0200 Subject: [PATCH 67/87] fix compile/render-ssr typings --- src/compile/render-ssr/Renderer.ts | 7 ++++++- src/compile/render-ssr/handlers/AwaitBlock.ts | 8 ++++---- src/compile/render-ssr/handlers/Comment.ts | 8 ++++---- src/compile/render-ssr/handlers/DebugTag.ts | 9 +++++---- src/compile/render-ssr/handlers/EachBlock.ts | 6 ++++-- src/compile/render-ssr/handlers/Element.ts | 13 +++++++++---- src/compile/render-ssr/handlers/Head.ts | 7 +++++-- src/compile/render-ssr/handlers/HtmlTag.ts | 6 ++++-- src/compile/render-ssr/handlers/IfBlock.ts | 7 ++++--- src/compile/render-ssr/handlers/InlineComponent.ts | 11 +++++++---- src/compile/render-ssr/handlers/Slot.ts | 6 ++++-- src/compile/render-ssr/handlers/Tag.ts | 6 +++--- src/compile/render-ssr/handlers/Text.ts | 9 ++++++--- src/compile/render-ssr/handlers/Title.ts | 7 +++++-- src/compile/render-ssr/index.ts | 8 +++++--- 15 files changed, 75 insertions(+), 43 deletions(-) diff --git a/src/compile/render-ssr/Renderer.ts b/src/compile/render-ssr/Renderer.ts index c97965de14..ef1d16429e 100644 --- a/src/compile/render-ssr/Renderer.ts +++ b/src/compile/render-ssr/Renderer.ts @@ -12,6 +12,7 @@ import Tag from './handlers/Tag'; import Text from './handlers/Text'; import Title from './handlers/Title'; import { AppendTarget, CompileOptions } from '../../interfaces'; +import { INode } from '../nodes/interfaces'; type Handler = (node: any, renderer: Renderer, options: CompileOptions) => void; @@ -36,6 +37,10 @@ const handlers: Record = { Window: noop }; +export interface RenderOptions extends CompileOptions{ + locate: (c: number) => { line: number; column: number; }; +}; + export default class Renderer { has_bindings = false; code = ''; @@ -51,7 +56,7 @@ export default class Renderer { } } - render(nodes, options) { + render(nodes: INode[], options: RenderOptions) { nodes.forEach(node => { const handler = handlers[node.type]; diff --git a/src/compile/render-ssr/handlers/AwaitBlock.ts b/src/compile/render-ssr/handlers/AwaitBlock.ts index bbc4a15e05..85bf7b3135 100644 --- a/src/compile/render-ssr/handlers/AwaitBlock.ts +++ b/src/compile/render-ssr/handlers/AwaitBlock.ts @@ -1,8 +1,8 @@ -import Renderer from '../Renderer'; -import { CompileOptions } from '../../../interfaces'; +import Renderer, { RenderOptions } from '../Renderer'; import { snip } from '../../utils/snip'; +import AwaitBlock from '../../nodes/AwaitBlock'; -export default function(node, renderer: Renderer, options: CompileOptions) { +export default function(node: AwaitBlock, renderer: Renderer, options: RenderOptions) { renderer.append('${(function(__value) { if(@is_promise(__value)) return `'); renderer.render(node.pending.children, options); @@ -13,4 +13,4 @@ export default function(node, renderer: Renderer, options: CompileOptions) { const snippet = snip(node.expression); renderer.append(`\`;}(__value);}(${snippet})) }`); -} \ No newline at end of file +} diff --git a/src/compile/render-ssr/handlers/Comment.ts b/src/compile/render-ssr/handlers/Comment.ts index 4517faace5..237c260230 100644 --- a/src/compile/render-ssr/handlers/Comment.ts +++ b/src/compile/render-ssr/handlers/Comment.ts @@ -1,8 +1,8 @@ -import Renderer from '../Renderer'; -import { CompileOptions } from '../../../interfaces'; +import Renderer, { RenderOptions } from '../Renderer'; +import Comment from '../../nodes/Comment'; -export default function(node, renderer: Renderer, options: CompileOptions) { +export default function(node: Comment, renderer: Renderer, options: RenderOptions) { if (options.preserveComments) { renderer.append(``); } -} \ No newline at end of file +} diff --git a/src/compile/render-ssr/handlers/DebugTag.ts b/src/compile/render-ssr/handlers/DebugTag.ts index b04d541105..3fd7584d57 100644 --- a/src/compile/render-ssr/handlers/DebugTag.ts +++ b/src/compile/render-ssr/handlers/DebugTag.ts @@ -1,9 +1,10 @@ import { stringify } from '../../utils/stringify'; - -export default function(node, renderer, options) { +import DebugTag from '../../nodes/DebugTag'; +import Renderer, { RenderOptions } from '../Renderer'; +export default function(node: DebugTag, renderer: Renderer, options: RenderOptions) { if (!options.dev) return; - const filename = options.file || null; + const filename = options.filename || null; const { line, column } = options.locate(node.start + 1); const obj = node.expressions.length === 0 @@ -15,4 +16,4 @@ export default function(node, renderer, options) { const str = '${@debug(' + `${filename && stringify(filename)}, ${line}, ${column}, ${obj})}`; renderer.append(str); -} \ No newline at end of file +} diff --git a/src/compile/render-ssr/handlers/EachBlock.ts b/src/compile/render-ssr/handlers/EachBlock.ts index 3731093a9b..5ed27dff15 100644 --- a/src/compile/render-ssr/handlers/EachBlock.ts +++ b/src/compile/render-ssr/handlers/EachBlock.ts @@ -1,6 +1,8 @@ import { snip } from '../../utils/snip'; +import Renderer, { RenderOptions } from '../Renderer'; +import EachBlock from '../../nodes/EachBlock'; -export default function(node, renderer, options) { +export default function(node: EachBlock, renderer: Renderer, options: RenderOptions) { const snippet = snip(node.expression); const { start, end } = node.context_node; @@ -24,4 +26,4 @@ export default function(node, renderer, options) { } renderer.append('}'); -} \ No newline at end of file +} diff --git a/src/compile/render-ssr/handlers/Element.ts b/src/compile/render-ssr/handlers/Element.ts index 7717be48e3..fc6bc5b969 100644 --- a/src/compile/render-ssr/handlers/Element.ts +++ b/src/compile/render-ssr/handlers/Element.ts @@ -5,6 +5,9 @@ import Node from '../../nodes/shared/Node'; import { snip } from '../../utils/snip'; import { stringify_attribute } from '../../utils/stringify_attribute'; import { get_slot_scope } from './shared/get_slot_scope'; +import Renderer, { RenderOptions } from '../Renderer'; +import Element from '../../nodes/Element'; +import Text from '../../nodes/Text'; // source: https://gist.github.com/ArjanSchouten/0b8574a6ad7f5065a5e7 const boolean_attributes = new Set([ @@ -47,15 +50,17 @@ const boolean_attributes = new Set([ 'translate' ]); -export default function(node, renderer, options) { +export default function(node: Element, renderer: Renderer, options: RenderOptions & { + slot_scopes: Map; +}) { let opening_tag = `<${node.name}`; let textarea_contents; // awkward special case const slot = node.get_static_attribute_value('slot'); const component = node.find_nearest(/InlineComponent/); if (slot && component) { - const slot = node.attributes.find((attribute: Node) => attribute.name === 'slot'); - const slot_name = slot.chunks[0].data; + const slot = node.attributes.find((attribute) => attribute.name === 'slot'); + const slot_name = (slot.chunks[0] as Text).data; const target = renderer.targets[renderer.targets.length - 1]; target.slot_stack.push(slot_name); target.slots[slot_name] = ''; @@ -160,4 +165,4 @@ export default function(node, renderer, options) { if (!is_void(node.name)) { renderer.append(``); } -} \ No newline at end of file +} diff --git a/src/compile/render-ssr/handlers/Head.ts b/src/compile/render-ssr/handlers/Head.ts index 656759af3c..ecd32cc0ef 100644 --- a/src/compile/render-ssr/handlers/Head.ts +++ b/src/compile/render-ssr/handlers/Head.ts @@ -1,7 +1,10 @@ -export default function(node, renderer, options) { +import Renderer, { RenderOptions } from '../Renderer'; +import Head from '../../nodes/Head'; + +export default function(node: Head, renderer: Renderer, options: RenderOptions) { renderer.append('${($$result.head += `'); renderer.render(node.children, options); renderer.append('`, "")}'); -} \ No newline at end of file +} diff --git a/src/compile/render-ssr/handlers/HtmlTag.ts b/src/compile/render-ssr/handlers/HtmlTag.ts index 7562186a4b..84e2e1f573 100644 --- a/src/compile/render-ssr/handlers/HtmlTag.ts +++ b/src/compile/render-ssr/handlers/HtmlTag.ts @@ -1,5 +1,7 @@ import { snip } from '../../utils/snip'; +import Renderer, { RenderOptions } from '../Renderer'; +import RawMustacheTag from '../../nodes/RawMustacheTag'; -export default function(node, renderer, options) { +export default function(node: RawMustacheTag, renderer: Renderer, options: RenderOptions) { renderer.append('${' + snip(node.expression) + '}'); -} \ No newline at end of file +} diff --git a/src/compile/render-ssr/handlers/IfBlock.ts b/src/compile/render-ssr/handlers/IfBlock.ts index cbe505fef8..c841f1d593 100644 --- a/src/compile/render-ssr/handlers/IfBlock.ts +++ b/src/compile/render-ssr/handlers/IfBlock.ts @@ -1,6 +1,7 @@ import { snip } from '../../utils/snip'; - -export default function(node, renderer, options) { +import IfBlock from '../../nodes/IfBlock'; +import Renderer, { RenderOptions } from '../Renderer'; +export default function(node: IfBlock, renderer: Renderer, options: RenderOptions) { const snippet = snip(node.expression); renderer.append('${ ' + snippet + ' ? `'); @@ -14,4 +15,4 @@ export default function(node, renderer, options) { } renderer.append('` }'); -} \ No newline at end of file +} diff --git a/src/compile/render-ssr/handlers/InlineComponent.ts b/src/compile/render-ssr/handlers/InlineComponent.ts index bc58be5df9..94fdcfd434 100644 --- a/src/compile/render-ssr/handlers/InlineComponent.ts +++ b/src/compile/render-ssr/handlers/InlineComponent.ts @@ -1,14 +1,17 @@ import { escape, escape_template, stringify } from '../../utils/stringify'; import { quote_name_if_necessary } from '../../../utils/names'; import { snip } from '../../utils/snip'; -import Renderer from '../Renderer'; +import Renderer, { RenderOptions } from '../Renderer'; import { stringify_props } from '../../utils/stringify_props'; import { get_slot_scope } from './shared/get_slot_scope'; import { AppendTarget } from '../../../interfaces'; +import InlineComponent from '../../nodes/InlineComponent'; +import { INode } from '../../nodes/interfaces'; +import Text from '../../nodes/Text'; -function stringify_attribute(chunk: Node) { +function stringify_attribute(chunk: INode) { if (chunk.type === 'Text') { - return escape_template(escape(chunk.data)); + return escape_template(escape((chunk as Text).data)); } return '${@escape(' + snip(chunk) + ')}'; @@ -30,7 +33,7 @@ function get_attribute_value(attribute) { return '`' + attribute.chunks.map(stringify_attribute).join('') + '`'; } -export default function(node, renderer: Renderer, options) { +export default function(node: InlineComponent, renderer: Renderer, options: RenderOptions) { const binding_props = []; const binding_fns = []; diff --git a/src/compile/render-ssr/handlers/Slot.ts b/src/compile/render-ssr/handlers/Slot.ts index b2e67f9e79..087519979b 100644 --- a/src/compile/render-ssr/handlers/Slot.ts +++ b/src/compile/render-ssr/handlers/Slot.ts @@ -1,7 +1,9 @@ import { quote_prop_if_necessary } from '../../../utils/names'; import get_slot_data from '../../utils/get_slot_data'; +import Renderer, { RenderOptions } from '../Renderer'; +import Slot from '../../nodes/Slot'; -export default function(node, renderer, options) { +export default function(node: Slot, renderer: Renderer, options: RenderOptions) { const prop = quote_prop_if_necessary(node.slot_name); const slot_data = get_slot_data(node.values, true); @@ -13,4 +15,4 @@ export default function(node, renderer, options) { renderer.render(node.children, options); renderer.append(`\`}`); -} \ No newline at end of file +} diff --git a/src/compile/render-ssr/handlers/Tag.ts b/src/compile/render-ssr/handlers/Tag.ts index eb887b8688..d03f46fe0a 100644 --- a/src/compile/render-ssr/handlers/Tag.ts +++ b/src/compile/render-ssr/handlers/Tag.ts @@ -1,6 +1,6 @@ import { snip } from '../../utils/snip'; - -export default function(node, renderer, options) { +import Renderer, { RenderOptions } from '../Renderer'; +export default function(node, renderer: Renderer, options: RenderOptions) { const snippet = snip(node.expression); renderer.append( @@ -10,4 +10,4 @@ export default function(node, renderer, options) { ? '${' + snippet + '}' : '${@escape(' + snippet + ')}' ); -} \ No newline at end of file +} diff --git a/src/compile/render-ssr/handlers/Text.ts b/src/compile/render-ssr/handlers/Text.ts index e794025370..1d2906d10a 100644 --- a/src/compile/render-ssr/handlers/Text.ts +++ b/src/compile/render-ssr/handlers/Text.ts @@ -1,14 +1,17 @@ import { escape_html, escape_template, escape } from '../../utils/stringify'; +import Renderer, { RenderOptions } from '../Renderer'; +import Text from '../../nodes/Text'; +import Element from '../../nodes/Element'; -export default function(node, renderer, options) { +export default function(node: Text, renderer: Renderer, options: RenderOptions) { let text = node.data; if ( !node.parent || node.parent.type !== 'Element' || - (node.parent.name !== 'script' && node.parent.name !== 'style') + ((node.parent as Element).name !== 'script' && (node.parent as Element).name !== 'style') ) { // unless this Text node is inside a + +
    {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..31b605e214 --- /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 attribute '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 @@ + + + From c29c389a72fe4fe130d58728c1c95e826ac1ba1d Mon Sep 17 00:00:00 2001 From: Bogdan Savluk Date: Wed, 22 May 2019 05:20:43 +0200 Subject: [PATCH 73/87] convert everything to TypeScript --- .gitignore | 10 +-- index.mjs | 10 --- package.json | 2 +- rollup.config.js | 76 ++++++++----------- animate.mjs => src/animate.ts | 6 +- src/compile/index.ts | 2 +- src/compiler.ts | 6 ++ easing.mjs => src/easing.ts | 2 +- src/index.ts | 16 ++-- src/internal/{Component.js => Component.ts} | 35 +++++++-- src/internal/{animations.js => animations.ts} | 8 +- .../{await-block.js => await-block.ts} | 10 +-- src/internal/{dom.js => dom.ts} | 43 ++++++----- src/internal/index.js | 12 --- src/internal/index.ts | 12 +++ src/internal/{keyed-each.js => keyed-each.ts} | 4 +- src/internal/{lifecycle.js => lifecycle.ts} | 0 src/internal/{loop.js => loop.ts} | 10 ++- src/internal/{scheduler.js => scheduler.ts} | 4 +- src/internal/{spread.js => spread.ts} | 0 src/internal/{ssr.js => ssr.ts} | 6 +- .../{style_manager.js => style_manager.ts} | 6 +- .../{transitions.js => transitions.ts} | 13 ++-- src/internal/{utils.js => utils.ts} | 4 +- src/motion/index.js | 2 - src/motion/index.ts | 2 + src/motion/{spring.js => spring.ts} | 42 ++++++---- src/motion/{tweened.js => tweened.ts} | 4 +- src/motion/{utils.js => utils.ts} | 4 +- src/store.ts | 2 +- transition.mjs => src/transition.ts | 6 +- src/utils/indentation.ts | 2 +- tsconfig.json | 7 +- 33 files changed, 204 insertions(+), 164 deletions(-) delete mode 100644 index.mjs rename animate.mjs => src/animate.ts (86%) create mode 100644 src/compiler.ts rename easing.mjs => src/easing.ts (98%) rename src/internal/{Component.js => Component.ts} (89%) rename src/internal/{animations.js => animations.ts} (92%) rename src/internal/{await-block.js => await-block.ts} (89%) rename src/internal/{dom.js => dom.ts} (80%) delete mode 100644 src/internal/index.js create mode 100644 src/internal/index.ts rename src/internal/{keyed-each.js => keyed-each.ts} (98%) rename src/internal/{lifecycle.js => lifecycle.ts} (100%) rename src/internal/{loop.js => loop.ts} (73%) rename src/internal/{scheduler.js => scheduler.ts} (94%) rename src/internal/{spread.js => spread.ts} (100%) rename src/internal/{ssr.js => ssr.ts} (97%) rename src/internal/{style_manager.js => style_manager.ts} (95%) rename src/internal/{transitions.js => transitions.ts} (95%) rename src/internal/{utils.js => utils.ts} (96%) delete mode 100644 src/motion/index.js create mode 100644 src/motion/index.ts rename src/motion/{spring.js => spring.ts} (73%) rename src/motion/{tweened.js => tweened.ts} (98%) rename src/motion/{utils.js => utils.ts} (63%) rename transition.mjs => src/transition.ts (97%) diff --git a/.gitignore b/.gitignore index 3d1322c33e..b50d83fd2e 100644 --- a/.gitignore +++ b/.gitignore @@ -4,14 +4,14 @@ node_modules *.map /src/compile/internal-exports.ts -/compiler.js -/index.js +/compiler.* +/index.* /internal.* /store.* -/easing.js +/easing.* /motion.* -/transition.js -/animate.js +/transition.* +/animate.* /scratch/ /coverage/ /coverage.lcov/ 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/package.json b/package.json index b32e19786f..8665648abb 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,7 @@ "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 .", "typecheck": "tsc --noEmit" 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/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/index.ts b/src/compile/index.ts index 526d8abaeb..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'; diff --git a/src/compiler.ts b/src/compiler.ts new file mode 100644 index 0000000000..4987c18a15 --- /dev/null +++ b/src/compiler.ts @@ -0,0 +1,6 @@ +export { default as compile } from './compile/index'; +export { default as parse } from './parse/index'; +export { default as preprocess } from './preprocess/index'; +export { walk } from 'estree-walker'; + +export const VERSION = '__VERSION__'; \ No newline at end of file diff --git a/easing.mjs b/src/easing.ts similarity index 98% rename from easing.mjs rename to src/easing.ts index 4fc625c24f..7a762394c2 100644 --- a/easing.mjs +++ b/src/easing.ts @@ -3,7 +3,7 @@ Adapted from https://github.com/mattdesl Distributed under MIT License https://github.com/mattdesl/eases/blob/master/LICENSE.md */ -export { identity as linear } from './internal'; +export { identity as linear } from 'svelte/internal'; export function backInOut(t) { const s = 1.70158 * 1.525; diff --git a/src/index.ts b/src/index.ts index 4987c18a15..40928da8a0 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,6 +1,10 @@ -export { default as compile } from './compile/index'; -export { default as parse } from './parse/index'; -export { default as preprocess } from './preprocess/index'; -export { walk } from 'estree-walker'; - -export const VERSION = '__VERSION__'; \ No newline at end of file +export { + onMount, + onDestroy, + beforeUpdate, + afterUpdate, + setContext, + getContext, + tick, + createEventDispatcher +} from 'svelte/internal'; diff --git a/src/internal/Component.js b/src/internal/Component.ts similarity index 89% rename from src/internal/Component.js rename to src/internal/Component.ts index 871dbd6054..714d15df34 100644 --- a/src/internal/Component.js +++ b/src/internal/Component.ts @@ -1,7 +1,23 @@ -import { add_render_callback, flush, schedule_update, dirty_components } from './scheduler.js'; -import { current_component, set_current_component } from './lifecycle.js'; -import { blank_object, is_function, run, run_all, noop } from './utils.js'; -import { children } from './dom.js'; +import { add_render_callback, flush, schedule_update, dirty_components } from './scheduler'; +import { current_component, set_current_component } from './lifecycle'; +import { blank_object, is_function, run, run_all, noop } from './utils'; +import { children } from './dom'; + +interface T$$ { + dirty: null; + ctx: null|any; + bound: any; + update: () => void; + callbacks: any; + after_render: any[]; + props: any; + fragment: null|any; + not_equal: any; + before_render: any[]; + context: Map; + on_mount: any[]; + on_destroy: any[] +} export function bind(component, name, callback) { if (component.$$.props.indexOf(name) === -1) return; @@ -59,7 +75,7 @@ export function init(component, options, instance, create_fragment, not_equal, p const props = options.props || {}; - const $$ = component.$$ = { + const $$: T$$ = component.$$ = { fragment: null, ctx: null, @@ -99,9 +115,9 @@ export function init(component, options, instance, create_fragment, not_equal, p if (options.target) { if (options.hydrate) { - $$.fragment.l(children(options.target)); + $$.fragment!.l(children(options.target)); } else { - $$.fragment.c(); + $$.fragment!.c(); } if (options.intro && component.$$.fragment.i) component.$$.fragment.i(); @@ -115,13 +131,16 @@ export function init(component, options, instance, create_fragment, not_equal, p export let SvelteElement; if (typeof HTMLElement !== 'undefined') { SvelteElement = class extends HTMLElement { + $$: T$$; constructor() { super(); this.attachShadow({ mode: 'open' }); } connectedCallback() { + // @ts-ignore todo: improve typings for (const key in this.$$.slotted) { + // @ts-ignore todo: improve typings this.appendChild(this.$$.slotted[key]); } } @@ -153,6 +172,8 @@ if (typeof HTMLElement !== 'undefined') { } export class SvelteComponent { + $$: T$$; + $destroy() { destroy(this, true); this.$destroy = noop; diff --git a/src/internal/animations.js b/src/internal/animations.ts similarity index 92% rename from src/internal/animations.js rename to src/internal/animations.ts index 8d55c196ee..b6c7ae2df2 100644 --- a/src/internal/animations.js +++ b/src/internal/animations.ts @@ -1,6 +1,6 @@ -import { identity as linear, noop, now } from './utils.js'; -import { loop } from './loop.js'; -import { create_rule, delete_rule } from './style_manager.js'; +import { identity as linear, noop, now } from './utils'; +import { loop } from './loop'; +import { create_rule, delete_rule } from './style_manager'; export function create_animation(node, from, fn, params) { if (!from) return noop; @@ -90,4 +90,4 @@ export function fix_position(node) { node.style.transform = `${transform} translate(${a.left - b.left}px, ${a.top - b.top}px)`; } } -} \ No newline at end of file +} diff --git a/src/internal/await-block.js b/src/internal/await-block.ts similarity index 89% rename from src/internal/await-block.js rename to src/internal/await-block.ts index 9e14c50342..9527b000ca 100644 --- a/src/internal/await-block.js +++ b/src/internal/await-block.ts @@ -1,11 +1,11 @@ -import { assign, is_promise } from './utils.js'; -import { check_outros, group_outros, on_outro } from './transitions.js'; -import { flush } from '../internal/scheduler.js'; +import { assign, is_promise } from './utils'; +import { check_outros, group_outros, on_outro } from './transitions'; +import { flush } from '../internal/scheduler'; export function handle_promise(promise, info) { const token = info.token = {}; - function update(type, index, key, value) { + function update(type, index, key?, value?) { if (info.token !== token) return; info.resolved = key && { [key]: value }; @@ -61,4 +61,4 @@ export function handle_promise(promise, info) { info.resolved = { [info.value]: promise }; } -} \ No newline at end of file +} diff --git a/src/internal/dom.js b/src/internal/dom.ts similarity index 80% rename from src/internal/dom.js rename to src/internal/dom.ts index 46ffaa8472..293040ce20 100644 --- a/src/internal/dom.js +++ b/src/internal/dom.ts @@ -1,28 +1,28 @@ -export function append(target, node) { +export function append(target:Node, node:Node) { target.appendChild(node); } -export function insert(target, node, anchor) { +export function insert(target: Node, node: Node, anchor?:Node) { target.insertBefore(node, anchor || null); } -export function detach(node) { +export function detach(node: Node) { node.parentNode.removeChild(node); } -export function detach_between(before, after) { +export function detach_between(before: Node, after: Node) { while (before.nextSibling && before.nextSibling !== after) { before.parentNode.removeChild(before.nextSibling); } } -export function detach_before(after) { +export function detach_before(after:Node) { while (after.previousSibling) { after.parentNode.removeChild(after.previousSibling); } } -export function detach_after(before) { +export function detach_after(before:Node) { while (before.nextSibling) { before.parentNode.removeChild(before.nextSibling); } @@ -34,25 +34,30 @@ export function destroy_each(iterations, detaching) { } } -export function element(name) { - return document.createElement(name); +export function element(name: K) { + return document.createElement(name); } -export function object_without_properties(obj, exclude) { - const target = {}; +export function object_without_properties(obj:T, exclude: K[]) { + const target = {} as Pick>; for (const k in obj) { - if (Object.prototype.hasOwnProperty.call(obj, k) && exclude.indexOf(k) === -1) { + if ( + Object.prototype.hasOwnProperty.call(obj, k) + // @ts-ignore + && exclude.indexOf(k) === -1 + ) { + // @ts-ignore target[k] = obj[k]; } } return target; } -export function svg_element(name) { +export function svg_element(name:string):SVGElement { return document.createElementNS('http://www.w3.org/2000/svg', name); } -export function text(data) { +export function text(data:string) { return document.createTextNode(data); } @@ -64,7 +69,7 @@ export function empty() { return text(''); } -export function listen(node, event, handler, options) { +export function listen(node: Node, event: string, handler: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions | EventListenerOptions) { node.addEventListener(event, handler, options); return () => node.removeEventListener(event, handler, options); } @@ -72,6 +77,7 @@ export function listen(node, event, handler, options) { export function prevent_default(fn) { return function(event) { event.preventDefault(); + // @ts-ignore return fn.call(this, event); }; } @@ -79,16 +85,17 @@ export function prevent_default(fn) { export function stop_propagation(fn) { return function(event) { event.stopPropagation(); + // @ts-ignore return fn.call(this, event); }; } -export function attr(node, attribute, value) { +export function attr(node: Element, attribute: string, value?: string) { if (value == null) node.removeAttribute(attribute); else node.setAttribute(attribute, value); } -export function set_attributes(node, attributes) { +export function set_attributes(node: HTMLElement, attributes: { [x: string]: string; }) { for (const key in attributes) { if (key === 'style') { node.style.cssText = attributes[key]; @@ -243,8 +250,8 @@ export function toggle_class(element, name, toggle) { element.classList[toggle ? 'add' : 'remove'](name); } -export function custom_event(type, detail) { - const e = document.createEvent('CustomEvent'); +export function custom_event(type: string, detail?: T) { + const e: CustomEvent = document.createEvent('CustomEvent'); e.initCustomEvent(type, false, false, detail); return e; } diff --git a/src/internal/index.js b/src/internal/index.js deleted file mode 100644 index f3654f6b77..0000000000 --- a/src/internal/index.js +++ /dev/null @@ -1,12 +0,0 @@ -export * from './animations.js'; -export * from './await-block.js'; -export * from './dom.js'; -export * from './keyed-each.js'; -export * from './lifecycle.js'; -export * from './loop.js'; -export * from './scheduler.js'; -export * from './spread.js'; -export * from './ssr.js'; -export * from './transitions.js'; -export * from './utils.js'; -export * from './Component.js'; \ No newline at end of file diff --git a/src/internal/index.ts b/src/internal/index.ts new file mode 100644 index 0000000000..6487f04525 --- /dev/null +++ b/src/internal/index.ts @@ -0,0 +1,12 @@ +export * from './animations'; +export * from './await-block'; +export * from './dom'; +export * from './keyed-each'; +export * from './lifecycle'; +export * from './loop'; +export * from './scheduler'; +export * from './spread'; +export * from './ssr'; +export * from './transitions'; +export * from './utils'; +export * from './Component'; diff --git a/src/internal/keyed-each.js b/src/internal/keyed-each.ts similarity index 98% rename from src/internal/keyed-each.js rename to src/internal/keyed-each.ts index c40a1cc00b..0ec8b09400 100644 --- a/src/internal/keyed-each.js +++ b/src/internal/keyed-each.ts @@ -1,4 +1,4 @@ -import { on_outro } from './transitions.js'; +import { on_outro } from './transitions'; export function destroy_block(block, lookup) { block.d(1); @@ -110,4 +110,4 @@ export function measure(blocks) { let i = blocks.length; while (i--) rects[blocks[i].key] = blocks[i].node.getBoundingClientRect(); return rects; -} \ No newline at end of file +} diff --git a/src/internal/lifecycle.js b/src/internal/lifecycle.ts similarity index 100% rename from src/internal/lifecycle.js rename to src/internal/lifecycle.ts diff --git a/src/internal/loop.js b/src/internal/loop.ts similarity index 73% rename from src/internal/loop.js rename to src/internal/loop.ts index 8150727441..b6cd53a189 100644 --- a/src/internal/loop.js +++ b/src/internal/loop.ts @@ -1,4 +1,6 @@ -import { now } from './utils.js'; +import { now } from './utils'; + +export interface Task { abort(): void; promise: Promise } const tasks = new Set(); let running = false; @@ -21,7 +23,7 @@ export function clear_loops() { running = false; } -export function loop(fn) { +export function loop(fn: (number)=>void): Task { let task; if (!running) { @@ -30,11 +32,11 @@ export function loop(fn) { } return { - promise: new Promise(fulfil => { + promise: new Promise(fulfil => { tasks.add(task = [fn, fulfil]); }), abort() { tasks.delete(task); } }; -} \ No newline at end of file +} diff --git a/src/internal/scheduler.js b/src/internal/scheduler.ts similarity index 94% rename from src/internal/scheduler.js rename to src/internal/scheduler.ts index 749c3971dc..a26a4f8c33 100644 --- a/src/internal/scheduler.js +++ b/src/internal/scheduler.ts @@ -1,5 +1,5 @@ -import { run_all } from './utils.js'; -import { set_current_component } from './lifecycle.js'; +import { run_all } from './utils'; +import { set_current_component } from './lifecycle'; export const dirty_components = []; export const intros = { enabled: false }; diff --git a/src/internal/spread.js b/src/internal/spread.ts similarity index 100% rename from src/internal/spread.js rename to src/internal/spread.ts diff --git a/src/internal/ssr.js b/src/internal/ssr.ts similarity index 97% rename from src/internal/ssr.js rename to src/internal/ssr.ts index e8d96c609c..aaa391b4dc 100644 --- a/src/internal/ssr.js +++ b/src/internal/ssr.ts @@ -1,5 +1,5 @@ -import { set_current_component, current_component } from './lifecycle.js'; -import { run_all, blank_object } from './utils.js'; +import { set_current_component, current_component } from './lifecycle'; +import { run_all, blank_object } from './utils'; export const invalid_attribute_name_character = /[\s'">/=\u{FDD0}-\u{FDEF}\u{FFFE}\u{FFFF}\u{1FFFE}\u{1FFFF}\u{2FFFE}\u{2FFFF}\u{3FFFE}\u{3FFFF}\u{4FFFE}\u{4FFFF}\u{5FFFE}\u{5FFFF}\u{6FFFE}\u{6FFFF}\u{7FFFE}\u{7FFFF}\u{8FFFE}\u{8FFFF}\u{9FFFE}\u{9FFFF}\u{AFFFE}\u{AFFFF}\u{BFFFE}\u{BFFFF}\u{CFFFE}\u{CFFFF}\u{DFFFE}\u{DFFFF}\u{EFFFE}\u{EFFFF}\u{FFFFE}\u{FFFFF}\u{10FFFE}\u{10FFFF}]/u; // https://html.spec.whatwg.org/multipage/syntax.html#attributes-2 @@ -117,4 +117,4 @@ export function get_store_value(store) { let value; store.subscribe(_ => value = _)(); return value; -} \ No newline at end of file +} diff --git a/src/internal/style_manager.js b/src/internal/style_manager.ts similarity index 95% rename from src/internal/style_manager.js rename to src/internal/style_manager.ts index d71e922f01..8e4d35ca38 100644 --- a/src/internal/style_manager.js +++ b/src/internal/style_manager.ts @@ -1,4 +1,4 @@ -import { element } from './dom.js'; +import { element } from './dom'; let stylesheet; let active = 0; @@ -43,7 +43,7 @@ export function create_rule(node, a, b, duration, delay, ease, fn, uid = 0) { return name; } -export function delete_rule(node, name) { +export function delete_rule(node, name?) { node.style.animation = (node.style.animation || '') .split(', ') .filter(name @@ -62,4 +62,4 @@ export function clear_rules() { while (i--) stylesheet.deleteRule(i); current_rules = {}; }); -} \ No newline at end of file +} diff --git a/src/internal/transitions.js b/src/internal/transitions.ts similarity index 95% rename from src/internal/transitions.js rename to src/internal/transitions.ts index af15e8969e..04942e3d16 100644 --- a/src/internal/transitions.js +++ b/src/internal/transitions.ts @@ -1,8 +1,8 @@ -import { identity as linear, noop, now, run_all } from './utils.js'; -import { loop } from './loop.js'; -import { create_rule, delete_rule } from './style_manager.js'; -import { custom_event } from './dom.js'; -import { add_render_callback } from './scheduler.js'; +import { identity as linear, noop, now, run_all } from './utils'; +import { loop } from './loop'; +import { create_rule, delete_rule } from './style_manager'; +import { custom_event } from './dom'; +import { add_render_callback } from './scheduler'; let promise; @@ -229,6 +229,7 @@ export function create_bidirectional_transition(node, fn, params, intro) { }; if (!b) { + // @ts-ignore todo: improve typings program.group = outros; outros.remaining += 1; } @@ -309,4 +310,4 @@ export function create_bidirectional_transition(node, fn, params, intro) { running_program = pending_program = null; } }; -} \ No newline at end of file +} diff --git a/src/internal/utils.js b/src/internal/utils.ts similarity index 96% rename from src/internal/utils.js rename to src/internal/utils.ts index e6d66d8717..8bb40ac071 100644 --- a/src/internal/utils.js +++ b/src/internal/utils.ts @@ -80,11 +80,11 @@ export function exclude_internal_props(props) { return result; } -export let now = typeof window !== 'undefined' +export let now: () => number = typeof window !== 'undefined' ? () => window.performance.now() : () => Date.now(); // used internally for testing export function set_now(fn) { now = fn; -} \ No newline at end of file +} diff --git a/src/motion/index.js b/src/motion/index.js deleted file mode 100644 index e0e9bcf1ae..0000000000 --- a/src/motion/index.js +++ /dev/null @@ -1,2 +0,0 @@ -export * from './spring.js'; -export * from './tweened.js'; \ No newline at end of file diff --git a/src/motion/index.ts b/src/motion/index.ts new file mode 100644 index 0000000000..ea6c646dd9 --- /dev/null +++ b/src/motion/index.ts @@ -0,0 +1,2 @@ +export * from './spring'; +export * from './tweened'; diff --git a/src/motion/spring.js b/src/motion/spring.ts similarity index 73% rename from src/motion/spring.js rename to src/motion/spring.ts index 8b280366b2..3977c08f79 100644 --- a/src/motion/spring.js +++ b/src/motion/spring.ts @@ -1,6 +1,6 @@ -import { writable } from 'svelte/store'; // eslint-disable-line import/no-unresolved -import { loop, now } from 'svelte/internal'; // eslint-disable-line import/no-unresolved -import { is_date } from './utils.js'; +import { Readable, writable } from 'svelte/store'; +import { loop, now, Task } from 'svelte/internal'; +import { is_date } from './utils'; function tick_spring(ctx, last_value, current_value, target_value) { if (typeof current_value === 'number' || is_date(current_value)) { @@ -27,25 +27,41 @@ function tick_spring(ctx, last_value, current_value, target_value) { next_value[k] = tick_spring(ctx, last_value[k], current_value[k], target_value[k]); return next_value; } else { - throw new Error(`Cannot spring ${typeof value} values`); + throw new Error(`Cannot spring ${typeof current_value} values`); } } -export function spring(value, opts = {}) { +interface SpringOpts { + stiffness?: number, + damping?: number, + precision?: number, +} + +type SpringUpdateOpts = { hard?: any; soft?: string | number | boolean; }; + +interface Spring extends Readable{ + set: (new_value: T, opts?: SpringUpdateOpts) => (Promise | Promise); + precision: number; + update: (fn, opts: SpringUpdateOpts) => Promise; + damping: number; + stiffness: number +} + +export function spring(value: T, opts: SpringOpts = {}) { const store = writable(value); const { stiffness = 0.15, damping = 0.8, precision = 0.01 } = opts; - let last_time; - let task; - let current_token; - let last_value = value; - let target_value = value; + let last_time: number; + let task: Task; + let current_token: object; + let last_value:T = value; + let target_value:T = value; let inv_mass = 1; let inv_mass_recovery_rate = 0; let cancel_task = false; - function set(new_value, opts = {}) { + function set(new_value: any, opts: SpringUpdateOpts={}) { target_value = new_value; const token = current_token = {}; @@ -100,9 +116,9 @@ export function spring(value, opts = {}) { }); } - const spring = { + const spring: Spring = { set, - update: (fn, opts) => set(fn(target_value, value), opts), + update: (fn, opts:SpringUpdateOpts) => set(fn(target_value, value), opts), subscribe: store.subscribe, stiffness, damping, diff --git a/src/motion/tweened.js b/src/motion/tweened.ts similarity index 98% rename from src/motion/tweened.js rename to src/motion/tweened.ts index 45520832b7..3b2d0ef5a2 100644 --- a/src/motion/tweened.js +++ b/src/motion/tweened.ts @@ -1,7 +1,7 @@ import { writable } from 'svelte/store'; // eslint-disable-line import/no-unresolved import { assign, loop, now } from 'svelte/internal'; // eslint-disable-line import/no-unresolved import { linear } from 'svelte/easing'; // eslint-disable-line import/no-unresolved -import { is_date } from './utils.js'; +import { is_date } from './utils'; function get_interpolator(a, b) { if (a === b || a !== a) return () => a; @@ -109,4 +109,4 @@ export function tweened(value, defaults = {}) { update: (fn, opts) => set(fn(target_value, value), opts), subscribe: store.subscribe }; -} \ No newline at end of file +} diff --git a/src/motion/utils.js b/src/motion/utils.ts similarity index 63% rename from src/motion/utils.js rename to src/motion/utils.ts index 97a764bf46..f8bfcce14c 100644 --- a/src/motion/utils.js +++ b/src/motion/utils.ts @@ -1,3 +1,3 @@ -export function is_date(obj) { +export function is_date(obj: any) { return Object.prototype.toString.call(obj) === '[object Date]'; -} \ No newline at end of file +} diff --git a/src/store.ts b/src/store.ts index b0ee41fc8d..361632b61d 100644 --- a/src/store.ts +++ b/src/store.ts @@ -1,4 +1,4 @@ -import { run_all, noop, safe_not_equal, is_function } from './internal/utils'; +import { run_all, noop, safe_not_equal, is_function } from 'svelte/internal'; /** Callback to inform of a value updates. */ type Subscriber = (value: T) => void; diff --git a/transition.mjs b/src/transition.ts similarity index 97% rename from transition.mjs rename to src/transition.ts index 857fd03165..20619ee131 100644 --- a/transition.mjs +++ b/src/transition.ts @@ -1,5 +1,5 @@ -import { cubicOut, cubicInOut } from './easing'; -import { assign, is_function } from './internal'; +import { cubicOut, cubicInOut } from 'svelte/easing'; +import { assign, is_function } from 'svelte/internal'; export function fade(node, { delay = 0, @@ -179,4 +179,4 @@ export function crossfade({ fallback, ...defaults }) { transition(to_send, to_receive, false), transition(to_receive, to_send, true) ]; -} \ No newline at end of file +} diff --git a/src/utils/indentation.ts b/src/utils/indentation.ts index 765a62bfbf..54ededc37d 100644 --- a/src/utils/indentation.ts +++ b/src/utils/indentation.ts @@ -54,4 +54,4 @@ export function add_indentation(code: MagicString, node: Node, levels = 1) { code.appendLeft(index + 1, indent); } -} \ No newline at end of file +} diff --git a/tsconfig.json b/tsconfig.json index fdb7367e05..acbca11ac7 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -7,12 +7,17 @@ "allowJs": true, "lib": ["es5", "es6", "dom"], "importHelpers": true, - "moduleResolution": "node" + "moduleResolution": "node", + "baseUrl": ".", + "paths": { + "svelte/*": ["./src/*"] + } }, "include": [ "src" ], "exclude": [ + "./*.*js", "node_modules" ] } From d5d5caba600b9bbc1b0e0e2000a0a3c34d1ed303 Mon Sep 17 00:00:00 2001 From: Bogdan Savluk Date: Wed, 22 May 2019 07:31:39 +0200 Subject: [PATCH 74/87] type declarations for bundled files --- .gitignore | 17 ++++++++-------- animate.d.ts | 1 + compiler.d.ts | 1 + easing.d.ts | 1 + index.d.ts | 1 + internal.d.ts | 1 + motion.d.ts | 1 + package.json | 4 ++-- store.d.ts | 1 + transition.d.ts | 1 + tsconfig.json | 53 +++++++++++++++++++++++++++++-------------------- 11 files changed, 51 insertions(+), 31 deletions(-) create mode 100644 animate.d.ts create mode 100644 compiler.d.ts create mode 100644 easing.d.ts create mode 100644 index.d.ts create mode 100644 internal.d.ts create mode 100644 motion.d.ts create mode 100644 store.d.ts create mode 100644 transition.d.ts diff --git a/.gitignore b/.gitignore index b50d83fd2e..35888493fa 100644 --- a/.gitignore +++ b/.gitignore @@ -4,14 +4,14 @@ node_modules *.map /src/compile/internal-exports.ts -/compiler.* -/index.* -/internal.* -/store.* -/easing.* -/motion.* -/transition.* -/animate.* +/compiler.*js +/index.*js +/internal.*js +/store.*js +/easing.*js +/motion.*js +/transition.*js +/animate.*js /scratch/ /coverage/ /coverage.lcov/ @@ -21,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/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.json b/package.json index 8665648abb..7963e2178d 100644 --- a/package.json +++ b/package.json @@ -32,8 +32,8 @@ "pretest": "npm run build", "posttest": "agadoo internal.mjs", "prepublishOnly": "export PUBLISH=true && npm run lint && npm test", - "tsd": "tsc -d src/store.ts --outDir .", - "typecheck": "tsc --noEmit" + "tsd": "tsc -p . --emitDeclarationOnly", + "typecheck": "tsc -p . --noEmit" }, "repository": { "type": "git", diff --git a/store.d.ts b/store.d.ts new file mode 100644 index 0000000000..2c1307011b --- /dev/null +++ b/store.d.ts @@ -0,0 +1 @@ +export * from './dist/store'; 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 acbca11ac7..ff11591679 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,23 +1,34 @@ { - "compilerOptions": { - "target": "ES6", - "diagnostics": true, - "noImplicitThis": true, - "noEmitOnError": true, - "allowJs": true, - "lib": ["es5", "es6", "dom"], - "importHelpers": true, - "moduleResolution": "node", - "baseUrl": ".", - "paths": { - "svelte/*": ["./src/*"] - } - }, - "include": [ - "src" - ], - "exclude": [ - "./*.*js", - "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/*": [ + "./src/*" + ] + }, + "typeRoots": [ + "node_modules/@types" + ] + }, + "include": [ + "src/**/*" + ], + "exclude": [ + "dist" + ] } From 33f827ca0a6f1a82f9123c0d3e6655482a687ec8 Mon Sep 17 00:00:00 2001 From: Bogdan Savluk Date: Wed, 22 May 2019 08:06:47 +0200 Subject: [PATCH 75/87] fix case sensitive import name, improve tsconfig --- src/compile/render-dom/wrappers/RawMustacheTag.ts | 2 +- tsconfig.json | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/compile/render-dom/wrappers/RawMustacheTag.ts b/src/compile/render-dom/wrappers/RawMustacheTag.ts index d8f863c674..326852bb18 100644 --- a/src/compile/render-dom/wrappers/RawMustacheTag.ts +++ b/src/compile/render-dom/wrappers/RawMustacheTag.ts @@ -1,7 +1,7 @@ import Renderer from '../Renderer'; import Block from '../Block'; import Tag from './shared/Tag'; -import Wrapper from './shared/wrapper'; +import Wrapper from './shared/Wrapper'; import deindent from '../../utils/deindent'; import MustacheTag from '../../nodes/MustacheTag'; import RawMustacheTag from '../../nodes/RawMustacheTag'; diff --git a/tsconfig.json b/tsconfig.json index ff11591679..994bc61b85 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -17,9 +17,10 @@ "moduleResolution": "node", "baseUrl": ".", "paths": { - "svelte/*": [ - "./src/*" - ] + "svelte/internal": ["./src/internal"], + "svelte/easing": ["./src/easing"], + "svelte/motion": ["./src/motion"], + "svelte/store": ["./src/store"] }, "typeRoots": [ "node_modules/@types" From a6c05ed3728c7b3b2e08fdb83fa58ab46a58ad5f Mon Sep 17 00:00:00 2001 From: Conduitry Date: Wed, 22 May 2019 12:00:22 -0400 Subject: [PATCH 76/87] site: add /faq redirect to GitHub wiki FAQ --- site/src/routes/faq.js | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 site/src/routes/faq.js diff --git a/site/src/routes/faq.js b/site/src/routes/faq.js new file mode 100644 index 0000000000..6263494a4c --- /dev/null +++ b/site/src/routes/faq.js @@ -0,0 +1,4 @@ +export function get(req, res) { + res.writeHead(302, { Location: 'https://github.com/sveltejs/svelte/wiki/FAQ' }); + res.end(); +} \ No newline at end of file From dabc9c3e5310316d82bfd8ef16f13e9a4fed3e66 Mon Sep 17 00:00:00 2001 From: Benjamin Milde Date: Fri, 24 May 2019 17:13:58 +0200 Subject: [PATCH 77/87] Allow binding of
    open --- src/compile/nodes/Element.ts | 10 ++- .../render-dom/wrappers/Element/index.ts | 6 ++ test/js/samples/bind-open/expected.js | 69 +++++++++++++++++++ test/js/samples/bind-open/input.svelte | 7 ++ .../samples/binding-details-open/_config.js | 25 +++++++ .../samples/binding-details-open/main.svelte | 9 +++ 6 files changed, 125 insertions(+), 1 deletion(-) create mode 100644 test/js/samples/bind-open/expected.js create mode 100644 test/js/samples/bind-open/input.svelte create mode 100644 test/runtime/samples/binding-details-open/_config.js create mode 100644 test/runtime/samples/binding-details-open/main.svelte diff --git a/src/compile/nodes/Element.ts b/src/compile/nodes/Element.ts index ac2b81b3e7..2b76d68e6d 100644 --- a/src/compile/nodes/Element.ts +++ b/src/compile/nodes/Element.ts @@ -544,7 +544,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 +560,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/render-dom/wrappers/Element/index.ts b/src/compile/render-dom/wrappers/Element/index.ts index 22ea7a78cd..ad85a46db3 100644 --- a/src/compile/render-dom/wrappers/Element/index.ts +++ b/src/compile/render-dom/wrappers/Element/index.ts @@ -91,6 +91,12 @@ const events = [ name === 'playbackRate' }, + // details event + { + event_names: ['toggle'], + filter: (node: Element, name: string) => + node.name === 'details' + }, ]; export default class ElementWrapper extends Wrapper { diff --git a/test/js/samples/bind-open/expected.js b/test/js/samples/bind-open/expected.js new file mode 100644 index 0000000000..7c73c8ddac --- /dev/null +++ b/test/js/samples/bind-open/expected.js @@ -0,0 +1,69 @@ +/* generated by Svelte vX.Y.Z */ +import { + SvelteComponent, + detach, + element, + init, + insert, + listen, + noop, + safe_not_equal +} from "svelte/internal"; + +function create_fragment(ctx) { + var details, dispose; + + return { + c() { + details = element("details"); + details.innerHTML = `summarycontent + `; + dispose = listen(details, "toggle", ctx.details_toggle_handler); + }, + + m(target, anchor) { + insert(target, details, anchor); + + details.open = ctx.open; + }, + + p(changed, ctx) { + if (changed.open) details.open = ctx.open; + }, + + i: noop, + o: noop, + + d(detaching) { + if (detaching) { + detach(details); + } + + dispose(); + } + }; +} + +function instance($$self, $$props, $$invalidate) { + let { open } = $$props; + + function details_toggle_handler() { + open = this.open; + $$invalidate('open', open); + } + + $$self.$set = $$props => { + if ('open' in $$props) $$invalidate('open', open = $$props.open); + }; + + return { open, details_toggle_handler }; +} + +class Component extends SvelteComponent { + constructor(options) { + super(); + init(this, options, instance, create_fragment, safe_not_equal, ["open"]); + } +} + +export default Component; diff --git a/test/js/samples/bind-open/input.svelte b/test/js/samples/bind-open/input.svelte new file mode 100644 index 0000000000..3dd2b03a73 --- /dev/null +++ b/test/js/samples/bind-open/input.svelte @@ -0,0 +1,7 @@ + + +
    + summarycontent +
    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..e5e81b2c93 --- /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.open, true); + assert.htmlEqual(target.innerHTML, ` +
    toggle
    +

    hello!

    + `); + + details.open = false; + await details.dispatchEvent(event); + assert.equal(component.open, 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} From 2f80667f207432f1154fb22ea735f03f1654793d Mon Sep 17 00:00:00 2001 From: Conduitry Date: Fri, 24 May 2019 12:05:18 -0400 Subject: [PATCH 78/87] site: actions tutorial: destroy is not required (#2776) --- site/content/tutorial/12-actions/01-actions/text.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/site/content/tutorial/12-actions/01-actions/text.md b/site/content/tutorial/12-actions/01-actions/text.md index 279dc3123f..38de8f9a65 100644 --- a/site/content/tutorial/12-actions/01-actions/text.md +++ b/site/content/tutorial/12-actions/01-actions/text.md @@ -27,7 +27,7 @@ import { pannable } from './pannable.js'; >
    ``` -Open the `pannable.js` file. Like transition functions, an action function receives a `node` and some optional parameters, and returns an action object. That object must have a `destroy` function, which is called when the element is unmounted. +Open the `pannable.js` file. Like transition functions, an action function receives a `node` and some optional parameters, and returns an action object. That object can have a `destroy` function, which is called when the element is unmounted. We want to fire `panstart` event when the user mouses down on the element, `panmove` events (with `dx` and `dy` properties showing how far the mouse moved) when they drag it, and `panend` events when they mouse up. One possible implementation looks like this: @@ -84,4 +84,3 @@ export function pannable(node) { Update the `pannable` function and try moving the box around. > This implementation is for demonstration purposes — a more complete one would also consider touch events. - From a5fe09c48154c9b993dfc5386e8f7c72ce748d09 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Fri, 24 May 2019 14:12:41 -0400 Subject: [PATCH 79/87] treat requestAnimationFrame as a noop on the server --- package-lock.json | 2 +- src/compile/render-dom/wrappers/Element/index.ts | 2 +- src/internal/loop.js | 6 +++--- src/internal/style_manager.js | 3 ++- src/internal/utils.js | 8 ++++++-- 5 files changed, 13 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index bb2b7d7d7e..28ecb0eedb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "svelte", - "version": "3.4.0", + "version": "3.4.1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/src/compile/render-dom/wrappers/Element/index.ts b/src/compile/render-dom/wrappers/Element/index.ts index 22ea7a78cd..ad624c8d6c 100644 --- a/src/compile/render-dom/wrappers/Element/index.ts +++ b/src/compile/render-dom/wrappers/Element/index.ts @@ -455,7 +455,7 @@ export default class ElementWrapper extends Wrapper { function ${handler}() { ${animation_frame && deindent` cancelAnimationFrame(${animation_frame}); - if (!${this.var}.paused) ${animation_frame} = requestAnimationFrame(${handler});`} + if (!${this.var}.paused) ${animation_frame} = @raf(${handler});`} ${needs_lock && `${lock} = true;`} ctx.${handler}.call(${this.var}${contextual_dependencies.size > 0 ? ', ctx' : ''}); } diff --git a/src/internal/loop.js b/src/internal/loop.js index 8150727441..60c7df4d70 100644 --- a/src/internal/loop.js +++ b/src/internal/loop.js @@ -1,4 +1,4 @@ -import { now } from './utils.js'; +import { now, raf } from './utils.js'; const tasks = new Set(); let running = false; @@ -12,7 +12,7 @@ function run_tasks() { }); running = tasks.size > 0; - if (running) requestAnimationFrame(run_tasks); + if (running) raf(run_tasks); } export function clear_loops() { @@ -26,7 +26,7 @@ export function loop(fn) { if (!running) { running = true; - requestAnimationFrame(run_tasks); + raf(run_tasks); } return { diff --git a/src/internal/style_manager.js b/src/internal/style_manager.js index d71e922f01..3679470399 100644 --- a/src/internal/style_manager.js +++ b/src/internal/style_manager.js @@ -1,4 +1,5 @@ import { element } from './dom.js'; +import { raf } from './utils.js'; let stylesheet; let active = 0; @@ -56,7 +57,7 @@ export function delete_rule(node, name) { } export function clear_rules() { - requestAnimationFrame(() => { + raf(() => { if (active) return; let i = stylesheet.cssRules.length; while (i--) stylesheet.deleteRule(i); diff --git a/src/internal/utils.js b/src/internal/utils.js index e6d66d8717..c493eacb96 100644 --- a/src/internal/utils.js +++ b/src/internal/utils.js @@ -80,11 +80,15 @@ export function exclude_internal_props(props) { return result; } -export let now = typeof window !== 'undefined' +const is_client = typeof window !== 'undefined'; + +export let now = is_client ? () => window.performance.now() : () => Date.now(); // used internally for testing export function set_now(fn) { now = fn; -} \ No newline at end of file +} + +export const raf = is_client ? requestAnimationFrame : noop; \ No newline at end of file From ef59c32099ef27620be6ad5759e136925db4d819 Mon Sep 17 00:00:00 2001 From: Timothy Johnson Date: Fri, 24 May 2019 16:31:01 -0700 Subject: [PATCH 80/87] Fixes #2714 --- src/parse/state/tag.ts | 9 +++++++-- src/parse/state/text.ts | 9 +++++++-- test/parser/samples/attribute-escaped/output.json | 3 ++- .../samples/convert-entities-in-element/output.json | 3 ++- test/parser/samples/convert-entities/output.json | 3 ++- test/parser/samples/nbsp/output.json | 3 ++- 6 files changed, 22 insertions(+), 8 deletions(-) diff --git a/src/parse/state/tag.ts b/src/parse/state/tag.ts index 56195549d8..fc5fc3620d 100644 --- a/src/parse/state/tag.ts +++ b/src/parse/state/tag.ts @@ -490,8 +490,13 @@ function read_sequence(parser: Parser, done: () => boolean) { if (current_chunk.data) chunks.push(current_chunk); chunks.forEach(chunk => { - if (chunk.type === 'Text') - chunk.data = decode_character_references(chunk.data); + if (chunk.type === 'Text') { + let decoded = decode_character_references(chunk.data); + if (chunk.data != decoded) { + chunk.raw = chunk.data; + chunk.data = decoded; + } + } }); return chunks; diff --git a/src/parse/state/text.ts b/src/parse/state/text.ts index f739c8cc9e..503d79aa08 100644 --- a/src/parse/state/text.ts +++ b/src/parse/state/text.ts @@ -14,10 +14,15 @@ export default function text(parser: Parser) { data += parser.template[parser.index++]; } - parser.current().children.push({ + let node = { start, end: parser.index, type: 'Text', data: decode_character_references(data), - }); + }; + + if (node.data != data) + node.raw = data; + + parser.current().children.push(node); } diff --git a/test/parser/samples/attribute-escaped/output.json b/test/parser/samples/attribute-escaped/output.json index 6a4143e674..79b135eb86 100644 --- a/test/parser/samples/attribute-escaped/output.json +++ b/test/parser/samples/attribute-escaped/output.json @@ -20,7 +20,8 @@ "start": 15, "end": 33, "type": "Text", - "data": "\"quoted\"" + "data": "\"quoted\"", + "raw": ""quoted"" } ] } diff --git a/test/parser/samples/convert-entities-in-element/output.json b/test/parser/samples/convert-entities-in-element/output.json index fb0f5b288e..92b5aafb00 100644 --- a/test/parser/samples/convert-entities-in-element/output.json +++ b/test/parser/samples/convert-entities-in-element/output.json @@ -15,7 +15,8 @@ "start": 3, "end": 20, "type": "Text", - "data": "Hello & World" + "data": "Hello & World", + "raw": "Hello & World" } ] } diff --git a/test/parser/samples/convert-entities/output.json b/test/parser/samples/convert-entities/output.json index ca1c1356f8..967895383d 100644 --- a/test/parser/samples/convert-entities/output.json +++ b/test/parser/samples/convert-entities/output.json @@ -8,7 +8,8 @@ "start": 0, "end": 17, "type": "Text", - "data": "Hello & World" + "data": "Hello & World", + "raw": "Hello & World" } ] }, diff --git a/test/parser/samples/nbsp/output.json b/test/parser/samples/nbsp/output.json index 4fa318ce48..c47257c873 100644 --- a/test/parser/samples/nbsp/output.json +++ b/test/parser/samples/nbsp/output.json @@ -15,7 +15,8 @@ "start": 6, "end": 12, "type": "Text", - "data": " " + "data": " ", + "raw": " " } ] } From 4c805018e4d20218e95017ca571fa908f10cdaec Mon Sep 17 00:00:00 2001 From: Elliot Waite <1767836+elliotwaite@users.noreply.github.com> Date: Fri, 24 May 2019 15:55:18 -1000 Subject: [PATCH 81/87] Fix CRUD example to allow changing input values. Currently, the first name and last name inputs fields can't be edited without the changes immediately being overwritten back to the selected person's first name and last name. This change will make it so that the input fields only get overwritten with the selected person's first name and last name when the selected person is changed. --- site/content/examples/19-7guis/05-7guis-crud/App.svelte | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) 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 : ''; } From 9d53f568fab23b82c8b344c5969c8bfab44de03a Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Sat, 25 May 2019 11:25:09 +0100 Subject: [PATCH 82/87] fix tests --- src/internal/utils.js | 6 +++++- test/js/samples/debug-hoisted/expected.js | 2 +- test/js/samples/media-bindings/expected.js | 3 ++- test/runtime/index.js | 6 +++--- 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/internal/utils.js b/src/internal/utils.js index c493eacb96..7823a5b920 100644 --- a/src/internal/utils.js +++ b/src/internal/utils.js @@ -86,9 +86,13 @@ export let now = is_client ? () => window.performance.now() : () => Date.now(); +export let raf = is_client ? requestAnimationFrame : noop; + // used internally for testing export function set_now(fn) { now = fn; } -export const raf = is_client ? requestAnimationFrame : noop; \ No newline at end of file +export function set_raf(fn) { + raf = fn; +} \ No newline at end of file diff --git a/test/js/samples/debug-hoisted/expected.js b/test/js/samples/debug-hoisted/expected.js index 153f92bad8..51d8bf63a3 100644 --- a/test/js/samples/debug-hoisted/expected.js +++ b/test/js/samples/debug-hoisted/expected.js @@ -53,4 +53,4 @@ class Component extends SvelteComponentDev { } } -export default Component; +export default Component; \ No newline at end of file diff --git a/test/js/samples/media-bindings/expected.js b/test/js/samples/media-bindings/expected.js index 8a193f698b..f45f9ce8db 100644 --- a/test/js/samples/media-bindings/expected.js +++ b/test/js/samples/media-bindings/expected.js @@ -8,6 +8,7 @@ import { insert, listen, noop, + raf, run_all, safe_not_equal, time_ranges_to_array @@ -18,7 +19,7 @@ function create_fragment(ctx) { function audio_timeupdate_handler() { cancelAnimationFrame(audio_animationframe); - if (!audio.paused) audio_animationframe = requestAnimationFrame(audio_timeupdate_handler); + if (!audio.paused) audio_animationframe = raf(audio_timeupdate_handler); audio_updating = true; ctx.audio_timeupdate_handler.call(audio); } 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`); From cce9f14e380db04f1365ca97ca0acc4f0ca1f619 Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Sun, 26 May 2019 13:49:06 +0200 Subject: [PATCH 83/87] fix test --- test/runtime/samples/binding-details-open/_config.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/runtime/samples/binding-details-open/_config.js b/test/runtime/samples/binding-details-open/_config.js index e5e81b2c93..cf2459c3f1 100644 --- a/test/runtime/samples/binding-details-open/_config.js +++ b/test/runtime/samples/binding-details-open/_config.js @@ -9,7 +9,7 @@ export default { details.open = true; await details.dispatchEvent(event); - assert.equal(component.open, true); + assert.equal(component.visible, true); assert.htmlEqual(target.innerHTML, `
    toggle

    hello!

    @@ -17,9 +17,9 @@ export default { details.open = false; await details.dispatchEvent(event); - assert.equal(component.open, false); + assert.equal(component.visible, false); assert.htmlEqual(target.innerHTML, ` -
    toggle
    +
    toggle
    `); } }; From 089149564799fd4f22799128315bc91208dda84f Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Sun, 26 May 2019 14:04:29 +0200 Subject: [PATCH 84/87] code style --- src/compile/render-dom/index.ts | 12 ++++++------ test/js/samples/bind-open/expected.js | 2 +- test/js/samples/debug-empty/expected.js | 6 +++--- test/js/samples/debug-foo-bar-baz-things/expected.js | 6 +++--- test/js/samples/debug-foo/expected.js | 6 +++--- .../dev-warning-missing-data-computed/expected.js | 6 +++--- .../samples/dev-warning-unknown-props/_config.js | 2 +- 7 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/compile/render-dom/index.ts b/src/compile/render-dom/index.ts index e7f063d086..1432813e9d 100644 --- a/src/compile/render-dom/index.ts +++ b/src/compile/render-dom/index.ts @@ -394,12 +394,12 @@ export default function dom( return $name; }); - let unknownPropsCheck; + let unknown_props_check; if (component.compile_options.dev && writable_props.length) { - unknownPropsCheck = deindent` - const writableProps = [${writable_props.map(prop => `'${prop.export_name}'`).join(', ')}]; + unknown_props_check = deindent` + const writable_props = [${writable_props.map(prop => `'${prop.export_name}'`).join(', ')}]; Object.keys($$props).forEach(key => { - if (!writableProps.includes(key)) console.warn(\`<${component.tag}> was created with unknown attribute '\${key}'\`); + if (!writable_props.includes(key)) console.warn(\`<${component.tag}> was created with unknown prop '\${key}'\`); }); `; } @@ -413,8 +413,8 @@ export default function dom( ${resubscribable_reactive_store_unsubscribers} ${component.javascript} - - ${unknownPropsCheck} + + ${unknown_props_check} ${component.slots.size && `let { $$slots = {}, $$scope } = $$props;`} diff --git a/test/js/samples/bind-open/expected.js b/test/js/samples/bind-open/expected.js index 7c73c8ddac..7f739aec8b 100644 --- a/test/js/samples/bind-open/expected.js +++ b/test/js/samples/bind-open/expected.js @@ -66,4 +66,4 @@ class Component extends SvelteComponent { } } -export default Component; +export default Component; \ No newline at end of file diff --git a/test/js/samples/debug-empty/expected.js b/test/js/samples/debug-empty/expected.js index 9b6ef447b4..c82cbeddd3 100644 --- a/test/js/samples/debug-empty/expected.js +++ b/test/js/samples/debug-empty/expected.js @@ -65,9 +65,9 @@ function create_fragment(ctx) { function instance($$self, $$props, $$invalidate) { let { name } = $$props; - const writableProps = ['name']; + const writable_props = ['name']; Object.keys($$props).forEach(key => { - if (!writableProps.includes(key)) console.warn(` was created with unknown attribute '${key}'`); + if (!writable_props.includes(key)) console.warn(` was created with unknown prop '${key}'`); }); $$self.$set = $$props => { @@ -98,4 +98,4 @@ class Component extends SvelteComponentDev { } } -export default Component; +export default Component; \ No newline at end of file diff --git a/test/js/samples/debug-foo-bar-baz-things/expected.js b/test/js/samples/debug-foo-bar-baz-things/expected.js index 006b25aba5..3e1571b890 100644 --- a/test/js/samples/debug-foo-bar-baz-things/expected.js +++ b/test/js/samples/debug-foo-bar-baz-things/expected.js @@ -151,9 +151,9 @@ function create_fragment(ctx) { function instance($$self, $$props, $$invalidate) { let { things, foo, bar, baz } = $$props; - const writableProps = ['things', 'foo', 'bar', 'baz']; + const writable_props = ['things', 'foo', 'bar', 'baz']; Object.keys($$props).forEach(key => { - if (!writableProps.includes(key)) console.warn(` was created with unknown attribute '${key}'`); + if (!writable_props.includes(key)) console.warn(` was created with unknown prop '${key}'`); }); $$self.$set = $$props => { @@ -220,4 +220,4 @@ class Component extends SvelteComponentDev { } } -export default Component; +export default Component; \ No newline at end of file diff --git a/test/js/samples/debug-foo/expected.js b/test/js/samples/debug-foo/expected.js index 7bc58434a8..1af0fcaebe 100644 --- a/test/js/samples/debug-foo/expected.js +++ b/test/js/samples/debug-foo/expected.js @@ -151,9 +151,9 @@ function create_fragment(ctx) { function instance($$self, $$props, $$invalidate) { let { things, foo } = $$props; - const writableProps = ['things', 'foo']; + const writable_props = ['things', 'foo']; Object.keys($$props).forEach(key => { - if (!writableProps.includes(key)) console.warn(` was created with unknown attribute '${key}'`); + if (!writable_props.includes(key)) console.warn(` was created with unknown prop '${key}'`); }); $$self.$set = $$props => { @@ -196,4 +196,4 @@ class Component extends SvelteComponentDev { } } -export default Component; +export default Component; \ No newline at end of file diff --git a/test/js/samples/dev-warning-missing-data-computed/expected.js b/test/js/samples/dev-warning-missing-data-computed/expected.js index e181486512..0c193934c0 100644 --- a/test/js/samples/dev-warning-missing-data-computed/expected.js +++ b/test/js/samples/dev-warning-missing-data-computed/expected.js @@ -65,9 +65,9 @@ function instance($$self, $$props, $$invalidate) { let bar; - const writableProps = ['foo']; + const writable_props = ['foo']; Object.keys($$props).forEach(key => { - if (!writableProps.includes(key)) console.warn(` was created with unknown attribute '${key}'`); + if (!writable_props.includes(key)) console.warn(` was created with unknown prop '${key}'`); }); $$self.$set = $$props => { @@ -102,4 +102,4 @@ class Component extends SvelteComponentDev { } } -export default Component; +export default Component; \ No newline at end of file diff --git a/test/runtime/samples/dev-warning-unknown-props/_config.js b/test/runtime/samples/dev-warning-unknown-props/_config.js index 31b605e214..9bff4a2a74 100644 --- a/test/runtime/samples/dev-warning-unknown-props/_config.js +++ b/test/runtime/samples/dev-warning-unknown-props/_config.js @@ -4,6 +4,6 @@ export default { }, warnings: [ - ` was created with unknown attribute 'fo'` + ` was created with unknown prop 'fo'` ] }; From 0d7f6fb795fc461aced9c3470932d715caf395f5 Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Sun, 26 May 2019 14:29:30 +0200 Subject: [PATCH 85/87] flesh out in/out transition tutorial chapter (#2792) --- .../content/tutorial/10-transitions/03-in-and-out/text.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) 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

    From b7f9c9c95444fb15d20eaa170253f1c3982c1148 Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Sun, 26 May 2019 14:48:10 +0200 Subject: [PATCH 86/87] always add raw property to text nodes --- src/parse/state/tag.ts | 36 ++++++++----------- src/parse/state/text.ts | 4 +-- .../samples/action-with-call/output.json | 5 +-- .../action-with-identifier/output.json | 5 +-- .../samples/action-with-literal/output.json | 5 +-- test/parser/samples/action/output.json | 5 +-- test/parser/samples/animation/output.json | 6 ++-- .../attribute-containing-solidus/output.json | 7 ++-- .../attribute-dynamic-boolean/output.json | 5 +-- .../attribute-dynamic-reserved/output.json | 5 +-- .../samples/attribute-dynamic/output.json | 9 +++-- .../samples/attribute-escaped/output.json | 9 ++--- .../samples/attribute-multiple/output.json | 7 ++-- .../samples/attribute-shorthand/output.json | 5 +-- .../attribute-static-boolean/output.json | 5 +-- .../samples/attribute-static/output.json | 6 ++-- .../samples/attribute-unquoted/output.json | 6 ++-- .../samples/await-then-catch/output.json | 28 +++++++++------ .../samples/binding-shorthand/output.json | 1 + test/parser/samples/binding/output.json | 1 + test/parser/samples/comment/output.json | 5 +-- .../samples/component-dynamic/output.json | 5 +-- .../convert-entities-in-element/output.json | 9 ++--- .../samples/convert-entities/output.json | 9 ++--- test/parser/samples/css/output.json | 6 ++-- .../parser/samples/dynamic-import/output.json | 5 ++- .../each-block-destructured/output.json | 8 ++--- .../samples/each-block-else/output.json | 6 ++-- .../samples/each-block-indexed/output.json | 6 ++-- .../samples/each-block-keyed/output.json | 5 +-- test/parser/samples/each-block/output.json | 5 +-- .../samples/element-with-mustache/output.json | 7 ++-- .../samples/element-with-text/output.json | 6 ++-- test/parser/samples/elements/output.json | 5 +-- test/parser/samples/event-handler/output.json | 10 +++--- test/parser/samples/if-block-else/output.json | 7 ++-- .../samples/if-block-elseif/output.json | 2 ++ test/parser/samples/if-block/output.json | 6 ++-- .../samples/implicitly-closed-li/output.json | 9 ++--- test/parser/samples/nbsp/output.json | 9 ++--- test/parser/samples/raw-mustaches/output.json | 8 ++--- test/parser/samples/refs/output.json | 1 + .../samples/script-comment-only/output.json | 1 + .../output.json | 3 ++ .../script-comment-trailing/output.json | 3 ++ test/parser/samples/script/output.json | 3 ++ .../samples/self-closing-element/output.json | 5 +-- .../parser/samples/self-reference/output.json | 5 +-- .../space-between-mustaches/output.json | 9 ++--- test/parser/samples/spread/output.json | 5 +-- .../samples/textarea-children/output.json | 9 +++-- .../transition-intro-no-params/output.json | 6 ++-- .../samples/transition-intro/output.json | 6 ++-- .../samples/unusual-identifier/output.json | 5 +-- .../whitespace-leading-trailing/output.json | 7 ++-- .../samples/whitespace-normal/output.json | 8 ++--- test/parser/samples/yield/output.json | 5 +-- 57 files changed, 150 insertions(+), 229 deletions(-) diff --git a/src/parse/state/tag.ts b/src/parse/state/tag.ts index d6e9706714..108cfce3e1 100644 --- a/src/parse/state/tag.ts +++ b/src/parse/state/tag.ts @@ -476,35 +476,28 @@ function read_sequence(parser: Parser, done: () => boolean): Node[] { start: parser.index, end: null, type: 'Text', - data: '', + raw: '', + data: null }; + function flush() { + if (current_chunk.raw) { + current_chunk.data = decode_character_references(current_chunk.raw); + current_chunk.end = parser.index; + chunks.push(current_chunk); + } + } + const chunks: Node[] = []; while (parser.index < parser.template.length) { const index = parser.index; if (done()) { - current_chunk.end = parser.index; - - if (current_chunk.data) chunks.push(current_chunk); - - chunks.forEach(chunk => { - if (chunk.type === 'Text') { - let decoded = decode_character_references(chunk.data); - if (chunk.data != decoded) { - chunk.raw = chunk.data; - chunk.data = decoded; - } - } - }); - + flush(); return chunks; } else if (parser.eat('{')) { - if (current_chunk.data) { - current_chunk.end = index; - chunks.push(current_chunk); - } + flush(); parser.allow_whitespace(); const expression = read_expression(parser); @@ -522,10 +515,11 @@ function read_sequence(parser: Parser, done: () => boolean): Node[] { start: parser.index, end: null, type: 'Text', - data: '', + raw: '', + data: null }; } else { - current_chunk.data += parser.template[parser.index++]; + current_chunk.raw += parser.template[parser.index++]; } } diff --git a/src/parse/state/text.ts b/src/parse/state/text.ts index 503d79aa08..1d9099055e 100644 --- a/src/parse/state/text.ts +++ b/src/parse/state/text.ts @@ -18,11 +18,9 @@ export default function text(parser: Parser) { start, end: parser.index, type: 'Text', + raw: data, data: decode_character_references(data), }; - if (node.data != data) - node.raw = data; - parser.current().children.push(node); } diff --git a/test/parser/samples/action-with-call/output.json b/test/parser/samples/action-with-call/output.json index d6aaa72892..e910f0b49f 100644 --- a/test/parser/samples/action-with-call/output.json +++ b/test/parser/samples/action-with-call/output.json @@ -41,8 +41,5 @@ "children": [] } ] - }, - "css": null, - "instance": null, - "module": null + } } \ No newline at end of file diff --git a/test/parser/samples/action-with-identifier/output.json b/test/parser/samples/action-with-identifier/output.json index d58b9097b7..435aee4444 100644 --- a/test/parser/samples/action-with-identifier/output.json +++ b/test/parser/samples/action-with-identifier/output.json @@ -27,8 +27,5 @@ "children": [] } ] - }, - "css": null, - "instance": null, - "module": null + } } \ No newline at end of file diff --git a/test/parser/samples/action-with-literal/output.json b/test/parser/samples/action-with-literal/output.json index 4a6f596d10..01a6b67549 100644 --- a/test/parser/samples/action-with-literal/output.json +++ b/test/parser/samples/action-with-literal/output.json @@ -28,8 +28,5 @@ "children": [] } ] - }, - "css": null, - "instance": null, - "module": null + } } \ No newline at end of file diff --git a/test/parser/samples/action/output.json b/test/parser/samples/action/output.json index 2f553b5efa..9828e200dd 100644 --- a/test/parser/samples/action/output.json +++ b/test/parser/samples/action/output.json @@ -22,8 +22,5 @@ "children": [] } ] - }, - "css": null, - "instance": null, - "module": null + } } \ No newline at end of file diff --git a/test/parser/samples/animation/output.json b/test/parser/samples/animation/output.json index 8332b3ad04..f4d183eb5c 100644 --- a/test/parser/samples/animation/output.json +++ b/test/parser/samples/animation/output.json @@ -35,6 +35,7 @@ "start": 51, "end": 56, "type": "Text", + "raw": "flips", "data": "flips" } ] @@ -54,8 +55,5 @@ } } ] - }, - "css": null, - "instance": null, - "module": null + } } \ No newline at end of file diff --git a/test/parser/samples/attribute-containing-solidus/output.json b/test/parser/samples/attribute-containing-solidus/output.json index 95372bd77d..f1158b4f50 100644 --- a/test/parser/samples/attribute-containing-solidus/output.json +++ b/test/parser/samples/attribute-containing-solidus/output.json @@ -20,6 +20,7 @@ "start": 8, "end": 30, "type": "Text", + "raw": "https://www.google.com", "data": "https://www.google.com" } ] @@ -30,13 +31,11 @@ "start": 31, "end": 37, "type": "Text", + "raw": "Google", "data": "Google" } ] } ] - }, - "css": null, - "instance": null, - "module": null + } } \ No newline at end of file diff --git a/test/parser/samples/attribute-dynamic-boolean/output.json b/test/parser/samples/attribute-dynamic-boolean/output.json index 81a19f49b9..478144152a 100644 --- a/test/parser/samples/attribute-dynamic-boolean/output.json +++ b/test/parser/samples/attribute-dynamic-boolean/output.json @@ -33,8 +33,5 @@ "children": [] } ] - }, - "css": null, - "instance": null, - "module": null + } } \ No newline at end of file diff --git a/test/parser/samples/attribute-dynamic-reserved/output.json b/test/parser/samples/attribute-dynamic-reserved/output.json index 3a830d448f..22be3c9087 100644 --- a/test/parser/samples/attribute-dynamic-reserved/output.json +++ b/test/parser/samples/attribute-dynamic-reserved/output.json @@ -33,8 +33,5 @@ "children": [] } ] - }, - "css": null, - "instance": null, - "module": null + } } \ No newline at end of file diff --git a/test/parser/samples/attribute-dynamic/output.json b/test/parser/samples/attribute-dynamic/output.json index 50d8ec60a5..a48f376876 100644 --- a/test/parser/samples/attribute-dynamic/output.json +++ b/test/parser/samples/attribute-dynamic/output.json @@ -18,8 +18,9 @@ "value": [ { "start": 12, - "end": 19, + "end": 20, "type": "Text", + "raw": "color: ", "data": "color: " }, { @@ -37,6 +38,7 @@ "start": 26, "end": 27, "type": "Text", + "raw": ";", "data": ";" } ] @@ -57,8 +59,5 @@ ] } ] - }, - "css": null, - "instance": null, - "module": null + } } \ No newline at end of file diff --git a/test/parser/samples/attribute-escaped/output.json b/test/parser/samples/attribute-escaped/output.json index 79b135eb86..e60a8c2531 100644 --- a/test/parser/samples/attribute-escaped/output.json +++ b/test/parser/samples/attribute-escaped/output.json @@ -20,8 +20,8 @@ "start": 15, "end": 33, "type": "Text", - "data": "\"quoted\"", - "raw": ""quoted"" + "raw": ""quoted"", + "data": "\"quoted\"" } ] } @@ -29,8 +29,5 @@ "children": [] } ] - }, - "css": null, - "instance": null, - "module": null + } } \ No newline at end of file diff --git a/test/parser/samples/attribute-multiple/output.json b/test/parser/samples/attribute-multiple/output.json index 668409c0ef..c4be13e6ee 100644 --- a/test/parser/samples/attribute-multiple/output.json +++ b/test/parser/samples/attribute-multiple/output.json @@ -20,6 +20,7 @@ "start": 9, "end": 10, "type": "Text", + "raw": "x", "data": "x" } ] @@ -34,6 +35,7 @@ "start": 19, "end": 20, "type": "Text", + "raw": "y", "data": "y" } ] @@ -42,8 +44,5 @@ "children": [] } ] - }, - "css": null, - "instance": null, - "module": null + } } \ No newline at end of file diff --git a/test/parser/samples/attribute-shorthand/output.json b/test/parser/samples/attribute-shorthand/output.json index 08ddf5eda9..f23e62b04e 100644 --- a/test/parser/samples/attribute-shorthand/output.json +++ b/test/parser/samples/attribute-shorthand/output.json @@ -33,8 +33,5 @@ "children": [] } ] - }, - "css": null, - "instance": null, - "module": null + } } \ No newline at end of file diff --git a/test/parser/samples/attribute-static-boolean/output.json b/test/parser/samples/attribute-static-boolean/output.json index f63b5734e0..7d635004c1 100644 --- a/test/parser/samples/attribute-static-boolean/output.json +++ b/test/parser/samples/attribute-static-boolean/output.json @@ -21,8 +21,5 @@ "children": [] } ] - }, - "css": null, - "instance": null, - "module": null + } } \ No newline at end of file diff --git a/test/parser/samples/attribute-static/output.json b/test/parser/samples/attribute-static/output.json index 3185e48736..37b41d9a89 100644 --- a/test/parser/samples/attribute-static/output.json +++ b/test/parser/samples/attribute-static/output.json @@ -20,6 +20,7 @@ "start": 12, "end": 15, "type": "Text", + "raw": "foo", "data": "foo" } ] @@ -28,8 +29,5 @@ "children": [] } ] - }, - "css": null, - "instance": null, - "module": null + } } \ No newline at end of file diff --git a/test/parser/samples/attribute-unquoted/output.json b/test/parser/samples/attribute-unquoted/output.json index c7556f2eba..11fa397819 100644 --- a/test/parser/samples/attribute-unquoted/output.json +++ b/test/parser/samples/attribute-unquoted/output.json @@ -20,6 +20,7 @@ "start": 11, "end": 14, "type": "Text", + "raw": "foo", "data": "foo" } ] @@ -28,8 +29,5 @@ "children": [] } ] - }, - "css": null, - "instance": null, - "module": null + } } \ No newline at end of file diff --git a/test/parser/samples/await-then-catch/output.json b/test/parser/samples/await-then-catch/output.json index f62ad16574..ac598a403a 100644 --- a/test/parser/samples/await-then-catch/output.json +++ b/test/parser/samples/await-then-catch/output.json @@ -19,13 +19,13 @@ "pending": { "start": 19, "end": 39, - "skip": false, "type": "PendingBlock", "children": [ { "start": 19, "end": 21, "type": "Text", + "raw": "\n\t", "data": "\n\t" }, { @@ -39,6 +39,7 @@ "start": 24, "end": 34, "type": "Text", + "raw": "loading...", "data": "loading..." } ] @@ -47,20 +48,22 @@ "start": 38, "end": 39, "type": "Text", + "raw": "\n", "data": "\n" } - ] + ], + "skip": false }, "then": { "start": 39, "end": 88, - "skip": false, "type": "ThenBlock", "children": [ { "start": 55, "end": 57, "type": "Text", + "raw": "\n\t", "data": "\n\t" }, { @@ -74,6 +77,7 @@ "start": 60, "end": 73, "type": "Text", + "raw": "the value is ", "data": "the value is " }, { @@ -93,20 +97,22 @@ "start": 87, "end": 88, "type": "Text", + "raw": "\n", "data": "\n" } - ] + ], + "skip": false }, "catch": { "start": 88, "end": 140, - "skip": false, "type": "CatchBlock", "children": [ { "start": 105, "end": 107, "type": "Text", + "raw": "\n\t", "data": "\n\t" }, { @@ -120,6 +126,7 @@ "start": 110, "end": 117, "type": "Text", + "raw": "oh no! ", "data": "oh no! " }, { @@ -151,14 +158,13 @@ "start": 139, "end": 140, "type": "Text", + "raw": "\n", "data": "\n" } - ] + ], + "skip": false } } ] - }, - "css": null, - "instance": null, - "module": null -} + } +} \ No newline at end of file diff --git a/test/parser/samples/binding-shorthand/output.json b/test/parser/samples/binding-shorthand/output.json index 8f92101042..7fe7acb5b3 100644 --- a/test/parser/samples/binding-shorthand/output.json +++ b/test/parser/samples/binding-shorthand/output.json @@ -8,6 +8,7 @@ "start": 28, "end": 30, "type": "Text", + "raw": "\n\n", "data": "\n\n" }, { diff --git a/test/parser/samples/binding/output.json b/test/parser/samples/binding/output.json index d084050617..72ad60202c 100644 --- a/test/parser/samples/binding/output.json +++ b/test/parser/samples/binding/output.json @@ -8,6 +8,7 @@ "start": 29, "end": 31, "type": "Text", + "raw": "\n\n", "data": "\n\n" }, { diff --git a/test/parser/samples/comment/output.json b/test/parser/samples/comment/output.json index 89295c188a..2a57c4fa5d 100644 --- a/test/parser/samples/comment/output.json +++ b/test/parser/samples/comment/output.json @@ -11,8 +11,5 @@ "data": " a comment " } ] - }, - "css": null, - "instance": null, - "module": null + } } \ No newline at end of file diff --git a/test/parser/samples/component-dynamic/output.json b/test/parser/samples/component-dynamic/output.json index c2e4e3ee79..77837d1ca9 100644 --- a/test/parser/samples/component-dynamic/output.json +++ b/test/parser/samples/component-dynamic/output.json @@ -36,8 +36,5 @@ } } ] - }, - "css": null, - "instance": null, - "module": null + } } \ No newline at end of file diff --git a/test/parser/samples/convert-entities-in-element/output.json b/test/parser/samples/convert-entities-in-element/output.json index 92b5aafb00..c830c276de 100644 --- a/test/parser/samples/convert-entities-in-element/output.json +++ b/test/parser/samples/convert-entities-in-element/output.json @@ -15,14 +15,11 @@ "start": 3, "end": 20, "type": "Text", - "data": "Hello & World", - "raw": "Hello & World" + "raw": "Hello & World", + "data": "Hello & World" } ] } ] - }, - "css": null, - "instance": null, - "module": null + } } \ No newline at end of file diff --git a/test/parser/samples/convert-entities/output.json b/test/parser/samples/convert-entities/output.json index 967895383d..f4cc1a6662 100644 --- a/test/parser/samples/convert-entities/output.json +++ b/test/parser/samples/convert-entities/output.json @@ -8,12 +8,9 @@ "start": 0, "end": 17, "type": "Text", - "data": "Hello & World", - "raw": "Hello & World" + "raw": "Hello & World", + "data": "Hello & World" } ] - }, - "css": null, - "instance": null, - "module": null + } } \ No newline at end of file diff --git a/test/parser/samples/css/output.json b/test/parser/samples/css/output.json index 3127e01c71..12d74ae7f8 100644 --- a/test/parser/samples/css/output.json +++ b/test/parser/samples/css/output.json @@ -15,6 +15,7 @@ "start": 5, "end": 8, "type": "Text", + "raw": "foo", "data": "foo" } ] @@ -23,6 +24,7 @@ "start": 14, "end": 16, "type": "Text", + "raw": "\n\n", "data": "\n\n" } ] @@ -90,7 +92,5 @@ "end": 48, "styles": "\n\tdiv {\n\t\tcolor: red;\n\t}\n" } - }, - "instance": null, - "module": null + } } \ No newline at end of file diff --git a/test/parser/samples/dynamic-import/output.json b/test/parser/samples/dynamic-import/output.json index c0d4a45e0d..fa1acf7d9b 100644 --- a/test/parser/samples/dynamic-import/output.json +++ b/test/parser/samples/dynamic-import/output.json @@ -5,7 +5,6 @@ "type": "Fragment", "children": [] }, - "css": null, "instance": { "start": 0, "end": 146, @@ -66,8 +65,8 @@ "start": 54, "end": 134, "id": null, - "generator": false, "expression": false, + "generator": false, "async": false, "params": [], "body": { @@ -120,8 +119,8 @@ "start": 88, "end": 129, "id": null, - "generator": false, "expression": false, + "generator": false, "async": false, "params": [ { diff --git a/test/parser/samples/each-block-destructured/output.json b/test/parser/samples/each-block-destructured/output.json index 0c4b1a5c54..6368b445d6 100644 --- a/test/parser/samples/each-block-destructured/output.json +++ b/test/parser/samples/each-block-destructured/output.json @@ -37,6 +37,7 @@ "start": 50, "end": 52, "type": "Text", + "raw": ": ", "data": ": " }, { @@ -80,8 +81,5 @@ } } ] - }, - "css": null, - "instance": null, - "module": null -} + } +} \ No newline at end of file diff --git a/test/parser/samples/each-block-else/output.json b/test/parser/samples/each-block-else/output.json index aefc8c2f39..1e8ac455e6 100644 --- a/test/parser/samples/each-block-else/output.json +++ b/test/parser/samples/each-block-else/output.json @@ -58,6 +58,7 @@ "start": 55, "end": 65, "type": "Text", + "raw": "no animals", "data": "no animals" } ] @@ -66,8 +67,5 @@ } } ] - }, - "css": null, - "instance": null, - "module": null + } } \ No newline at end of file diff --git a/test/parser/samples/each-block-indexed/output.json b/test/parser/samples/each-block-indexed/output.json index 7518652468..77417ba67a 100644 --- a/test/parser/samples/each-block-indexed/output.json +++ b/test/parser/samples/each-block-indexed/output.json @@ -37,6 +37,7 @@ "start": 36, "end": 38, "type": "Text", + "raw": ": ", "data": ": " }, { @@ -62,8 +63,5 @@ "index": "i" } ] - }, - "css": null, - "instance": null, - "module": null + } } \ No newline at end of file diff --git a/test/parser/samples/each-block-keyed/output.json b/test/parser/samples/each-block-keyed/output.json index fe893bcdb9..11cdd45ff1 100644 --- a/test/parser/samples/each-block-keyed/output.json +++ b/test/parser/samples/each-block-keyed/output.json @@ -62,8 +62,5 @@ } } ] - }, - "css": null, - "instance": null, - "module": null + } } \ No newline at end of file diff --git a/test/parser/samples/each-block/output.json b/test/parser/samples/each-block/output.json index c16a71ad5d..6a60823952 100644 --- a/test/parser/samples/each-block/output.json +++ b/test/parser/samples/each-block/output.json @@ -44,8 +44,5 @@ } } ] - }, - "css": null, - "instance": null, - "module": null + } } \ No newline at end of file diff --git a/test/parser/samples/element-with-mustache/output.json b/test/parser/samples/element-with-mustache/output.json index c8a386d681..f7c2e9936b 100644 --- a/test/parser/samples/element-with-mustache/output.json +++ b/test/parser/samples/element-with-mustache/output.json @@ -15,6 +15,7 @@ "start": 4, "end": 10, "type": "Text", + "raw": "hello ", "data": "hello " }, { @@ -32,13 +33,11 @@ "start": 16, "end": 17, "type": "Text", + "raw": "!", "data": "!" } ] } ] - }, - "css": null, - "instance": null, - "module": null + } } \ No newline at end of file diff --git a/test/parser/samples/element-with-text/output.json b/test/parser/samples/element-with-text/output.json index 70f6163c93..b0e0f5c6cc 100644 --- a/test/parser/samples/element-with-text/output.json +++ b/test/parser/samples/element-with-text/output.json @@ -15,13 +15,11 @@ "start": 6, "end": 10, "type": "Text", + "raw": "test", "data": "test" } ] } ] - }, - "css": null, - "instance": null, - "module": null + } } \ No newline at end of file diff --git a/test/parser/samples/elements/output.json b/test/parser/samples/elements/output.json index d216f7f5d8..75548c20f0 100644 --- a/test/parser/samples/elements/output.json +++ b/test/parser/samples/elements/output.json @@ -21,8 +21,5 @@ "children": [] } ] - }, - "css": null, - "instance": null, - "module": null + } } \ No newline at end of file diff --git a/test/parser/samples/event-handler/output.json b/test/parser/samples/event-handler/output.json index b1fe89fc2a..f792ffadcc 100644 --- a/test/parser/samples/event-handler/output.json +++ b/test/parser/samples/event-handler/output.json @@ -21,8 +21,8 @@ "start": 19, "end": 43, "id": null, - "generator": false, "expression": true, + "generator": false, "async": false, "params": [], "body": { @@ -58,6 +58,7 @@ "start": 46, "end": 52, "type": "Text", + "raw": "toggle", "data": "toggle" } ] @@ -66,6 +67,7 @@ "start": 61, "end": 63, "type": "Text", + "raw": "\n\n", "data": "\n\n" }, { @@ -90,6 +92,7 @@ "start": 81, "end": 87, "type": "Text", + "raw": "hello!", "data": "hello!" } ] @@ -97,8 +100,5 @@ ] } ] - }, - "css": null, - "instance": null, - "module": null + } } \ No newline at end of file diff --git a/test/parser/samples/if-block-else/output.json b/test/parser/samples/if-block-else/output.json index dedf2797c4..8b22cfa26b 100644 --- a/test/parser/samples/if-block-else/output.json +++ b/test/parser/samples/if-block-else/output.json @@ -26,6 +26,7 @@ "start": 14, "end": 17, "type": "Text", + "raw": "foo", "data": "foo" } ] @@ -47,6 +48,7 @@ "start": 34, "end": 41, "type": "Text", + "raw": "not foo", "data": "not foo" } ] @@ -55,8 +57,5 @@ } } ] - }, - "css": null, - "instance": null, - "module": null + } } \ No newline at end of file diff --git a/test/parser/samples/if-block-elseif/output.json b/test/parser/samples/if-block-elseif/output.json index 188b57aaad..54fb53dacb 100644 --- a/test/parser/samples/if-block-elseif/output.json +++ b/test/parser/samples/if-block-elseif/output.json @@ -39,6 +39,7 @@ "start": 17, "end": 37, "type": "Text", + "raw": "x is greater than 10", "data": "x is greater than 10" } ] @@ -85,6 +86,7 @@ "start": 63, "end": 79, "type": "Text", + "raw": "x is less than 5", "data": "x is less than 5" } ] diff --git a/test/parser/samples/if-block/output.json b/test/parser/samples/if-block/output.json index d560824766..1714bb7141 100644 --- a/test/parser/samples/if-block/output.json +++ b/test/parser/samples/if-block/output.json @@ -19,13 +19,11 @@ "start": 9, "end": 12, "type": "Text", + "raw": "bar", "data": "bar" } ] } ] - }, - "css": null, - "instance": null, - "module": null + } } \ No newline at end of file diff --git a/test/parser/samples/implicitly-closed-li/output.json b/test/parser/samples/implicitly-closed-li/output.json index caf69d7109..f46a2b1a26 100644 --- a/test/parser/samples/implicitly-closed-li/output.json +++ b/test/parser/samples/implicitly-closed-li/output.json @@ -15,6 +15,7 @@ "start": 4, "end": 6, "type": "Text", + "raw": "\n\t", "data": "\n\t" }, { @@ -28,6 +29,7 @@ "start": 10, "end": 13, "type": "Text", + "raw": "a\n\t", "data": "a\n\t" } ] @@ -43,6 +45,7 @@ "start": 17, "end": 20, "type": "Text", + "raw": "b\n\t", "data": "b\n\t" } ] @@ -58,6 +61,7 @@ "start": 24, "end": 26, "type": "Text", + "raw": "c\n", "data": "c\n" } ] @@ -65,8 +69,5 @@ ] } ] - }, - "css": null, - "instance": null, - "module": null + } } \ No newline at end of file diff --git a/test/parser/samples/nbsp/output.json b/test/parser/samples/nbsp/output.json index c47257c873..044de64cba 100644 --- a/test/parser/samples/nbsp/output.json +++ b/test/parser/samples/nbsp/output.json @@ -15,14 +15,11 @@ "start": 6, "end": 12, "type": "Text", - "data": " ", - "raw": " " + "raw": " ", + "data": " " } ] } ] - }, - "css": null, - "instance": null, - "module": null + } } \ No newline at end of file diff --git a/test/parser/samples/raw-mustaches/output.json b/test/parser/samples/raw-mustaches/output.json index 1d92b21c85..1b3d9b7a9c 100644 --- a/test/parser/samples/raw-mustaches/output.json +++ b/test/parser/samples/raw-mustaches/output.json @@ -15,6 +15,7 @@ "start": 3, "end": 4, "type": "Text", + "raw": " ", "data": " " }, { @@ -32,6 +33,7 @@ "start": 16, "end": 17, "type": "Text", + "raw": " ", "data": " " }, { @@ -49,13 +51,11 @@ "start": 29, "end": 30, "type": "Text", + "raw": " ", "data": " " } ] } ] - }, - "css": null, - "instance": null, - "module": null + } } \ No newline at end of file diff --git a/test/parser/samples/refs/output.json b/test/parser/samples/refs/output.json index d15753b0a2..e09383f9b6 100644 --- a/test/parser/samples/refs/output.json +++ b/test/parser/samples/refs/output.json @@ -8,6 +8,7 @@ "start": 28, "end": 30, "type": "Text", + "raw": "\n\n", "data": "\n\n" }, { diff --git a/test/parser/samples/script-comment-only/output.json b/test/parser/samples/script-comment-only/output.json index 95ca769b20..ba28434318 100644 --- a/test/parser/samples/script-comment-only/output.json +++ b/test/parser/samples/script-comment-only/output.json @@ -8,6 +8,7 @@ "start": 43, "end": 45, "type": "Text", + "raw": "\n\n", "data": "\n\n" }, { diff --git a/test/parser/samples/script-comment-trailing-multiline/output.json b/test/parser/samples/script-comment-trailing-multiline/output.json index d4a45911a1..7d01599efa 100644 --- a/test/parser/samples/script-comment-trailing-multiline/output.json +++ b/test/parser/samples/script-comment-trailing-multiline/output.json @@ -8,6 +8,7 @@ "start": 77, "end": 79, "type": "Text", + "raw": "\n\n", "data": "\n\n" }, { @@ -21,6 +22,7 @@ "start": 83, "end": 89, "type": "Text", + "raw": "Hello ", "data": "Hello " }, { @@ -38,6 +40,7 @@ "start": 95, "end": 96, "type": "Text", + "raw": "!", "data": "!" } ] diff --git a/test/parser/samples/script-comment-trailing/output.json b/test/parser/samples/script-comment-trailing/output.json index 92d431b558..bc8f3e4e67 100644 --- a/test/parser/samples/script-comment-trailing/output.json +++ b/test/parser/samples/script-comment-trailing/output.json @@ -8,6 +8,7 @@ "start": 66, "end": 68, "type": "Text", + "raw": "\n\n", "data": "\n\n" }, { @@ -21,6 +22,7 @@ "start": 72, "end": 78, "type": "Text", + "raw": "Hello ", "data": "Hello " }, { @@ -38,6 +40,7 @@ "start": 84, "end": 85, "type": "Text", + "raw": "!", "data": "!" } ] diff --git a/test/parser/samples/script/output.json b/test/parser/samples/script/output.json index 95966f5dc6..75aa0a7d2c 100644 --- a/test/parser/samples/script/output.json +++ b/test/parser/samples/script/output.json @@ -8,6 +8,7 @@ "start": 39, "end": 41, "type": "Text", + "raw": "\n\n", "data": "\n\n" }, { @@ -21,6 +22,7 @@ "start": 45, "end": 51, "type": "Text", + "raw": "Hello ", "data": "Hello " }, { @@ -38,6 +40,7 @@ "start": 57, "end": 58, "type": "Text", + "raw": "!", "data": "!" } ] diff --git a/test/parser/samples/self-closing-element/output.json b/test/parser/samples/self-closing-element/output.json index 47eea2f333..63ff17a466 100644 --- a/test/parser/samples/self-closing-element/output.json +++ b/test/parser/samples/self-closing-element/output.json @@ -13,8 +13,5 @@ "children": [] } ] - }, - "css": null, - "instance": null, - "module": null + } } \ No newline at end of file diff --git a/test/parser/samples/self-reference/output.json b/test/parser/samples/self-reference/output.json index de5112a087..92dfdfe4d0 100644 --- a/test/parser/samples/self-reference/output.json +++ b/test/parser/samples/self-reference/output.json @@ -72,8 +72,5 @@ ] } ] - }, - "css": null, - "instance": null, - "module": null + } } \ No newline at end of file diff --git a/test/parser/samples/space-between-mustaches/output.json b/test/parser/samples/space-between-mustaches/output.json index c89409daeb..9a367bd2c1 100644 --- a/test/parser/samples/space-between-mustaches/output.json +++ b/test/parser/samples/space-between-mustaches/output.json @@ -15,6 +15,7 @@ "start": 3, "end": 4, "type": "Text", + "raw": " ", "data": " " }, { @@ -32,6 +33,7 @@ "start": 7, "end": 8, "type": "Text", + "raw": " ", "data": " " }, { @@ -49,6 +51,7 @@ "start": 11, "end": 14, "type": "Text", + "raw": " : ", "data": " : " }, { @@ -66,13 +69,11 @@ "start": 17, "end": 20, "type": "Text", + "raw": " : ", "data": " : " } ] } ] - }, - "css": null, - "instance": null, - "module": null + } } \ No newline at end of file diff --git a/test/parser/samples/spread/output.json b/test/parser/samples/spread/output.json index 3986da3578..73a0dc9777 100644 --- a/test/parser/samples/spread/output.json +++ b/test/parser/samples/spread/output.json @@ -25,8 +25,5 @@ "children": [] } ] - }, - "css": null, - "instance": null, - "module": null + } } \ No newline at end of file diff --git a/test/parser/samples/textarea-children/output.json b/test/parser/samples/textarea-children/output.json index 3b403458fc..90f31f3caf 100644 --- a/test/parser/samples/textarea-children/output.json +++ b/test/parser/samples/textarea-children/output.json @@ -16,8 +16,9 @@ "value": [ { "start": 10, - "end": 40, + "end": 41, "type": "Text", + "raw": "\n\t

    not actually an element. ", "data": "\n\t

    not actually an element. " }, { @@ -35,6 +36,7 @@ "start": 45, "end": 50, "type": "Text", + "raw": "

    \n", "data": "

    \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 From 04af24916a41e408f9407f79535428645bc071bc Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Sun, 26 May 2019 14:59:38 +0200 Subject: [PATCH 87/87] -> v3.4.3 --- CHANGELOG.md | 9 +++++++++ package.json | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 02d42ddc8c..4981ca096b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Svelte changelog +## 3.4.3 + +* Add type declaration files for everything ([#2842](https://github.com/sveltejs/svelte/pull/2842)) +* Prevent `svelte/store` being bundled ([#2786](https://github.com/sveltejs/svelte/issues/2786)) +* Warn on unknown props in dev mode ([#2840](https://github.com/sveltejs/svelte/pull/2840)) +* Treat `requestAnimationFrame` as a no-op on the server ([#2856](https://github.com/sveltejs/svelte/pull/2856)) +* Add `raw` property to AST's `Text` nodes ([#2714](https://github.com/sveltejs/svelte/issues/2714)) +* Add `
    ` ([#2854](https://github.com/sveltejs/svelte/issues/2854)) + ## 3.4.2 * Use empty string for empty data attributes ([#2804](https://github.com/sveltejs/svelte/pull/2804)) diff --git a/package.json b/package.json index 7963e2178d..b7214c9254 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "svelte", - "version": "3.4.2", + "version": "3.4.3", "description": "Cybernetically enhanced web apps", "module": "index.mjs", "main": "index",