From e85138f3e3680925c4a46412f2a4810e61a8943e Mon Sep 17 00:00:00 2001 From: Mikhail Korepanov Date: Sat, 23 Mar 2019 19:25:08 +0300 Subject: [PATCH 1/9] Don't remove digits and _ from slot names --- src/utils/names.ts | 4 +- test/js/samples/slot-names/expected.js | 121 ++++++++++++++++++++++++ test/js/samples/slot-names/input.svelte | 5 + 3 files changed, 128 insertions(+), 2 deletions(-) create mode 100644 test/js/samples/slot-names/expected.js create mode 100644 test/js/samples/slot-names/input.svelte diff --git a/src/utils/names.ts b/src/utils/names.ts index 5047fe850c..317379198f 100644 --- a/src/utils/names.ts +++ b/src/utils/names.ts @@ -111,5 +111,5 @@ export function quote_prop_if_necessary(name: string) { } export function sanitize(name: string) { - return name.replace(/[^a-zA-Z]+/g, '_').replace(/^_/, '').replace(/_$/, ''); -} \ No newline at end of file + return name.replace(/[^a-zA-Z0-9_]+/g, '_').replace(/^_/, '').replace(/_$/, ''); +} diff --git a/test/js/samples/slot-names/expected.js b/test/js/samples/slot-names/expected.js new file mode 100644 index 0000000000..a538888651 --- /dev/null +++ b/test/js/samples/slot-names/expected.js @@ -0,0 +1,121 @@ +/* generated by Svelte vX.Y.Z */ +import { + SvelteComponent as SvelteComponent_1, + append, + create_slot, + detach, + element, + get_slot_changes, + get_slot_context, + init, + insert, + noop, + safe_not_equal, + space +} from "svelte/internal"; + +function create_fragment(ctx) { + var div, t0, t1; + + const header_1_slot_1 = ctx.$$slot_header_1; + const header_1_slot = create_slot(header_1_slot_1, ctx, null); + + const header_2__slot_1 = ctx.$$slot_header_2_; + const header_2__slot = create_slot(header_2__slot_1, ctx, null); + + const header_3_slot_1 = ctx.$$slot_header_3; + const header_3_slot = create_slot(header_3_slot_1, ctx, null); + + return { + c() { + div = element("div"); + + if (header_1_slot) header_1_slot.c(); + t0 = space(); + + if (header_2__slot) header_2__slot.c(); + t1 = space(); + + if (header_3_slot) header_3_slot.c(); + }, + + l(nodes) { + if (header_1_slot) header_1_slot.l(div_nodes); + if (header_2__slot) header_2__slot.l(div_nodes); + if (header_3_slot) header_3_slot.l(div_nodes); + }, + + m(target, anchor) { + insert(target, div, anchor); + + if (header_1_slot) { + header_1_slot.m(div, null); + } + + append(div, t0); + + if (header_2__slot) { + header_2__slot.m(div, null); + } + + append(div, t1); + + if (header_3_slot) { + header_3_slot.m(div, null); + } + }, + + p(changed, ctx) { + if (header_1_slot && header_1_slot.p && changed.$$scope) { + header_1_slot.p(get_slot_changes(header_1_slot_1, ctx, changed,), get_slot_context(header_1_slot_1, ctx, null)); + } + + if (header_2__slot && header_2__slot.p && changed.$$scope) { + header_2__slot.p(get_slot_changes(header_2__slot_1, ctx, changed,), get_slot_context(header_2__slot_1, ctx, null)); + } + + if (header_3_slot && header_3_slot.p && changed.$$scope) { + header_3_slot.p(get_slot_changes(header_3_slot_1, ctx, changed,), get_slot_context(header_3_slot_1, ctx, null)); + } + }, + + i: noop, + o: noop, + + d(detaching) { + if (detaching) { + detach(div); + } + + if (header_1_slot) header_1_slot.d(detaching); + + if (header_2__slot) header_2__slot.d(detaching); + + if (header_3_slot) header_3_slot.d(detaching); + } + }; +} + +function instance($$self, $$props, $$invalidate) { + let { $$slot_header_1, $$slot_header_2_, $$slot_header_3, $$scope } = $$props; + + $$self.$set = $$props => { + if ('$$scope' in $$props) $$invalidate('$$scope', $$scope = $$props.$$scope); + }; + + return { + $$slot_header_1, + $$slot_header_2_, + $$slot_header_3, + $$scope + }; +} + +class SvelteComponent extends SvelteComponent_1 { + constructor(options) { + super(); + init(this, options, instance, create_fragment, safe_not_equal, []); + } +} + +export default SvelteComponent; diff --git a/test/js/samples/slot-names/input.svelte b/test/js/samples/slot-names/input.svelte new file mode 100644 index 0000000000..986fb798f4 --- /dev/null +++ b/test/js/samples/slot-names/input.svelte @@ -0,0 +1,5 @@ +
+ + + +
From 658d2353508ba1d6b79e9e919de01946aff1b8ea Mon Sep 17 00:00:00 2001 From: Mikhail Korepanov Date: Sat, 23 Mar 2019 21:50:11 +0300 Subject: [PATCH 2/9] Add an error for a slot name starts with a digit --- src/compile/nodes/Slot.ts | 9 ++++++++- .../slot-name-starts-with-a-digit/errors.json | 15 +++++++++++++++ .../slot-name-starts-with-a-digit/input.svelte | 3 +++ 3 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 test/validator/samples/slot-name-starts-with-a-digit/errors.json create mode 100644 test/validator/samples/slot-name-starts-with-a-digit/input.svelte diff --git a/src/compile/nodes/Slot.ts b/src/compile/nodes/Slot.ts index 0a4f4af848..fe9e1ff0e8 100644 --- a/src/compile/nodes/Slot.ts +++ b/src/compile/nodes/Slot.ts @@ -34,6 +34,13 @@ export default class Slot extends Element { message: `default is a reserved word — it cannot be used as a slot name` }); } + + if (/^[0-9]/.test(slot_name)) { + component.error(attr, { + code: `invalid-slot-name`, + message: ` name cannot start with a digit` + }); + } } // TODO should duplicate slots be disallowed? Feels like it's more likely to be a @@ -70,4 +77,4 @@ export default class Slot extends Element { return null; } -} \ No newline at end of file +} diff --git a/test/validator/samples/slot-name-starts-with-a-digit/errors.json b/test/validator/samples/slot-name-starts-with-a-digit/errors.json new file mode 100644 index 0000000000..a898e6e282 --- /dev/null +++ b/test/validator/samples/slot-name-starts-with-a-digit/errors.json @@ -0,0 +1,15 @@ +[{ + "code": "invalid-slot-name", + "message": " name cannot start with a digit", + "start": { + "line": 2, + "column": 7, + "character": 13 + }, + "end": { + "line": 2, + "column": 21, + "character": 27 + }, + "pos": 13 +}] diff --git a/test/validator/samples/slot-name-starts-with-a-digit/input.svelte b/test/validator/samples/slot-name-starts-with-a-digit/input.svelte new file mode 100644 index 0000000000..ae9ede75ba --- /dev/null +++ b/test/validator/samples/slot-name-starts-with-a-digit/input.svelte @@ -0,0 +1,3 @@ +
+ +
From 0ab7077d40bd7fa947bfa0620480b3e7bc36c8cc Mon Sep 17 00:00:00 2001 From: Mikhail Korepanov Date: Mon, 25 Mar 2019 16:54:14 +0300 Subject: [PATCH 3/9] Move slot names test to runtime. Allow slot names that start with a digit --- src/compile/nodes/Slot.ts | 9 +- src/utils/names.ts | 6 +- test/js/samples/slot-names/expected.js | 121 ------------------ test/js/samples/slot-names/input.svelte | 5 - test/runtime/samples/slot-names/Nested.svelte | 6 + test/runtime/samples/slot-names/_config.js | 10 ++ test/runtime/samples/slot-names/main.svelte | 10 ++ .../slot-name-starts-with-a-digit/errors.json | 15 --- .../input.svelte | 3 - 9 files changed, 32 insertions(+), 153 deletions(-) delete mode 100644 test/js/samples/slot-names/expected.js delete mode 100644 test/js/samples/slot-names/input.svelte create mode 100644 test/runtime/samples/slot-names/Nested.svelte create mode 100644 test/runtime/samples/slot-names/_config.js create mode 100644 test/runtime/samples/slot-names/main.svelte delete mode 100644 test/validator/samples/slot-name-starts-with-a-digit/errors.json delete mode 100644 test/validator/samples/slot-name-starts-with-a-digit/input.svelte diff --git a/src/compile/nodes/Slot.ts b/src/compile/nodes/Slot.ts index fe9e1ff0e8..0a4f4af848 100644 --- a/src/compile/nodes/Slot.ts +++ b/src/compile/nodes/Slot.ts @@ -34,13 +34,6 @@ export default class Slot extends Element { message: `default is a reserved word — it cannot be used as a slot name` }); } - - if (/^[0-9]/.test(slot_name)) { - component.error(attr, { - code: `invalid-slot-name`, - message: ` name cannot start with a digit` - }); - } } // TODO should duplicate slots be disallowed? Feels like it's more likely to be a @@ -77,4 +70,4 @@ export default class Slot extends Element { return null; } -} +} \ No newline at end of file diff --git a/src/utils/names.ts b/src/utils/names.ts index 317379198f..1f0a9cc29e 100644 --- a/src/utils/names.ts +++ b/src/utils/names.ts @@ -111,5 +111,9 @@ export function quote_prop_if_necessary(name: string) { } export function sanitize(name: string) { - return name.replace(/[^a-zA-Z0-9_]+/g, '_').replace(/^_/, '').replace(/_$/, ''); + return name + .replace(/[^a-zA-Z0-9_]+/g, '_') + .replace(/^_/, '') + .replace(/_$/, '') + .replace(/^[0-9]/, '_$&'); } diff --git a/test/js/samples/slot-names/expected.js b/test/js/samples/slot-names/expected.js deleted file mode 100644 index a538888651..0000000000 --- a/test/js/samples/slot-names/expected.js +++ /dev/null @@ -1,121 +0,0 @@ -/* generated by Svelte vX.Y.Z */ -import { - SvelteComponent as SvelteComponent_1, - append, - create_slot, - detach, - element, - get_slot_changes, - get_slot_context, - init, - insert, - noop, - safe_not_equal, - space -} from "svelte/internal"; - -function create_fragment(ctx) { - var div, t0, t1; - - const header_1_slot_1 = ctx.$$slot_header_1; - const header_1_slot = create_slot(header_1_slot_1, ctx, null); - - const header_2__slot_1 = ctx.$$slot_header_2_; - const header_2__slot = create_slot(header_2__slot_1, ctx, null); - - const header_3_slot_1 = ctx.$$slot_header_3; - const header_3_slot = create_slot(header_3_slot_1, ctx, null); - - return { - c() { - div = element("div"); - - if (header_1_slot) header_1_slot.c(); - t0 = space(); - - if (header_2__slot) header_2__slot.c(); - t1 = space(); - - if (header_3_slot) header_3_slot.c(); - }, - - l(nodes) { - if (header_1_slot) header_1_slot.l(div_nodes); - if (header_2__slot) header_2__slot.l(div_nodes); - if (header_3_slot) header_3_slot.l(div_nodes); - }, - - m(target, anchor) { - insert(target, div, anchor); - - if (header_1_slot) { - header_1_slot.m(div, null); - } - - append(div, t0); - - if (header_2__slot) { - header_2__slot.m(div, null); - } - - append(div, t1); - - if (header_3_slot) { - header_3_slot.m(div, null); - } - }, - - p(changed, ctx) { - if (header_1_slot && header_1_slot.p && changed.$$scope) { - header_1_slot.p(get_slot_changes(header_1_slot_1, ctx, changed,), get_slot_context(header_1_slot_1, ctx, null)); - } - - if (header_2__slot && header_2__slot.p && changed.$$scope) { - header_2__slot.p(get_slot_changes(header_2__slot_1, ctx, changed,), get_slot_context(header_2__slot_1, ctx, null)); - } - - if (header_3_slot && header_3_slot.p && changed.$$scope) { - header_3_slot.p(get_slot_changes(header_3_slot_1, ctx, changed,), get_slot_context(header_3_slot_1, ctx, null)); - } - }, - - i: noop, - o: noop, - - d(detaching) { - if (detaching) { - detach(div); - } - - if (header_1_slot) header_1_slot.d(detaching); - - if (header_2__slot) header_2__slot.d(detaching); - - if (header_3_slot) header_3_slot.d(detaching); - } - }; -} - -function instance($$self, $$props, $$invalidate) { - let { $$slot_header_1, $$slot_header_2_, $$slot_header_3, $$scope } = $$props; - - $$self.$set = $$props => { - if ('$$scope' in $$props) $$invalidate('$$scope', $$scope = $$props.$$scope); - }; - - return { - $$slot_header_1, - $$slot_header_2_, - $$slot_header_3, - $$scope - }; -} - -class SvelteComponent extends SvelteComponent_1 { - constructor(options) { - super(); - init(this, options, instance, create_fragment, safe_not_equal, []); - } -} - -export default SvelteComponent; diff --git a/test/js/samples/slot-names/input.svelte b/test/js/samples/slot-names/input.svelte deleted file mode 100644 index 986fb798f4..0000000000 --- a/test/js/samples/slot-names/input.svelte +++ /dev/null @@ -1,5 +0,0 @@ -
- - - -
diff --git a/test/runtime/samples/slot-names/Nested.svelte b/test/runtime/samples/slot-names/Nested.svelte new file mode 100644 index 0000000000..70037db27e --- /dev/null +++ b/test/runtime/samples/slot-names/Nested.svelte @@ -0,0 +1,6 @@ +
+ + + + +
diff --git a/test/runtime/samples/slot-names/_config.js b/test/runtime/samples/slot-names/_config.js new file mode 100644 index 0000000000..c94d09edef --- /dev/null +++ b/test/runtime/samples/slot-names/_config.js @@ -0,0 +1,10 @@ +export default { + html: ` +
+

Header 1

+

Header 2

+

Header 3

+

Header 4

+
+ ` +}; diff --git a/test/runtime/samples/slot-names/main.svelte b/test/runtime/samples/slot-names/main.svelte new file mode 100644 index 0000000000..3538bc49e3 --- /dev/null +++ b/test/runtime/samples/slot-names/main.svelte @@ -0,0 +1,10 @@ + + + +

Header 1

+

Header 2

+

Header 3

+

Header 4

+
diff --git a/test/validator/samples/slot-name-starts-with-a-digit/errors.json b/test/validator/samples/slot-name-starts-with-a-digit/errors.json deleted file mode 100644 index a898e6e282..0000000000 --- a/test/validator/samples/slot-name-starts-with-a-digit/errors.json +++ /dev/null @@ -1,15 +0,0 @@ -[{ - "code": "invalid-slot-name", - "message": " name cannot start with a digit", - "start": { - "line": 2, - "column": 7, - "character": 13 - }, - "end": { - "line": 2, - "column": 21, - "character": 27 - }, - "pos": 13 -}] diff --git a/test/validator/samples/slot-name-starts-with-a-digit/input.svelte b/test/validator/samples/slot-name-starts-with-a-digit/input.svelte deleted file mode 100644 index ae9ede75ba..0000000000 --- a/test/validator/samples/slot-name-starts-with-a-digit/input.svelte +++ /dev/null @@ -1,3 +0,0 @@ -
- -
From 844a4830111fc2d9d99873323c94460b42aaa5ad Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Mon, 25 Mar 2019 17:29:48 -0400 Subject: [PATCH 4/9] test for conflicting slot names --- test/runtime/samples/slot-names/Nested.svelte | 2 ++ test/runtime/samples/slot-names/_config.js | 2 ++ test/runtime/samples/slot-names/main.svelte | 2 ++ 3 files changed, 6 insertions(+) diff --git a/test/runtime/samples/slot-names/Nested.svelte b/test/runtime/samples/slot-names/Nested.svelte index 70037db27e..ca8328920d 100644 --- a/test/runtime/samples/slot-names/Nested.svelte +++ b/test/runtime/samples/slot-names/Nested.svelte @@ -3,4 +3,6 @@ + + diff --git a/test/runtime/samples/slot-names/_config.js b/test/runtime/samples/slot-names/_config.js index c94d09edef..d75beb1b05 100644 --- a/test/runtime/samples/slot-names/_config.js +++ b/test/runtime/samples/slot-names/_config.js @@ -5,6 +5,8 @@ export default {

Header 2

Header 3

Header 4

+
Header 5
+
Header 5b
` }; diff --git a/test/runtime/samples/slot-names/main.svelte b/test/runtime/samples/slot-names/main.svelte index 3538bc49e3..3e607de5fa 100644 --- a/test/runtime/samples/slot-names/main.svelte +++ b/test/runtime/samples/slot-names/main.svelte @@ -7,4 +7,6 @@

Header 2

Header 3

Header 4

+
Header 5
+
Header 5b
From fa6427530f7b26bdbb27cd4c61979a400ed999c2 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Mon, 25 Mar 2019 17:30:16 -0400 Subject: [PATCH 5/9] move test --- .../{slot-names => component-slot-names-sanitized}/Nested.svelte | 0 .../{slot-names => component-slot-names-sanitized}/_config.js | 0 .../{slot-names => component-slot-names-sanitized}/main.svelte | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename test/runtime/samples/{slot-names => component-slot-names-sanitized}/Nested.svelte (100%) rename test/runtime/samples/{slot-names => component-slot-names-sanitized}/_config.js (100%) rename test/runtime/samples/{slot-names => component-slot-names-sanitized}/main.svelte (100%) diff --git a/test/runtime/samples/slot-names/Nested.svelte b/test/runtime/samples/component-slot-names-sanitized/Nested.svelte similarity index 100% rename from test/runtime/samples/slot-names/Nested.svelte rename to test/runtime/samples/component-slot-names-sanitized/Nested.svelte diff --git a/test/runtime/samples/slot-names/_config.js b/test/runtime/samples/component-slot-names-sanitized/_config.js similarity index 100% rename from test/runtime/samples/slot-names/_config.js rename to test/runtime/samples/component-slot-names-sanitized/_config.js diff --git a/test/runtime/samples/slot-names/main.svelte b/test/runtime/samples/component-slot-names-sanitized/main.svelte similarity index 100% rename from test/runtime/samples/slot-names/main.svelte rename to test/runtime/samples/component-slot-names-sanitized/main.svelte From 0d02a84f337ec3113cc29ed63dabc8139d5ede44 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Mon, 25 Mar 2019 17:37:28 -0400 Subject: [PATCH 6/9] DRY out --- src/compile/nodes/Element.ts | 17 ------------ src/compile/nodes/Slot.ts | 17 ------------ src/compile/nodes/shared/Node.ts | 27 +++++++++++++++---- .../render-dom/wrappers/Element/Attribute.ts | 2 +- .../render-dom/wrappers/Element/Binding.ts | 2 +- .../render-dom/wrappers/Element/index.ts | 21 ++------------- 6 files changed, 26 insertions(+), 60 deletions(-) diff --git a/src/compile/nodes/Element.ts b/src/compile/nodes/Element.ts index c0da7ea5c0..6d9c8059f5 100644 --- a/src/compile/nodes/Element.ts +++ b/src/compile/nodes/Element.ts @@ -636,23 +636,6 @@ export default class Element extends Node { }); } - get_static_attribute_value(name: string) { - const attribute = this.attributes.find( - (attr: Attribute) => attr.type === 'Attribute' && attr.name.toLowerCase() === name - ); - - if (!attribute) return null; - - if (attribute.is_true) return true; - if (attribute.chunks.length === 0) return ''; - - if (attribute.chunks.length === 1 && attribute.chunks[0].type === 'Text') { - return attribute.chunks[0].data; - } - - return null; - } - is_media_node() { return this.name === 'audio' || this.name === 'video'; } diff --git a/src/compile/nodes/Slot.ts b/src/compile/nodes/Slot.ts index 0a4f4af848..31026e302a 100644 --- a/src/compile/nodes/Slot.ts +++ b/src/compile/nodes/Slot.ts @@ -53,21 +53,4 @@ export default class Slot extends Element { // }); // } } - - get_static_attribute_value(name: string) { - const attribute = this.attributes.find( - attr => attr.name.toLowerCase() === name - ); - - if (!attribute) return null; - - if (attribute.is_true) return true; - if (attribute.chunks.length === 0) return ''; - - if (attribute.chunks.length === 1 && attribute.chunks[0].type === 'Text') { - return attribute.chunks[0].data; - } - - return null; - } } \ No newline at end of file diff --git a/src/compile/nodes/shared/Node.ts b/src/compile/nodes/shared/Node.ts index 4317e23e4f..92c1cc40d7 100644 --- a/src/compile/nodes/shared/Node.ts +++ b/src/compile/nodes/shared/Node.ts @@ -37,17 +37,34 @@ export default class Node { } } + find_nearest(selector: RegExp) { + if (selector.test(this.type)) return this; + if (this.parent) return this.parent.find_nearest(selector); + } + + get_static_attribute_value(name: string) { + const attribute = this.attributes.find( + (attr: Attribute) => attr.type === 'Attribute' && attr.name.toLowerCase() === name + ); + + if (!attribute) return null; + + if (attribute.is_true) return true; + if (attribute.chunks.length === 0) return ''; + + if (attribute.chunks.length === 1 && attribute.chunks[0].type === 'Text') { + return attribute.chunks[0].data; + } + + return null; + } + has_ancestor(type: string) { return this.parent ? this.parent.type === type || this.parent.has_ancestor(type) : false; } - find_nearest(selector: RegExp) { - if (selector.test(this.type)) return this; - if (this.parent) return this.parent.find_nearest(selector); - } - warn_if_empty_block() { if (!/Block$/.test(this.type) || !this.children) return; if (this.children.length > 1) return; diff --git a/src/compile/render-dom/wrappers/Element/Attribute.ts b/src/compile/render-dom/wrappers/Element/Attribute.ts index 5b581677d8..c0c8327bb0 100644 --- a/src/compile/render-dom/wrappers/Element/Attribute.ts +++ b/src/compile/render-dom/wrappers/Element/Attribute.ts @@ -117,7 +117,7 @@ export default class AttributeWrapper { updater = `@set_input_type(${element.var}, ${should_cache ? last : value});`; } else if (is_select_value_attribute) { // annoying special case - const is_multiple_select = element.get_static_attribute_value('multiple'); + const is_multiple_select = element.node.get_static_attribute_value('multiple'); const i = block.get_unique_name('i'); const option = block.get_unique_name('option'); diff --git a/src/compile/render-dom/wrappers/Element/Binding.ts b/src/compile/render-dom/wrappers/Element/Binding.ts index 8657a1b054..f2bf82a826 100644 --- a/src/compile/render-dom/wrappers/Element/Binding.ts +++ b/src/compile/render-dom/wrappers/Element/Binding.ts @@ -153,7 +153,7 @@ export default class BindingWrapper { break; case 'value': - if (parent.get_static_attribute_value('type') === 'file') { + if (parent.node.get_static_attribute_value('type') === 'file') { update_dom = null; } } diff --git a/src/compile/render-dom/wrappers/Element/index.ts b/src/compile/render-dom/wrappers/Element/index.ts index d54a66dffa..32c8063f05 100644 --- a/src/compile/render-dom/wrappers/Element/index.ts +++ b/src/compile/render-dom/wrappers/Element/index.ts @@ -213,8 +213,8 @@ export default class ElementWrapper extends Wrapper { const { renderer } = this; if (this.node.name === 'slot') { - const slotName = this.get_static_attribute_value('name') || 'default'; - renderer.slots.add(slotName); + const slot_name = this.node.get_static_attribute_value('name') || 'default'; + renderer.slots.add(slot_name); } if (this.node.name === 'noscript') return; @@ -804,23 +804,6 @@ export default class ElementWrapper extends Wrapper { }); } - get_static_attribute_value(name: string) { - const attribute = this.node.attributes.find( - (attr: Attribute) => attr.type === 'Attribute' && attr.name.toLowerCase() === name - ); - - if (!attribute) return null; - - if (attribute.is_true) return true; - if (attribute.chunks.length === 0) return ''; - - if (attribute.chunks.length === 1 && attribute.chunks[0].type === 'Text') { - return attribute.chunks[0].data; - } - - return null; - } - add_css_class(class_name = this.component.stylesheet.id) { const class_attribute = this.attributes.find(a => a.name === 'class'); if (class_attribute && !class_attribute.is_true) { From 7c4ae2c859d0306dad5c8d3ef6d1420981cf4577 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Mon, 25 Mar 2019 17:49:25 -0400 Subject: [PATCH 7/9] simplify some slot_name stuff --- src/compile/nodes/Slot.ts | 7 +++++-- src/compile/render-dom/wrappers/Element/index.ts | 4 ++-- src/compile/render-dom/wrappers/Slot.ts | 2 +- src/compile/render-ssr/handlers/Slot.ts | 5 +---- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/compile/nodes/Slot.ts b/src/compile/nodes/Slot.ts index 31026e302a..1540fa6271 100644 --- a/src/compile/nodes/Slot.ts +++ b/src/compile/nodes/Slot.ts @@ -5,6 +5,7 @@ import Attribute from './Attribute'; export default class Slot extends Element { type: 'Element'; name: string; + slot_name: string; attributes: Attribute[]; children: Node[]; @@ -27,8 +28,8 @@ export default class Slot extends Element { }); } - const slot_name = attr.value[0].data; - if (slot_name === 'default') { + this.slot_name = attr.value[0].data; + if (this.slot_name === 'default') { component.error(attr, { code: `invalid-slot-name`, message: `default is a reserved word — it cannot be used as a slot name` @@ -46,6 +47,8 @@ export default class Slot extends Element { // validator.slots.add(slot_name); }); + if (!this.slot_name) this.slot_name = 'default'; + // if (node.attributes.length === 0) && validator.slots.has('default')) { // validator.error(node, { // code: `duplicate-slot`, diff --git a/src/compile/render-dom/wrappers/Element/index.ts b/src/compile/render-dom/wrappers/Element/index.ts index 32c8063f05..fa025bacbe 100644 --- a/src/compile/render-dom/wrappers/Element/index.ts +++ b/src/compile/render-dom/wrappers/Element/index.ts @@ -20,6 +20,7 @@ import add_event_handlers from '../shared/add_event_handlers'; import add_actions from '../shared/add_actions'; import create_debugging_comment from '../shared/create_debugging_comment'; import { get_context_merger } from '../shared/get_context_merger'; +import Slot from '../../../nodes/Slot'; const events = [ { @@ -213,8 +214,7 @@ export default class ElementWrapper extends Wrapper { const { renderer } = this; if (this.node.name === 'slot') { - const slot_name = this.node.get_static_attribute_value('name') || 'default'; - renderer.slots.add(slot_name); + renderer.slots.add((this.node as Slot).slot_name); } if (this.node.name === 'noscript') return; diff --git a/src/compile/render-dom/wrappers/Slot.ts b/src/compile/render-dom/wrappers/Slot.ts index 3760e73ce0..0374587c24 100644 --- a/src/compile/render-dom/wrappers/Slot.ts +++ b/src/compile/render-dom/wrappers/Slot.ts @@ -55,7 +55,7 @@ export default class SlotWrapper extends Wrapper { ) { const { renderer } = this; - const slot_name = this.node.get_static_attribute_value('name') || 'default'; + const { slot_name } = this.node; renderer.slots.add(slot_name); let get_slot_changes; diff --git a/src/compile/render-ssr/handlers/Slot.ts b/src/compile/render-ssr/handlers/Slot.ts index 51e37ab9cf..77273e8009 100644 --- a/src/compile/render-ssr/handlers/Slot.ts +++ b/src/compile/render-ssr/handlers/Slot.ts @@ -2,10 +2,7 @@ import { quote_prop_if_necessary } from '../../../utils/names'; import get_slot_data from '../../utils/get_slot_data'; export default function(node, renderer, options) { - const name = node.attributes.find(attribute => attribute.name === 'name'); - - const slot_name = name && name.chunks[0].data || 'default'; - const prop = quote_prop_if_necessary(slot_name); + const prop = quote_prop_if_necessary(node.slot_name); const slot_data = get_slot_data(node.attributes, true); From 0c7151c5029f5917923c538a02353df8fb816cbf Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Mon, 25 Mar 2019 23:24:36 -0400 Subject: [PATCH 8/9] handle arbitrary slot names --- src/compile/render-dom/index.ts | 7 +++---- .../render-dom/wrappers/InlineComponent/index.ts | 13 ++++++++----- src/compile/render-dom/wrappers/Slot.ts | 4 ++-- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/compile/render-dom/index.ts b/src/compile/render-dom/index.ts index aef29a194b..6151373d25 100644 --- a/src/compile/render-dom/index.ts +++ b/src/compile/render-dom/index.ts @@ -10,7 +10,7 @@ import add_to_set from '../utils/add_to_set'; import get_object from '../utils/get_object'; import { extract_names } from '../utils/scope'; import { nodes_match } from '../../utils/nodes_match'; -import { sanitize } from '../../utils/names'; +import { sanitize, quote_prop_if_necessary, quote_name_if_necessary } from '../../utils/names'; export default function dom( component: Component, @@ -305,8 +305,7 @@ export default function dom( const reactive_stores = component.vars.filter(variable => variable.name[0] === '$' && variable.name[1] !== '$'); if (renderer.slots.size > 0) { - const arr = Array.from(renderer.slots); - filtered_declarations.push(...arr.map(name => `$$slot_${sanitize(name)}`), '$$scope'); + filtered_declarations.push('$$slots', '$$scope'); } if (renderer.binding_groups.length > 0) { @@ -399,7 +398,7 @@ export default function dom( ${component.javascript} - ${renderer.slots.size && `let { ${[...renderer.slots].map(name => `$$slot_${sanitize(name)}`).join(', ')}, $$scope } = $$props;`} + ${renderer.slots.size && `let { $$slots = {}, $$scope } = $$props;`} ${renderer.binding_groups.length > 0 && `const $$binding_groups = [${renderer.binding_groups.map(_ => `[]`).join(', ')}];`} diff --git a/src/compile/render-dom/wrappers/InlineComponent/index.ts b/src/compile/render-dom/wrappers/InlineComponent/index.ts index 958a98bcb5..bc13014a29 100644 --- a/src/compile/render-dom/wrappers/InlineComponent/index.ts +++ b/src/compile/render-dom/wrappers/InlineComponent/index.ts @@ -119,16 +119,19 @@ export default class InlineComponentWrapper extends Wrapper { const uses_spread = !!this.node.attributes.find(a => a.is_spread); - const slot_props = Array.from(this.slots).map(([name, slot]) => `$$slot_${sanitize(name)}: [${slot.block.name}${slot.fn ? `, ${slot.fn}` : ''}]`); - if (slot_props.length > 0) slot_props.push(`$$scope: { ctx }`); + const slot_props = Array.from(this.slots).map(([name, slot]) => `${quote_name_if_necessary(name)}: [${slot.block.name}${slot.fn ? `, ${slot.fn}` : ''}]`); + + const initial_props = slot_props.length > 0 + ? [`$$slots: ${stringify_props(slot_props)}`, `$$scope: { ctx }`] + : []; const attribute_object = uses_spread - ? stringify_props(slot_props) + ? stringify_props(initial_props) : stringify_props( - this.node.attributes.map(attr => `${quote_name_if_necessary(attr.name)}: ${attr.get_value(block)}`).concat(slot_props) + this.node.attributes.map(attr => `${quote_name_if_necessary(attr.name)}: ${attr.get_value(block)}`).concat(initial_props) ); - if (this.node.attributes.length || this.node.bindings.length || slot_props.length) { + if (this.node.attributes.length || this.node.bindings.length || initial_props.length) { if (!uses_spread && this.node.bindings.length === 0) { component_opts.push(`props: ${attribute_object}`); } else { diff --git a/src/compile/render-dom/wrappers/Slot.ts b/src/compile/render-dom/wrappers/Slot.ts index 0374587c24..38896b4546 100644 --- a/src/compile/render-dom/wrappers/Slot.ts +++ b/src/compile/render-dom/wrappers/Slot.ts @@ -4,7 +4,7 @@ import Block from '../Block'; import Slot from '../../nodes/Slot'; import FragmentWrapper from './Fragment'; import deindent from '../../utils/deindent'; -import { sanitize } from '../../../utils/names'; +import { sanitize, quote_prop_if_necessary } from '../../../utils/names'; import add_to_set from '../../utils/add_to_set'; import get_slot_data from '../../utils/get_slot_data'; import { stringify_props } from '../../utils/stringify_props'; @@ -99,7 +99,7 @@ export default class SlotWrapper extends Wrapper { const slot_definition = block.get_unique_name(`${sanitize(slot_name)}_slot`); block.builders.init.add_block(deindent` - const ${slot_definition} = ctx.$$slot_${sanitize(slot_name)}; + const ${slot_definition} = ctx.$$slots${quote_prop_if_necessary(slot_name)}; const ${slot} = @create_slot(${slot_definition}, ctx, ${get_slot_context}); `); From 91d92c1e8a4d0f83337633b35ed22ff5f414476b Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Mon, 25 Mar 2019 23:28:36 -0400 Subject: [PATCH 9/9] remove unused import --- src/compile/render-dom/index.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/compile/render-dom/index.ts b/src/compile/render-dom/index.ts index 6151373d25..363d807916 100644 --- a/src/compile/render-dom/index.ts +++ b/src/compile/render-dom/index.ts @@ -10,7 +10,6 @@ import add_to_set from '../utils/add_to_set'; import get_object from '../utils/get_object'; import { extract_names } from '../utils/scope'; import { nodes_match } from '../../utils/nodes_match'; -import { sanitize, quote_prop_if_necessary, quote_name_if_necessary } from '../../utils/names'; export default function dom( component: Component,