Skip to content

Commit 56cbc0d

Browse files
authored
separate static attribute logic out into its own function (#9505)
Co-authored-by: Rich Harris <[email protected]>
1 parent 1807e88 commit 56cbc0d

File tree

1 file changed

+61
-51
lines changed
  • packages/svelte/src/compiler/phases/1-parse/state

1 file changed

+61
-51
lines changed

packages/svelte/src/compiler/phases/1-parse/state/element.js

Lines changed: 61 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -191,15 +191,24 @@ export default function tag(parser) {
191191
};
192192
}
193193

194-
/** @type {Set<string>} */
195-
const unique_names = new Set();
194+
/** @type {string[]} */
195+
const unique_names = [];
196196

197197
const current = parser.current();
198198
const is_top_level_script_or_style =
199199
(name === 'script' || name === 'style') && current.type === 'Root';
200200

201+
const read = is_top_level_script_or_style ? read_static_attribute : read_attribute;
202+
201203
let attribute;
202-
while ((attribute = read_attribute(parser, unique_names, is_top_level_script_or_style))) {
204+
while ((attribute = read(parser))) {
205+
if (
206+
(attribute.type === 'Attribute' || attribute.type === 'BindDirective') &&
207+
unique_names.includes(attribute.name)
208+
) {
209+
error(attribute.start, 'duplicate-attribute');
210+
}
211+
203212
element.attributes.push(attribute);
204213
parser.allow_whitespace();
205214
}
@@ -376,22 +385,58 @@ const regex_starts_with_quote_characters = /^["']/;
376385

377386
/**
378387
* @param {import('../index.js').Parser} parser
379-
* @param {Set<string>} unique_names
380-
* @param {boolean} is_static If `true`, `{` and `}` are not treated as delimiters for expressions
381-
* @returns {any}
388+
* @returns {import('#compiler').Attribute | null}
382389
*/
383-
function read_attribute(parser, unique_names, is_static) {
390+
function read_static_attribute(parser) {
384391
const start = parser.index;
385392

386-
/** @param {string} name */
387-
function check_unique(name) {
388-
if (unique_names.has(name)) {
389-
error(start, 'duplicate-attribute');
393+
const name = parser.read_until(regex_token_ending_character);
394+
if (!name) return null;
395+
396+
/** @type {true | Array<import('#compiler').Text | import('#compiler').ExpressionTag>} */
397+
let value = true;
398+
399+
if (parser.eat('=')) {
400+
parser.allow_whitespace();
401+
let raw = parser.match_regex(regex_attribute_value);
402+
if (!raw) {
403+
error(parser.index, 'missing-attribute-value');
404+
}
405+
406+
parser.index += raw.length;
407+
408+
const quoted = raw[0] === '"' || raw[0] === "'";
409+
if (quoted) {
410+
raw = raw.slice(1, -1);
390411
}
391-
unique_names.add(name);
412+
413+
value = [
414+
{
415+
start: parser.index - raw.length - (quoted ? 1 : 0),
416+
end: quoted ? parser.index - 1 : parser.index,
417+
type: 'Text',
418+
raw: raw,
419+
data: decode_character_references(raw, true),
420+
parent: null
421+
}
422+
];
392423
}
393424

394-
if (!is_static && parser.eat('{')) {
425+
if (parser.match_regex(regex_starts_with_quote_characters)) {
426+
error(parser.index, 'expected-token', '=');
427+
}
428+
429+
return create_attribute(name, start, parser.index, value);
430+
}
431+
432+
/**
433+
* @param {import('../index.js').Parser} parser
434+
* @returns {import('#compiler').Attribute | import('#compiler').SpreadAttribute | import('#compiler').Directive | null}
435+
*/
436+
function read_attribute(parser) {
437+
const start = parser.index;
438+
439+
if (parser.eat('{')) {
395440
parser.allow_whitespace();
396441

397442
if (parser.eat('...')) {
@@ -421,8 +466,6 @@ function read_attribute(parser, unique_names, is_static) {
421466
error(start, 'empty-attribute-shorthand');
422467
}
423468

424-
check_unique(name);
425-
426469
parser.allow_whitespace();
427470
parser.eat('}', true);
428471

@@ -462,25 +505,19 @@ function read_attribute(parser, unique_names, is_static) {
462505
let value = true;
463506
if (parser.eat('=')) {
464507
parser.allow_whitespace();
465-
value = read_attribute_value(parser, is_static);
508+
value = read_attribute_value(parser);
466509
end = parser.index;
467510
} else if (parser.match_regex(regex_starts_with_quote_characters)) {
468511
error(parser.index, 'expected-token', '=');
469512
}
470513

471-
if (!is_static && type) {
514+
if (type) {
472515
const [directive_name, ...modifiers] = name.slice(colon_index + 1).split('|');
473516

474517
if (directive_name === '') {
475518
error(start + colon_index + 1, 'empty-directive-name', type);
476519
}
477520

478-
if (type === 'BindDirective' && directive_name !== 'this') {
479-
check_unique(directive_name);
480-
} else if (type !== 'OnDirective' && type !== 'UseDirective') {
481-
check_unique(name);
482-
}
483-
484521
if (type === 'StyleDirective') {
485522
return {
486523
start,
@@ -548,8 +585,6 @@ function read_attribute(parser, unique_names, is_static) {
548585
return directive;
549586
}
550587

551-
check_unique(name);
552-
553588
return create_attribute(name, start, end, value);
554589
}
555590

@@ -573,33 +608,8 @@ const regex_attribute_value = /^(?:"([^"]*)"|'([^'])*'|([^>\s]))/;
573608

574609
/**
575610
* @param {import('../index.js').Parser} parser
576-
* @param {boolean} is_static If `true`, `{` and `}` are not treated as delimiters for expressions
577611
*/
578-
function read_attribute_value(parser, is_static) {
579-
if (is_static) {
580-
let value = parser.match_regex(regex_attribute_value);
581-
if (!value) {
582-
error(parser.index, 'missing-attribute-value');
583-
}
584-
585-
parser.index += value.length;
586-
587-
const quoted = value[0] === '"' || value[0] === "'";
588-
if (quoted) {
589-
value = value.slice(1, -1);
590-
}
591-
592-
return [
593-
{
594-
start: parser.index - value.length - (quoted ? 1 : 0),
595-
end: quoted ? parser.index - 1 : parser.index,
596-
type: 'Text',
597-
raw: value,
598-
data: decode_character_references(value, true)
599-
}
600-
];
601-
}
602-
612+
function read_attribute_value(parser) {
603613
const quote_mark = parser.eat("'") ? "'" : parser.eat('"') ? '"' : null;
604614
if (quote_mark && parser.eat(quote_mark)) {
605615
return [

0 commit comments

Comments
 (0)