diff --git a/package.json b/package.json index 438c5c68b..78483ce60 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "lint": "prettier --check ." }, "dependencies": { - "typescript": "^5.6.3" + "typescript": "~5.6.3" }, "devDependencies": { "cross-env": "^7.0.2", diff --git a/packages/language-server/package.json b/packages/language-server/package.json index 6d7a5d4ca..3021cb374 100644 --- a/packages/language-server/package.json +++ b/packages/language-server/package.json @@ -62,7 +62,7 @@ "prettier-plugin-svelte": "^3.3.0", "svelte": "^4.2.19", "svelte2tsx": "workspace:~", - "typescript": "^5.6.3", + "typescript": "~5.6.3", "typescript-auto-import-cache": "^0.3.5", "vscode-css-languageservice": "~6.3.0", "vscode-html-languageservice": "~5.3.0", diff --git a/packages/language-server/test/plugins/typescript/features/CodeActionsProvider.test.ts b/packages/language-server/test/plugins/typescript/features/CodeActionsProvider.test.ts index 1ad7ac620..53fadc529 100644 --- a/packages/language-server/test/plugins/typescript/features/CodeActionsProvider.test.ts +++ b/packages/language-server/test/plugins/typescript/features/CodeActionsProvider.test.ts @@ -1755,20 +1755,9 @@ describe('CodeActionsProvider', function () { line: 1 } } - }, - { - newText: "import { } from './somepng.png';\n", - range: { - end: { - character: 0, - line: 4 - }, - start: { - character: 4, - line: 3 - } - } } + // Because the generated code adds a ; after the last import, the + // second import is not appearing in the edits here ], textDocument: { uri: getUri('organize-imports-leading-comment.svelte'), diff --git a/packages/svelte-check/package.json b/packages/svelte-check/package.json index 8cf77806e..df5d66db3 100644 --- a/packages/svelte-check/package.json +++ b/packages/svelte-check/package.json @@ -54,7 +54,7 @@ "rollup-plugin-copy": "^3.4.0", "svelte": "^4.2.19", "svelte-language-server": "workspace:*", - "typescript": "^5.6.3", + "typescript": "~5.6.3", "vscode-languageserver": "8.0.2", "vscode-languageserver-protocol": "3.17.2", "vscode-languageserver-types": "3.17.2", diff --git a/packages/svelte-vscode/package.json b/packages/svelte-vscode/package.json index 07a9c2542..30ab2dd03 100644 --- a/packages/svelte-vscode/package.json +++ b/packages/svelte-vscode/package.json @@ -732,7 +732,7 @@ "@types/vscode": "^1.67", "js-yaml": "^3.14.0", "tslib": "^2.4.0", - "typescript": "^5.6.3", + "typescript": "~5.6.3", "vscode-tmgrammar-test": "^0.0.11" }, "dependencies": { 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/package.json b/packages/svelte2tsx/package.json index 7a9f1758c..c608983da 100644 --- a/packages/svelte2tsx/package.json +++ b/packages/svelte2tsx/package.json @@ -40,7 +40,7 @@ "svelte": "~4.2.19", "tiny-glob": "^0.2.6", "tslib": "^2.4.0", - "typescript": "^5.6.3" + "typescript": "~5.6.3" }, "peerDependencies": { "svelte": "^3.55 || ^4.0.0-next.0 || ^4.0 || ^5.0.0-next.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/src/svelte2tsx/nodes/HoistableInterfaces.ts b/packages/svelte2tsx/src/svelte2tsx/nodes/HoistableInterfaces.ts index 093a4a132..7ee4de9b9 100644 --- a/packages/svelte2tsx/src/svelte2tsx/nodes/HoistableInterfaces.ts +++ b/packages/svelte2tsx/src/svelte2tsx/nodes/HoistableInterfaces.ts @@ -337,8 +337,11 @@ export class HoistableInterfaces { for (const [name, node] of hoistable) { let pos = node.pos + astOffset; - // node.pos includes preceeding whitespace, which could mean we accidentally also move stuff appended to a previous node - if (name !== '$$ComponentProps') { + if (name === '$$ComponentProps') { + // So that organize imports doesn't mess with the types + str.prependRight(pos, '\n'); + } else { + // node.pos includes preceeding whitespace, which could mean we accidentally also move stuff appended to a previous node if (str.original[pos] === '\r') { pos++; } @@ -346,7 +349,8 @@ export class HoistableInterfaces { pos++; } - // jsdoc comments would be ignored if they are on the same line as the ;, so we add a newline, too + // jsdoc comments would be ignored if they are on the same line as the ;, so we add a newline, too. + // Also helps with organize imports not messing with the types str.prependRight(pos, ';\n'); str.appendLeft(node.end + astOffset, ';'); } diff --git a/packages/svelte2tsx/src/svelte2tsx/nodes/handleImportDeclaration.ts b/packages/svelte2tsx/src/svelte2tsx/nodes/handleImportDeclaration.ts index 9a0b4a5e9..4f022260b 100644 --- a/packages/svelte2tsx/src/svelte2tsx/nodes/handleImportDeclaration.ts +++ b/packages/svelte2tsx/src/svelte2tsx/nodes/handleImportDeclaration.ts @@ -25,9 +25,8 @@ export function handleFirstInstanceImport( hasModuleScript: boolean, str: MagicString ) { - const firstImport = tsAst.statements - .filter(ts.isImportDeclaration) - .sort((a, b) => a.end - b.end)[0]; + const imports = tsAst.statements.filter(ts.isImportDeclaration).sort((a, b) => a.end - b.end); + const firstImport = imports[0]; if (!firstImport) { return; } @@ -42,4 +41,12 @@ export function handleFirstInstanceImport( : firstImport.getStart(); str.appendRight(start + astOffset, '\n' + (hasModuleScript ? '\n' : '')); + + // Add a semi-colon to the last import if it doesn't have one, to prevent auto completion + // and imports from being added at the wrong position + const lastImport = imports[imports.length - 1]; + const end = lastImport.end + astOffset - 1; + if (str.original[end] !== ';') { + str.overwrite(end, lastImport.end + astOffset, str.original[end] + ';\n'); + } } diff --git a/packages/svelte2tsx/test/htmlx2jsx/samples/binding/expectedv2.js b/packages/svelte2tsx/test/htmlx2jsx/samples/binding/expectedv2.js index 132f731ac..5b3a9a052 100644 --- a/packages/svelte2tsx/test/htmlx2jsx/samples/binding/expectedv2.js +++ b/packages/svelte2tsx/test/htmlx2jsx/samples/binding/expectedv2.js @@ -1,6 +1,6 @@ - { svelteHTML.createElement("input", { "type":`text`,"bind:value":test,});/*Ωignore_startΩ*/() => test = __sveltets_2_any(null);/*Ωignore_endΩ*/} - { svelteHTML.createElement("input", { "type":`text`,"bind:value":test,});/*Ωignore_startΩ*/() => test = __sveltets_2_any(null);/*Ωignore_endΩ*/} - { svelteHTML.createElement("input", { "type":`text`,"bind:value":test,});/*Ωignore_startΩ*/() => test = __sveltets_2_any(null);/*Ωignore_endΩ*/} + { svelteHTML.createElement("input", { "type":`text`,"bind:value":test,});/*Ωignore_startΩ*/() => test = __sveltets_2_any(null);/*Ωignore_endΩ*/} + { svelteHTML.createElement("input", { "type":`text`,"bind:value":test,});/*Ωignore_startΩ*/() => test = __sveltets_2_any(null);/*Ωignore_endΩ*/} + { svelteHTML.createElement("input", { "type":`text`,"bind:value":test,});/*Ωignore_startΩ*/() => test = __sveltets_2_any(null);/*Ωignore_endΩ*/} { const $$_tupnI0C = __sveltets_2_ensureComponent(Input); new $$_tupnI0C({ target: __sveltets_2_any(), props: { "type":`text`,value:test,}});/*Ωignore_startΩ*/() => test = __sveltets_2_any(null);/*Ωignore_endΩ*/} { const $$_tupnI0C = __sveltets_2_ensureComponent(Input); new $$_tupnI0C({ target: __sveltets_2_any(), props: { "type":`text`,value:test,}});/*Ωignore_startΩ*/() => test = __sveltets_2_any(null);/*Ωignore_endΩ*/} 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} diff --git a/packages/svelte2tsx/test/sourcemaps/samples/element-attributes/mappings.jsx b/packages/svelte2tsx/test/sourcemaps/samples/element-attributes/mappings.jsx index b5a478a40..f6aa46383 100644 --- a/packages/svelte2tsx/test/sourcemaps/samples/element-attributes/mappings.jsx +++ b/packages/svelte2tsx/test/sourcemaps/samples/element-attributes/mappings.jsx @@ -133,24 +133,25 @@ async•()•=>•{•{•svelteHTML.createElement("element",•{"foo":true,});} ↲ />↲ [original] line 21 (rest generated at line 13) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} - { svelteHTML.createElement("element", { "bind:foo":bar,});/*Ωignore_startΩ*/() => bar = __sveltets_2_any(null);/*Ωignore_endΩ*/}}; {/** -•{•svelteHTML.createElement("element",•{••"bind:foo":bar,});/*Ωignore_startΩ*/()•=>•bar•=•__sveltets_2_any(null);/*Ωignore_endΩ*/}};↲ [generated] line 15 -•{•svelteHTML.createElement("element",•{ "bind:foo": [generated] subset -< element ↲ + { svelteHTML.createElement("element", { "bind:foo":bar,});/*Ωignore_startΩ*/() => bar = __sveltets_2_any(null);/*Ωignore_endΩ*/}}; {/** +•{•svelteHTML.createElement("element",•{•••"bind:foo":bar,});/*Ωignore_startΩ*/()•=>•bar•=•__sveltets_2_any(null);/*Ωignore_endΩ*/}};↲ [generated] line 15 +•{•svelteHTML.createElement("element",•{ " [generated] subset +< element ↲ •bar•=•__sveltets_2_any(null);/*Ωignore_endΩ*/}};↲ [generated] line 15 - • bar,});/*Ωignore_startΩ*/()•=>•bar•=•__sveltets_2_any(null);/*Ωignore_endΩ*/}};↲ [generated] subset - • bar} -• bar} -••••bind:foo={bar}↲ [original] line 24 +•{•svelteHTML.createElement("element",•{•••"bind:foo":bar,});/*Ωignore_startΩ*/()•=>•bar•=•__sveltets_2_any(null);/*Ωignore_endΩ*/}};↲ [generated] line 15 + •• bind:foo":bar,});/*Ωignore_startΩ*/()•=>•bar•=•__sveltets_2_any(null);/*Ωignore_endΩ*/}};↲ [generated] subset + •{ bind:foo= bar} + #== Order-breaking mappings +• bind:foo={bar} +••••bind:foo={bar}↲ [original] line 24 -•{•svelteHTML.createElement("element",•{••"bind:foo":bar,});/*Ωignore_startΩ*/()•=>•bar•=•__sveltets_2_any(null);/*Ωignore_endΩ*/}};↲ [generated] line 15 - • [generated] subset - / +•{•svelteHTML.createElement("element",•{•••"bind:foo":bar,});/*Ωignore_startΩ*/()•=>•bar•=•__sveltets_2_any(null);/*Ωignore_endΩ*/}};↲ [generated] line 15 + • [generated] subset + / / -/> [original] line 25 +/> [original] line 25 ------------------------------------------------------------------------------------------------------------------------------------------------------ */} return { props: /** @type {Record} */ ({}), slots: {}, events: {} }} diff --git a/packages/svelte2tsx/test/sourcemaps/samples/large-sample-1/mappings.jsx b/packages/svelte2tsx/test/sourcemaps/samples/large-sample-1/mappings.jsx index 44c3de9a8..419f8ad51 100644 --- a/packages/svelte2tsx/test/sourcemaps/samples/large-sample-1/mappings.jsx +++ b/packages/svelte2tsx/test/sourcemaps/samples/large-sample-1/mappings.jsx @@ -368,9 +368,9 @@ s ↲ ------------------------------------------------------------------------------------------------------------------------------------------------------ */} { svelteHTML.createElement("svelte:window", { "bind:innerWidth":width,});/*Ωignore_startΩ*/() => width = __sveltets_2_any(null);/*Ωignore_endΩ*/} {/** ••{•svelteHTML.createElement("svelte:window",•{•"bind:innerWidth":width,});/*Ωignore_startΩ*/()•=>•width•=•__sveltets_2_any(null);/*Ωignore_endΩ*/}↲ [generated] line 133 -<> ib width} ↲ - #=============================================# Order-breaking mappings -< bi width} >↲ +<> { bind:innerWidth= width} ↲ + #=============================================#= Order-breaking mappings +< bind:innerWidth={width} >↲ ↲ [original] line 269 (rest generated at line 134) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} {/** diff --git a/packages/svelte2tsx/test/svelte2tsx/samples/imports/expectedv2.ts b/packages/svelte2tsx/test/svelte2tsx/samples/imports/expectedv2.ts index ae4e57e82..b80485ccf 100644 --- a/packages/svelte2tsx/test/svelte2tsx/samples/imports/expectedv2.ts +++ b/packages/svelte2tsx/test/svelte2tsx/samples/imports/expectedv2.ts @@ -2,7 +2,7 @@ ; import { a as b } from "./test.svelte" -import * as c from "b.ts" +import * as c from "b.ts"; function render() { diff --git a/packages/svelte2tsx/test/svelte2tsx/samples/jsdoc-before-first-import/expectedv2.ts b/packages/svelte2tsx/test/svelte2tsx/samples/jsdoc-before-first-import/expectedv2.ts index 3e8c7c047..138ef5946 100644 --- a/packages/svelte2tsx/test/svelte2tsx/samples/jsdoc-before-first-import/expectedv2.ts +++ b/packages/svelte2tsx/test/svelte2tsx/samples/jsdoc-before-first-import/expectedv2.ts @@ -2,7 +2,7 @@ ;// non-leading comment /**@typedef {{ a: string }} Foo */ -import '' +import ''; function render() { diff --git a/packages/svelte2tsx/test/svelte2tsx/samples/ts-runes-hoistable-props-2.v5/expectedv2.ts b/packages/svelte2tsx/test/svelte2tsx/samples/ts-runes-hoistable-props-2.v5/expectedv2.ts index 556d5bb46..b66a2a1d8 100644 --- a/packages/svelte2tsx/test/svelte2tsx/samples/ts-runes-hoistable-props-2.v5/expectedv2.ts +++ b/packages/svelte2tsx/test/svelte2tsx/samples/ts-runes-hoistable-props-2.v5/expectedv2.ts @@ -5,7 +5,8 @@ interface Dependency { a: number; b: typeof value; - };;type $$ComponentProps = { a: Dependency, b: string };function render() { + }; +;type $$ComponentProps = { a: Dependency, b: string };function render() { diff --git a/packages/svelte2tsx/test/svelte2tsx/samples/ts-runes.v5/expectedv2.ts b/packages/svelte2tsx/test/svelte2tsx/samples/ts-runes.v5/expectedv2.ts index b15ca4992..ae5caf1a7 100644 --- a/packages/svelte2tsx/test/svelte2tsx/samples/ts-runes.v5/expectedv2.ts +++ b/packages/svelte2tsx/test/svelte2tsx/samples/ts-runes.v5/expectedv2.ts @@ -1,5 +1,6 @@ /// -;;type $$ComponentProps = { a: number, b: string };function render() { +; +;type $$ComponentProps = { a: number, b: string };function render() { let { a, b }:/*Ωignore_startΩ*/$$ComponentProps/*Ωignore_endΩ*/ = $props(); let x = $state(0); diff --git a/packages/svelte2tsx/test/svelte2tsx/samples/ts-sveltekit-autotypes-$props-rune-unchanged.v5/expectedv2.ts b/packages/svelte2tsx/test/svelte2tsx/samples/ts-sveltekit-autotypes-$props-rune-unchanged.v5/expectedv2.ts index 51e17c6ce..385c54c68 100644 --- a/packages/svelte2tsx/test/svelte2tsx/samples/ts-sveltekit-autotypes-$props-rune-unchanged.v5/expectedv2.ts +++ b/packages/svelte2tsx/test/svelte2tsx/samples/ts-sveltekit-autotypes-$props-rune-unchanged.v5/expectedv2.ts @@ -1,5 +1,6 @@ /// -;;type $$ComponentProps = {form: boolean, data: true };function render() { +; +;type $$ComponentProps = {form: boolean, data: true };function render() { const snapshot: any = {}; let { form, data }:/*Ωignore_startΩ*/$$ComponentProps/*Ωignore_endΩ*/ = $props(); diff --git a/packages/typescript-plugin/package.json b/packages/typescript-plugin/package.json index b3e934521..9f41a5dfe 100644 --- a/packages/typescript-plugin/package.json +++ b/packages/typescript-plugin/package.json @@ -24,7 +24,7 @@ "license": "MIT", "devDependencies": { "@types/node": "^18.0.0", - "typescript": "^5.6.3", + "typescript": "~5.6.3", "svelte": "^4.2.19" }, "dependencies": { diff --git a/packages/typescript-plugin/src/svelte-snapshots.ts b/packages/typescript-plugin/src/svelte-snapshots.ts index 438ceb6ca..87cad7305 100644 --- a/packages/typescript-plugin/src/svelte-snapshots.ts +++ b/packages/typescript-plugin/src/svelte-snapshots.ts @@ -269,7 +269,7 @@ export class SvelteSnapshot { } export class SvelteSnapshotManager { - private snapshots = new Map(); + private snapshots: Map; constructor( private typescript: typeof ts, @@ -280,7 +280,9 @@ export class SvelteSnapshotManager { /** undefined if no node_modules with Svelte next to tsconfig.json */ private svelteCompiler: typeof import('svelte/compiler') | undefined ) { - this.patchProjectServiceReadFile(); + this.patchProjectService(); + // @ts-expect-error + this.snapshots = this.projectService[snapshots]; } get(fileName: string) { @@ -321,92 +323,78 @@ export class SvelteSnapshotManager { return snapshot; } - private patchProjectServiceReadFile() { - // @ts-ignore The projectService is shared across some instances, make sure we patch readFile only once - if (!this.projectService.host[onReadSvelteFile]) { - this.logger.log('patching projectService host readFile'); + private patchProjectService() { + // @ts-expect-error The projectService is shared across some instances, make sure we patch only once + if (this.projectService[snapshots]) return; - // @ts-ignore - this.projectService.host[onReadSvelteFile] = []; + this.logger.log('patching projectService'); - const readFile = this.projectService.host.readFile; - this.projectService.host.readFile = (path: string, encoding?: string | undefined) => { - if (!this.configManager.getConfig().enable) { - return readFile(path, encoding); - } + // @ts-expect-error Snapshots are stored on the projectService, so they are shared across all instances + this.snapshots = this.projectService[snapshots] = new Map(); - // The following (very hacky) first two checks make sure that the ambient module definitions - // that tell TS "every import ending with .svelte is a valid module" are removed. - // They exist in svelte2tsx and svelte to make sure that people don't - // get errors in their TS files when importing Svelte files and not using our TS plugin. - // If someone wants to get back the behavior they can add an ambient module definition - // on their own. - const normalizedPath = path.replace(/\\/g, '/'); - if (normalizedPath.endsWith('node_modules/svelte/types/runtime/ambient.d.ts')) { - return ''; - } else if (normalizedPath.endsWith('svelte2tsx/svelte-jsx.d.ts')) { - // Remove the dom lib reference to not load these ambient types in case - // the user has a tsconfig.json with different lib settings like in - // https://github.com/sveltejs/language-tools/issues/1733 - const originalText = readFile(path) || ''; - const toReplace = '/// '; - return originalText.replace(toReplace, ' '.repeat(toReplace.length)); - } else if (normalizedPath.endsWith('svelte2tsx/svelte-shims.d.ts')) { - let originalText = readFile(path) || ''; - if (!originalText.includes('// -- start svelte-ls-remove --')) { - return originalText; // uses an older version of svelte2tsx or is already patched - } - const startIdx = originalText.indexOf('// -- start svelte-ls-remove --'); - const endIdx = originalText.indexOf('// -- end svelte-ls-remove --'); - originalText = - originalText.substring(0, startIdx) + - ' '.repeat(endIdx - startIdx) + - originalText.substring(endIdx); - return originalText; - } else if (isSvelteFilePath(path)) { - this.logger.debug('Read Svelte file:', path); - const svelteCode = readFile(path) || ''; - const isTsFile = true; // TODO check file contents? TS might be okay with importing ts into js. - let code: string; - let mapper: SourceMapper; - - try { - const result = svelte2tsx(svelteCode, { - filename: path.split('/').pop(), - isTsFile, - mode: 'ts', - typingsNamespace: this.svelteOptions.namespace, - // Don't search for compiler from current path - could be a different one from which we have loaded the svelte2tsx globals - parse: this.svelteCompiler?.parse, - version: this.svelteCompiler?.VERSION - }); - code = result.code; - mapper = new SourceMapper(result.map.mappings); - this.logger.log('Successfully read Svelte file contents of', path); - } catch (e) { - this.logger.log('Error loading Svelte file:', path, ' Using fallback.'); - this.logger.debug('Error:', e); - // Return something either way, else "X is not a module" errors will appear - // in the TS files that use this file. - code = 'export default class extends Svelte2TsxComponent {}'; - mapper = new SourceMapper(''); - } - - // @ts-ignore - this.projectService.host[onReadSvelteFile].forEach((listener) => - listener(path, svelteCode, isTsFile, mapper) - ); + const readFile = this.projectService.host.readFile; + this.projectService.host.readFile = (path: string, encoding?: string | undefined) => { + if (!this.configManager.getConfig().enable) { + return readFile(path, encoding); + } - return code; - } else { - return readFile(path, encoding); + // The following (very hacky) first two checks make sure that the ambient module definitions + // that tell TS "every import ending with .svelte is a valid module" are removed. + // They exist in svelte2tsx and svelte to make sure that people don't + // get errors in their TS files when importing Svelte files and not using our TS plugin. + // If someone wants to get back the behavior they can add an ambient module definition + // on their own. + const normalizedPath = path.replace(/\\/g, '/'); + if (normalizedPath.endsWith('node_modules/svelte/types/runtime/ambient.d.ts')) { + return ''; + } else if (normalizedPath.endsWith('svelte2tsx/svelte-jsx.d.ts')) { + // Remove the dom lib reference to not load these ambient types in case + // the user has a tsconfig.json with different lib settings like in + // https://github.com/sveltejs/language-tools/issues/1733 + const originalText = readFile(path) || ''; + const toReplace = '/// '; + return originalText.replace(toReplace, ' '.repeat(toReplace.length)); + } else if (normalizedPath.endsWith('svelte2tsx/svelte-shims.d.ts')) { + let originalText = readFile(path) || ''; + if (!originalText.includes('// -- start svelte-ls-remove --')) { + return originalText; // uses an older version of svelte2tsx or is already patched + } + const startIdx = originalText.indexOf('// -- start svelte-ls-remove --'); + const endIdx = originalText.indexOf('// -- end svelte-ls-remove --'); + originalText = + originalText.substring(0, startIdx) + + ' '.repeat(endIdx - startIdx) + + originalText.substring(endIdx); + return originalText; + } else if (isSvelteFilePath(path)) { + this.logger.debug('Read Svelte file:', path); + const svelteCode = readFile(path) || ''; + const isTsFile = true; // TODO check file contents? TS might be okay with importing ts into js. + let code: string; + let mapper: SourceMapper; + + try { + const result = svelte2tsx(svelteCode, { + filename: path.split('/').pop(), + isTsFile, + mode: 'ts', + typingsNamespace: this.svelteOptions.namespace, + // Don't search for compiler from current path - could be a different one from which we have loaded the svelte2tsx globals + parse: this.svelteCompiler?.parse, + version: this.svelteCompiler?.VERSION + }); + code = result.code; + mapper = new SourceMapper(result.map.mappings); + this.logger.log('Successfully read Svelte file contents of', path); + } catch (e) { + this.logger.log('Error loading Svelte file:', path, ' Using fallback.'); + this.logger.debug('Error:', e); + // Return something either way, else "X is not a module" errors will appear + // in the TS files that use this file. + code = 'export default class extends Svelte2TsxComponent {}'; + mapper = new SourceMapper(''); } - }; - } - // @ts-ignore - this.projectService.host[onReadSvelteFile].push( - (path: string, svelteCode: string, isTsFile: boolean, mapper: SourceMapper) => { const canonicalFilePath = this.projectService.toCanonicalFileName(path); const existingSnapshot = this.snapshots.get(canonicalFilePath); if (existingSnapshot) { @@ -424,9 +412,13 @@ export class SvelteSnapshotManager { ) ); } + + return code; + } else { + return readFile(path, encoding); } - ); + }; } } -const onReadSvelteFile = Symbol('sveltePluginPatchSymbol'); +const snapshots = Symbol('sveltePluginPatchSymbol'); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6e1703cb9..8e27e7797 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9,7 +9,7 @@ importers: .: dependencies: typescript: - specifier: ^5.6.3 + specifier: ~5.6.3 version: 5.6.3 devDependencies: cross-env: @@ -58,7 +58,7 @@ importers: specifier: workspace:~ version: link:../svelte2tsx typescript: - specifier: ^5.6.3 + specifier: ~5.6.3 version: 5.6.3 typescript-auto-import-cache: specifier: ^0.3.5 @@ -168,7 +168,7 @@ importers: specifier: workspace:* version: link:../language-server typescript: - specifier: ^5.6.3 + specifier: ~5.6.3 version: 5.6.3 vscode-languageserver: specifier: 8.0.2 @@ -217,7 +217,7 @@ importers: specifier: ^2.4.0 version: 2.5.2 typescript: - specifier: ^5.6.3 + specifier: ~5.6.3 version: 5.6.3 vscode-tmgrammar-test: specifier: ^0.0.11 @@ -299,7 +299,7 @@ importers: specifier: ^2.4.0 version: 2.5.2 typescript: - specifier: ^5.6.3 + specifier: ~5.6.3 version: 5.6.3 packages/typescript-plugin: @@ -318,7 +318,7 @@ importers: specifier: ^4.2.19 version: 4.2.19 typescript: - specifier: ^5.6.3 + specifier: ~5.6.3 version: 5.6.3 packages: pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy