From 342389863e6856515fa002fc9d8c0b5cfe23faa9 Mon Sep 17 00:00:00 2001 From: Benjamin Milde Date: Sun, 5 May 2019 19:33:00 +0200 Subject: [PATCH 1/3] 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 3747d2d482da..f02eed037c71 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 000000000000..b13403f77d04 --- /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 000000000000..9579fe5b4c14 --- /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 9eec0fcd983ac14f525db42413dcd582c2fac98a Mon Sep 17 00:00:00 2001 From: Benjamin Milde Date: Sat, 11 May 2019 17:42:36 +0200 Subject: [PATCH 2/3] 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 f02eed037c71..365085ca087e 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 3/3] 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 b13403f77d04..000000000000 --- 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 9579fe5b4c14..000000000000 --- 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 000000000000..cf17c61f6055 --- /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 000000000000..f327a7fd2a99 --- /dev/null +++ b/test/runtime/samples/event-handler-multiple/main.svelte @@ -0,0 +1,6 @@ + + +