Skip to content

Commit

Permalink
fix: default values in object destructuring (#14554)
Browse files Browse the repository at this point in the history
* fix: enhance string/expression length check and fix closing character issues

* docs: add documentation for unterminated_string_constant error

* test: add tests for object destructuring with default values in "each" blocks

* Update .changeset/clean-planets-rush.md

* refactor: clean up unnecessary comments and whitespace

* fix: resolve formatting issues

* simplify

* tweak

* regenerate

---------

Co-authored-by: Rich Harris <[email protected]>
  • Loading branch information
caiquetorres and Rich-Harris authored Jan 7, 2025
1 parent 4aadb34 commit 48e3db2
Show file tree
Hide file tree
Showing 9 changed files with 1,806 additions and 25 deletions.
5 changes: 5 additions & 0 deletions .changeset/clean-planets-rush.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'svelte': patch
---

fix: handle default values in object destructuring within "each" blocks when using characters like "}" and "]"
6 changes: 6 additions & 0 deletions documentation/docs/98-reference/.generated/compile-errors.md
Original file line number Diff line number Diff line change
Expand Up @@ -1012,6 +1012,12 @@ Unexpected end of input
'%word%' is a reserved word in JavaScript and cannot be used here
```

### unterminated_string_constant

```
Unterminated string constant
```

### void_element_invalid_content

```
Expand Down
4 changes: 4 additions & 0 deletions packages/svelte/messages/compile-errors/template.md
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,10 @@ See https://html.spec.whatwg.org/multipage/custom-elements.html#valid-custom-ele

> '%word%' is a reserved word in JavaScript and cannot be used here
## unterminated_string_constant

> Unterminated string constant
## void_element_invalid_content

> Void elements cannot have children or closing tags
9 changes: 9 additions & 0 deletions packages/svelte/src/compiler/errors.js
Original file line number Diff line number Diff line change
Expand Up @@ -1574,6 +1574,15 @@ export function unexpected_reserved_word(node, word) {
e(node, "unexpected_reserved_word", `'${word}' is a reserved word in JavaScript and cannot be used here\nhttps://svelte.dev/e/unexpected_reserved_word`);
}

/**
* Unterminated string constant
* @param {null | number | NodeLike} node
* @returns {never}
*/
export function unterminated_string_constant(node) {
e(node, "unterminated_string_constant", `Unterminated string constant\nhttps://svelte.dev/e/unterminated_string_constant`);
}

/**
* Void elements cannot have children or closing tags
* @param {null | number | NodeLike} node
Expand Down
95 changes: 71 additions & 24 deletions packages/svelte/src/compiler/phases/1-parse/read/context.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,33 +37,11 @@ export default function read_pattern(parser) {
e.expected_pattern(i);
}

/** @type {string[]} */
const bracket_stack = [];

while (i < parser.template.length) {
const char = parser.template[i];

if (is_bracket_open(char)) {
bracket_stack.push(char);
} else if (is_bracket_close(char)) {
const popped = /** @type {string} */ (bracket_stack.pop());
const expected = /** @type {string} */ (get_bracket_close(popped));

if (char !== expected) {
e.expected_token(i, expected);
}

if (bracket_stack.length === 0) {
i += 1;
break;
}
}
i += 1;
}

i = match_bracket(parser, start);
parser.index = i;

const pattern_string = parser.template.slice(start, i);

try {
// the length of the `space_with_newline` has to be start - 1
// because we added a `(` in front of the pattern_string,
Expand Down Expand Up @@ -93,6 +71,75 @@ export default function read_pattern(parser) {
}
}

/**
* @param {Parser} parser
* @param {number} start
*/
function match_bracket(parser, start) {
const bracket_stack = [];

let i = start;

while (i < parser.template.length) {
let char = parser.template[i++];

if (char === "'" || char === '"' || char === '`') {
i = match_quote(parser, i, char);
continue;
}

if (is_bracket_open(char)) {
bracket_stack.push(char);
} else if (is_bracket_close(char)) {
const popped = /** @type {string} */ (bracket_stack.pop());
const expected = /** @type {string} */ (get_bracket_close(popped));

if (char !== expected) {
e.expected_token(i - 1, expected);
}

if (bracket_stack.length === 0) {
return i;
}
}
}

e.unexpected_eof(parser.template.length);
}

/**
* @param {Parser} parser
* @param {number} start
* @param {string} quote
*/
function match_quote(parser, start, quote) {
let is_escaped = false;
let i = start;

while (i < parser.template.length) {
const char = parser.template[i++];

if (is_escaped) {
is_escaped = false;
continue;
}

if (char === quote) {
return i;
}

if (char === '\\') {
is_escaped = true;
}

if (quote === '`' && char === '$' && parser.template[i] === '{') {
i = match_bracket(parser, i);
}
}

e.unterminated_string_constant(start);
}

/**
* @param {Parser} parser
* @returns {any}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{#each x as { y = 'z' }}{/each}

{#each x as { y = '{' }}{/each}

{#each x as { y = ']' }}{/each}

{#each x as { y = `${`"`}` }}{/each}

{#each x as { y = `${`John`}` }}{/each}
Loading

0 comments on commit 48e3db2

Please sign in to comment.