diff --git a/packages/svelte-vscode/syntaxes/svelte.tmLanguage.src.yaml b/packages/svelte-vscode/syntaxes/svelte.tmLanguage.src.yaml index 01a68bdeb..786d70adc 100644 --- a/packages/svelte-vscode/syntaxes/svelte.tmLanguage.src.yaml +++ b/packages/svelte-vscode/syntaxes/svelte.tmLanguage.src.yaml @@ -260,11 +260,11 @@ repository: patterns: # Start expression. - begin: \G\s*?(?=\S) - end: (?=(?:^\s*|\s+)(as)) + end: (?=(?:(?:^\s*|\s+)(as))|\s*(}|,)) contentName: meta.embedded.expression.svelte source.ts patterns: [ include: source.ts ] # 'as' token and onwards. - - begin: (as) + - begin: (as)|(?=}|,) beginCaptures: { 1: { name: keyword.control.as.svelte } } end: (?=}) patterns: diff --git a/packages/svelte-vscode/test/grammar/samples/each-block/input.svelte b/packages/svelte-vscode/test/grammar/samples/each-block/input.svelte index 7cdc3fb4c..3f1528478 100644 --- a/packages/svelte-vscode/test/grammar/samples/each-block/input.svelte +++ b/packages/svelte-vscode/test/grammar/samples/each-block/input.svelte @@ -7,3 +7,19 @@ {#each showGroups as [key, items] (key)} {/each} + +{#each v} + this should be seen as text +{/each} + +{#each v } + this should be seen as text +{/each} + +{#each v, i} + this should be seen as text +{/each} + +{#each v , i} + this should be seen as text +{/each} diff --git a/packages/svelte-vscode/test/grammar/samples/each-block/input.svelte.snap b/packages/svelte-vscode/test/grammar/samples/each-block/input.svelte.snap index 0888c820a..fb9896c3b 100644 --- a/packages/svelte-vscode/test/grammar/samples/each-block/input.svelte.snap +++ b/packages/svelte-vscode/test/grammar/samples/each-block/input.svelte.snap @@ -61,4 +61,70 @@ # ^ source.svelte meta.special.each.svelte meta.special.end.svelte punctuation.definition.keyword.svelte # ^^^^ source.svelte meta.special.each.svelte meta.special.end.svelte keyword.control.svelte # ^ source.svelte meta.special.each.svelte meta.special.end.svelte punctuation.definition.block.end.svelte +> +>{#each v} +#^ source.svelte meta.special.each.svelte meta.special.start.svelte punctuation.definition.block.begin.svelte +# ^ source.svelte meta.special.each.svelte meta.special.start.svelte punctuation.definition.keyword.svelte +# ^^^^ source.svelte meta.special.each.svelte meta.special.start.svelte keyword.control.svelte +# ^ source.svelte meta.special.each.svelte meta.special.start.svelte +# ^ source.svelte meta.special.each.svelte meta.special.start.svelte meta.embedded.expression.svelte source.ts +# ^ source.svelte meta.special.each.svelte meta.special.start.svelte punctuation.definition.block.end.svelte +> this should be seen as text +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ source.svelte text.svelte +>{/each} +#^ source.svelte meta.special.each.svelte meta.special.end.svelte punctuation.definition.block.begin.svelte +# ^ source.svelte meta.special.each.svelte meta.special.end.svelte punctuation.definition.keyword.svelte +# ^^^^ source.svelte meta.special.each.svelte meta.special.end.svelte keyword.control.svelte +# ^ source.svelte meta.special.each.svelte meta.special.end.svelte punctuation.definition.block.end.svelte +> +>{#each v } +#^ source.svelte meta.special.each.svelte meta.special.start.svelte punctuation.definition.block.begin.svelte +# ^ source.svelte meta.special.each.svelte meta.special.start.svelte punctuation.definition.keyword.svelte +# ^^^^ source.svelte meta.special.each.svelte meta.special.start.svelte keyword.control.svelte +# ^ source.svelte meta.special.each.svelte meta.special.start.svelte +# ^ source.svelte meta.special.each.svelte meta.special.start.svelte meta.embedded.expression.svelte source.ts +# ^ source.svelte meta.special.each.svelte meta.special.start.svelte +# ^ source.svelte meta.special.each.svelte meta.special.start.svelte punctuation.definition.block.end.svelte +> this should be seen as text +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ source.svelte text.svelte +>{/each} +#^ source.svelte meta.special.each.svelte meta.special.end.svelte punctuation.definition.block.begin.svelte +# ^ source.svelte meta.special.each.svelte meta.special.end.svelte punctuation.definition.keyword.svelte +# ^^^^ source.svelte meta.special.each.svelte meta.special.end.svelte keyword.control.svelte +# ^ source.svelte meta.special.each.svelte meta.special.end.svelte punctuation.definition.block.end.svelte +> +>{#each v, i} +#^ source.svelte meta.special.each.svelte meta.special.start.svelte punctuation.definition.block.begin.svelte +# ^ source.svelte meta.special.each.svelte meta.special.start.svelte punctuation.definition.keyword.svelte +# ^^^^ source.svelte meta.special.each.svelte meta.special.start.svelte keyword.control.svelte +# ^ source.svelte meta.special.each.svelte meta.special.start.svelte +# ^ source.svelte meta.special.each.svelte meta.special.start.svelte meta.embedded.expression.svelte source.ts +# ^ source.svelte meta.special.each.svelte meta.special.start.svelte punctuation.separator.svelte +# ^^ source.svelte meta.special.each.svelte meta.special.start.svelte meta.embedded.expression.svelte source.ts +# ^ source.svelte meta.special.each.svelte meta.special.start.svelte punctuation.definition.block.end.svelte +> this should be seen as text +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ source.svelte text.svelte +>{/each} +#^ source.svelte meta.special.each.svelte meta.special.end.svelte punctuation.definition.block.begin.svelte +# ^ source.svelte meta.special.each.svelte meta.special.end.svelte punctuation.definition.keyword.svelte +# ^^^^ source.svelte meta.special.each.svelte meta.special.end.svelte keyword.control.svelte +# ^ source.svelte meta.special.each.svelte meta.special.end.svelte punctuation.definition.block.end.svelte +> +>{#each v , i} +#^ source.svelte meta.special.each.svelte meta.special.start.svelte punctuation.definition.block.begin.svelte +# ^ source.svelte meta.special.each.svelte meta.special.start.svelte punctuation.definition.keyword.svelte +# ^^^^ source.svelte meta.special.each.svelte meta.special.start.svelte keyword.control.svelte +# ^ source.svelte meta.special.each.svelte meta.special.start.svelte +# ^ source.svelte meta.special.each.svelte meta.special.start.svelte meta.embedded.expression.svelte source.ts +# ^ source.svelte meta.special.each.svelte meta.special.start.svelte +# ^ source.svelte meta.special.each.svelte meta.special.start.svelte punctuation.separator.svelte +# ^^ source.svelte meta.special.each.svelte meta.special.start.svelte meta.embedded.expression.svelte source.ts +# ^ source.svelte meta.special.each.svelte meta.special.start.svelte punctuation.definition.block.end.svelte +> this should be seen as text +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ source.svelte text.svelte +>{/each} +#^ source.svelte meta.special.each.svelte meta.special.end.svelte punctuation.definition.block.begin.svelte +# ^ source.svelte meta.special.each.svelte meta.special.end.svelte punctuation.definition.keyword.svelte +# ^^^^ source.svelte meta.special.each.svelte meta.special.end.svelte keyword.control.svelte +# ^ source.svelte meta.special.each.svelte meta.special.end.svelte punctuation.definition.block.end.svelte > \ No newline at end of file diff --git a/packages/svelte-vscode/test/grammar/test.js b/packages/svelte-vscode/test/grammar/test.js index 8a24b9b12..4dc3e8ba5 100644 --- a/packages/svelte-vscode/test/grammar/test.js +++ b/packages/svelte-vscode/test/grammar/test.js @@ -48,7 +48,9 @@ async function snapShotTest() { ]; const code = await promisifySpawn(process.platform === 'win32' ? 'npx.cmd' : 'npx', args, { - stdio: 'inherit' + stdio: 'inherit', + // https://nodejs.org/en/blog/vulnerability/april-2024-security-releases-2#command-injection-via-args-parameter-of-child_processspawn-without-shell-option-enabled-on-windows-cve-2024-27980---high + shell: true }); if (code > 0) { diff --git a/packages/svelte2tsx/src/htmlxtojsx_v2/nodes/EachBlock.ts b/packages/svelte2tsx/src/htmlxtojsx_v2/nodes/EachBlock.ts index 6ec39fadf..51dcb950e 100644 --- a/packages/svelte2tsx/src/htmlxtojsx_v2/nodes/EachBlock.ts +++ b/packages/svelte2tsx/src/htmlxtojsx_v2/nodes/EachBlock.ts @@ -21,36 +21,44 @@ import { getEnd, transform, TransformationArray } from '../utils/node-utils'; * `ensureArray` will error that there are more args than expected */ export function handleEach(str: MagicString, eachBlock: BaseNode): void { - const startEnd = str.original.indexOf('}', eachBlock.key?.end || eachBlock.context.end) + 1; + const startEnd = + str.original.indexOf( + '}', + eachBlock.key?.end || eachBlock.context?.end || eachBlock.expression.end + ) + 1; let transforms: TransformationArray; // {#each true, [1,2]} is valid but for (const x of true, [1,2]) is not if not wrapped with braces const containsComma = str.original .substring(eachBlock.expression.start, eachBlock.expression.end) .includes(','); const expressionEnd = getEnd(eachBlock.expression); - const contextEnd = getEnd(eachBlock.context); + const contextEnd = eachBlock.context && getEnd(eachBlock.context); const arrayAndItemVarTheSame = + !!eachBlock.context && str.original.substring(eachBlock.expression.start, expressionEnd) === - str.original.substring(eachBlock.context.start, contextEnd); + str.original.substring(eachBlock.context.start, contextEnd); if (arrayAndItemVarTheSame) { transforms = [ `{ const $$_each = __sveltets_2_ensureArray(${containsComma ? '(' : ''}`, [eachBlock.expression.start, eachBlock.expression.end], `${containsComma ? ')' : ''}); for(let `, - [eachBlock.context.start, contextEnd], + [eachBlock.context!.start, contextEnd!], ' of $$_each){' ]; } else { transforms = [ 'for(let ', - [eachBlock.context.start, contextEnd], + eachBlock.context ? [eachBlock.context.start, contextEnd] : '$$each_item', ` of __sveltets_2_ensureArray(${containsComma ? '(' : ''}`, [eachBlock.expression.start, eachBlock.expression.end], - `${containsComma ? ')' : ''})){` + `${containsComma ? ')' : ''})){${eachBlock.context ? '' : '$$each_item;'}` ]; } if (eachBlock.index) { - const indexStart = str.original.indexOf(eachBlock.index, eachBlock.context.end); + const indexStart = str.original.indexOf( + eachBlock.index, + eachBlock.context?.end || eachBlock.expression.end + ); const indexEnd = indexStart + eachBlock.index.length; transforms.push('let ', [indexStart, indexEnd], ' = 1;'); } diff --git a/packages/svelte2tsx/test/htmlx2jsx/samples/each-block-without-as.v5/expectedv2.js b/packages/svelte2tsx/test/htmlx2jsx/samples/each-block-without-as.v5/expectedv2.js new file mode 100644 index 000000000..22df537b6 --- /dev/null +++ b/packages/svelte2tsx/test/htmlx2jsx/samples/each-block-without-as.v5/expectedv2.js @@ -0,0 +1,5 @@ + for(let $$each_item of __sveltets_2_ensureArray({ length: 5 })){$$each_item; } + + for(let $$each_item of __sveltets_2_ensureArray({ length: 5 })){$$each_item;let index = 1; + index; +} \ No newline at end of file diff --git a/packages/svelte2tsx/test/htmlx2jsx/samples/each-block-without-as.v5/input.svelte b/packages/svelte2tsx/test/htmlx2jsx/samples/each-block-without-as.v5/input.svelte new file mode 100644 index 000000000..02a113e22 --- /dev/null +++ b/packages/svelte2tsx/test/htmlx2jsx/samples/each-block-without-as.v5/input.svelte @@ -0,0 +1,7 @@ +{#each { length: 5 }} + hi +{/each} + +{#each { length: 5 }, index} + {index} +{/each}