diff --git a/packages/language-server/src/plugins/typescript/TypeScriptPlugin.ts b/packages/language-server/src/plugins/typescript/TypeScriptPlugin.ts index b052688e9..098bec745 100644 --- a/packages/language-server/src/plugins/typescript/TypeScriptPlugin.ts +++ b/packages/language-server/src/plugins/typescript/TypeScriptPlugin.ts @@ -93,6 +93,7 @@ import { convertToLocationForReferenceOrDefinition, convertToLocationRange, isInScript, + isSvelte2tsxShimFile, isSvelteFilePath, symbolKindFromString } from './utils'; @@ -387,7 +388,7 @@ export class TypeScriptPlugin const result = await Promise.all( defs.definitions.map(async (def) => { - if (def.fileName.endsWith('svelte-shims.d.ts')) { + if (isSvelte2tsxShimFile(def.fileName)) { return; } diff --git a/packages/language-server/src/plugins/typescript/features/InlayHintProvider.ts b/packages/language-server/src/plugins/typescript/features/InlayHintProvider.ts index 63d1e98ae..9ca919900 100644 --- a/packages/language-server/src/plugins/typescript/features/InlayHintProvider.ts +++ b/packages/language-server/src/plugins/typescript/features/InlayHintProvider.ts @@ -17,10 +17,10 @@ import { isInGeneratedCode, findChildOfKind, findRenderFunction, - findClosestContainingNode, - SnapshotMap + SnapshotMap, + startsWithIgnoredPosition } from './utils'; -import { convertRange } from '../utils'; +import { convertRange, isSvelte2tsxShimFile } from '../utils'; export class InlayHintProviderImpl implements InlayHintProvider { constructor(private readonly lsAndTsDocResolver: LSAndTSDocResolver) {} @@ -195,10 +195,19 @@ export class InlayHintProviderImpl implements InlayHintProvider { return false; } - const node = findClosestContainingNode( + if (inlayHint.displayParts?.some((v) => isSvelte2tsxShimFile(v.file))) { + return true; + } + + const hasParameterWithSamePosition = (node: ts.CallExpression | ts.NewExpression) => + node.arguments !== undefined && + node.arguments.some((arg) => arg.getStart() === inlayHint.position); + + const node = findContainingNode( sourceFile, { start: inlayHint.position, length: 0 }, - ts.isCallOrNewExpression + (node): node is ts.CallExpression | ts.NewExpression => + ts.isCallOrNewExpression(node) && hasParameterWithSamePosition(node) ); if (!node) { @@ -224,6 +233,10 @@ export class InlayHintProviderImpl implements InlayHintProvider { return false; } + if (startsWithIgnoredPosition(sourceFile.text, inlayHint.position)) { + return true; + } + const declaration = findContainingNode( sourceFile, { start: inlayHint.position, length: 0 }, diff --git a/packages/language-server/src/plugins/typescript/features/utils.ts b/packages/language-server/src/plugins/typescript/features/utils.ts index 02adde610..f8ee48a21 100644 --- a/packages/language-server/src/plugins/typescript/features/utils.ts +++ b/packages/language-server/src/plugins/typescript/features/utils.ts @@ -83,6 +83,7 @@ export function isComponentAtPosition( export const IGNORE_START_COMMENT = '/*Ωignore_startΩ*/'; export const IGNORE_END_COMMENT = '/*Ωignore_endΩ*/'; +export const IGNORE_POSITION_COMMENT = '/*Ωignore_positionΩ*/'; /** * Surrounds given string with a start/end comment which marks it @@ -105,6 +106,10 @@ export function isInGeneratedCode(text: string, start: number, end: number = sta return (lastStart > lastEnd || lastEnd === nextEnd) && lastStart < nextEnd; } +export function startsWithIgnoredPosition(text: string, offset: number) { + return text.slice(offset).startsWith(IGNORE_POSITION_COMMENT); +} + /** * Checks if this is a text span that is inside svelte2tsx-generated code * (has no mapping to the original) diff --git a/packages/language-server/src/plugins/typescript/utils.ts b/packages/language-server/src/plugins/typescript/utils.ts index b9c00d1f2..62fa6359d 100644 --- a/packages/language-server/src/plugins/typescript/utils.ts +++ b/packages/language-server/src/plugins/typescript/utils.ts @@ -371,3 +371,7 @@ export function hasTsExtensions(fileName: string) { fileName.endsWith(ts.Extension.Ts) ); } + +export function isSvelte2tsxShimFile(fileName: string | undefined) { + return fileName?.endsWith('svelte-shims.d.ts') || fileName?.endsWith('svelte-shims-v4.d.ts'); +} diff --git a/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/implicit-snippet.v5/SnippetParent.svelte b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/implicit-snippet.v5/SnippetParent.svelte new file mode 100644 index 000000000..50973865f --- /dev/null +++ b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/implicit-snippet.v5/SnippetParent.svelte @@ -0,0 +1,7 @@ + \ No newline at end of file diff --git a/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/implicit-snippet.v5/expectedv2.json b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/implicit-snippet.v5/expectedv2.json new file mode 100644 index 000000000..f00cdb63b --- /dev/null +++ b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/implicit-snippet.v5/expectedv2.json @@ -0,0 +1,18 @@ +[ + { + "range": { "start": { "line": 4, "character": 1 }, "end": { "line": 4, "character": 14 } }, + "severity": 1, + "source": "ts", + "message": "Property 'required' is missing in type '{ children: () => any; foo: (this: void, a: \"\") => any; }' but required in type '$$ComponentProps'.", + "code": 2741, + "tags": [] + }, + { + "range": { "start": { "line": 6, "character": 9 }, "end": { "line": 6, "character": 18 } }, + "severity": 1, + "source": "ts", + "message": "This comparison appears to be unintentional because the types '\"\"' and '\"b\"' have no overlap.", + "code": 2367, + "tags": [] + } +] diff --git a/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/implicit-snippet.v5/input.svelte b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/implicit-snippet.v5/input.svelte new file mode 100644 index 000000000..d972304f3 --- /dev/null +++ b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/implicit-snippet.v5/input.svelte @@ -0,0 +1,11 @@ + + + + {#snippet foo(a)} + {a === 'b'} + {/snippet} + + {@render foo('')} + \ No newline at end of file diff --git a/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/snippet-js.v5/expectedv2.json b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/snippet-js.v5/expectedv2.json new file mode 100644 index 000000000..9b6fabf0e --- /dev/null +++ b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/snippet-js.v5/expectedv2.json @@ -0,0 +1,24 @@ +[ + { + "range": { + "start": { "line": 10, "character": 9 }, + "end": { "line": 10, "character": 18 } + }, + "severity": 1, + "source": "js", + "message": "This comparison appears to be unintentional because the types 'number' and 'string' have no overlap.", + "code": 2367, + "tags": [] + }, + { + "range": { + "start": { "line": 16, "character": 12 }, + "end": { "line": 16, "character": 15 } + }, + "severity": 1, + "source": "js", + "message": "Argument of type '\"c\"' is not assignable to parameter of type 'TypeA'.", + "code": 2345, + "tags": [] + } +] diff --git a/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/snippet-js.v5/input.svelte b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/snippet-js.v5/input.svelte new file mode 100644 index 000000000..e4f381bd9 --- /dev/null +++ b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/snippet-js.v5/input.svelte @@ -0,0 +1,17 @@ + + + +{#snippet hi(/**@type {TypeA}*/a, b = 2)} + {a} + {#if b === 'a'} + {b} + {/if} +{/snippet} + + +{@render hi('c', 'd')} \ No newline at end of file diff --git a/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/snippet-scope.v5/expectedv2.json b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/snippet-scope.v5/expectedv2.json new file mode 100644 index 000000000..29adc907d --- /dev/null +++ b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/snippet-scope.v5/expectedv2.json @@ -0,0 +1,13 @@ +[ + { + "range": { + "start": { "line": 15, "character": 9 }, + "end": { "line": 15, "character": 16 } + }, + "severity": 1, + "source": "ts", + "message": "Cannot find name 'nested1'.", + "code": 2304, + "tags": [] + } +] diff --git a/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/snippet-scope.v5/input.svelte b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/snippet-scope.v5/input.svelte new file mode 100644 index 000000000..f2e6036c2 --- /dev/null +++ b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/snippet-scope.v5/input.svelte @@ -0,0 +1,16 @@ + + + +
+ + {#snippet nested1()}{/snippet} + {@render nested1()} +
+ +{#snippet top()}{/snippet} + + +{@render nested1()} \ No newline at end of file diff --git a/packages/language-server/test/plugins/typescript/features/inlayHints/fixtures/snippet.v5/expectedv2.json b/packages/language-server/test/plugins/typescript/features/inlayHints/fixtures/snippet.v5/expectedv2.json new file mode 100644 index 000000000..44cd6554d --- /dev/null +++ b/packages/language-server/test/plugins/typescript/features/inlayHints/fixtures/snippet.v5/expectedv2.json @@ -0,0 +1,20 @@ +[ + { + "label": [ + { + "value": "a", + "location": { + "range": { + "start": { "line": 0, "character": 14 }, + "end": { "line": 0, "character": 15 } + }, + "uri": "/snippet.v5/input.svelte" + } + }, + { "value": ":" } + ], + "position": { "line": 4, "character": 13 }, + "kind": 2, + "paddingRight": true + } +] diff --git a/packages/language-server/test/plugins/typescript/features/inlayHints/fixtures/snippet.v5/input.svelte b/packages/language-server/test/plugins/typescript/features/inlayHints/fixtures/snippet.v5/input.svelte new file mode 100644 index 000000000..68c3bc52c --- /dev/null +++ b/packages/language-server/test/plugins/typescript/features/inlayHints/fixtures/snippet.v5/input.svelte @@ -0,0 +1,5 @@ +{#snippet hi2(a = 1)} + hello world +{/snippet} + +{@render hi2(1)} \ No newline at end of file diff --git a/packages/language-server/test/plugins/typescript/test-utils.ts b/packages/language-server/test/plugins/typescript/test-utils.ts index 4c398c12c..c77970256 100644 --- a/packages/language-server/test/plugins/typescript/test-utils.ts +++ b/packages/language-server/test/plugins/typescript/test-utils.ts @@ -7,6 +7,9 @@ import { FileMap } from '../../../src/lib/documents/fileCollection'; import { LSConfigManager } from '../../../src/ls-config'; import { LSAndTSDocResolver } from '../../../src/plugins'; import { createGetCanonicalFileName, normalizePath, pathToUrl } from '../../../src/utils'; +import { VERSION } from 'svelte/compiler'; + +const isSvelte5Plus = Number(VERSION.split('.')[0]) >= 5; export function createVirtualTsSystem(currentDirectory: string): ts.System { const virtualFs = new FileMap(); @@ -198,7 +201,12 @@ export function createSnapshotTester< } if (existsSync(inputFile)) { - const _it = dir.endsWith('.only') ? it.only : it; + const _it = + dir.endsWith('.v5') && !isSvelte5Plus + ? it.skip + : dir.endsWith('.only') + ? it.only + : it; _it(dir.substring(__dirname.length), () => executeTest(inputFile, testOptions)); } else { const _describe = dir.endsWith('.only') ? describe.only : describe; diff --git a/packages/svelte2tsx/src/htmlxtojsx_v2/index.ts b/packages/svelte2tsx/src/htmlxtojsx_v2/index.ts index 49474ca2a..0fced1e1c 100644 --- a/packages/svelte2tsx/src/htmlxtojsx_v2/index.ts +++ b/packages/svelte2tsx/src/htmlxtojsx_v2/index.ts @@ -26,7 +26,7 @@ import { handleSpread } from './nodes/Spread'; import { handleStyleDirective } from './nodes/StyleDirective'; import { handleText } from './nodes/Text'; import { handleTransitionDirective } from './nodes/Transition'; -import { handleImplicitChildren, handleSnippet } from './nodes/SnippetBlock'; +import { handleImplicitChildren, handleSnippet, hoistSnippetBlock } from './nodes/SnippetBlock'; import { handleRenderTag } from './nodes/RenderTag'; type Walker = (node: TemplateNode, parent: BaseNode, prop: string, index: number) => void; @@ -63,6 +63,8 @@ export function convertHtmlxToJsx( const rootSnippets: Array<[number, number]> = []; let element: Element | InlineComponent | undefined; + const pendingSnippetHoistCheck = new Set(); + walk(ast as any, { enter: (estreeTypedNode, estreeTypedParent, prop: string, index: number) => { const node = estreeTypedNode as TemplateNode; @@ -94,6 +96,8 @@ export function convertHtmlxToJsx( if (parent === ast) { // root snippet -> move to instance script rootSnippets.push([node.start, node.end]); + } else { + pendingSnippetHoistCheck.add(parent); } break; case 'MustacheTag': @@ -251,6 +255,10 @@ export function convertHtmlxToJsx( } }); + for (const node of pendingSnippetHoistCheck) { + hoistSnippetBlock(str, node); + } + return rootSnippets; } diff --git a/packages/svelte2tsx/src/htmlxtojsx_v2/nodes/InlineComponent.ts b/packages/svelte2tsx/src/htmlxtojsx_v2/nodes/InlineComponent.ts index f340cd922..b1bab058d 100644 --- a/packages/svelte2tsx/src/htmlxtojsx_v2/nodes/InlineComponent.ts +++ b/packages/svelte2tsx/src/htmlxtojsx_v2/nodes/InlineComponent.ts @@ -33,6 +33,7 @@ export class InlineComponent { private propsTransformation: TransformationArray = []; private eventsTransformation: TransformationArray = []; private slotLetsTransformation?: [TransformationArray, TransformationArray]; + private snippetPropsTransformation: TransformationArray = []; private endTransformation: TransformationArray = []; private startTagStart: number; private startTagEnd: number; @@ -159,6 +160,12 @@ export class InlineComponent { this.slotLetsTransformation[1].push(...transformation, ','); } + addImplicitSnippetProp(name: [number, number], transforms: TransformationArray): void { + this.addProp([name], transforms); + + this.snippetPropsTransformation.push(this.str.original.slice(name[0], name[1])); + } + /** * Add something right after the start tag end. */ @@ -191,6 +198,13 @@ export class InlineComponent { this.endTransformation.push('}'); } + const snippetPropVariables = this.snippetPropsTransformation?.join(', '); + const snippetPropVariablesDeclaration = snippetPropVariables + ? surroundWithIgnoreComments( + `const {${snippetPropVariables}} = ${this.name}.$$prop_def;` + ) + : ''; + if (this.isSelfclosing) { this.endTransformation.push('}'); transform(this.str, this.startTagStart, this.startTagEnd, this.startTagEnd, [ @@ -203,6 +217,7 @@ export class InlineComponent { ...this.startEndTransformation, ...this.eventsTransformation, ...defaultSlotLetTransformation, + snippetPropVariablesDeclaration, ...this.endTransformation ]); } else { @@ -223,6 +238,7 @@ export class InlineComponent { ...this.propsTransformation, ...this.startEndTransformation, ...this.eventsTransformation, + snippetPropVariablesDeclaration, ...defaultSlotLetTransformation ]); transform(this.str, endStart, this.node.end, this.node.end, this.endTransformation); diff --git a/packages/svelte2tsx/src/htmlxtojsx_v2/nodes/SnippetBlock.ts b/packages/svelte2tsx/src/htmlxtojsx_v2/nodes/SnippetBlock.ts index 989fe6347..4a8957700 100644 --- a/packages/svelte2tsx/src/htmlxtojsx_v2/nodes/SnippetBlock.ts +++ b/packages/svelte2tsx/src/htmlxtojsx_v2/nodes/SnippetBlock.ts @@ -2,7 +2,7 @@ import MagicString from 'magic-string'; import { BaseNode } from '../../interfaces'; import { transform, TransformationArray } from '../utils/node-utils'; import { InlineComponent } from './InlineComponent'; -import { surroundWithIgnoreComments } from '../../utils/ignore'; +import { IGNORE_POSITION_COMMENT, surroundWithIgnoreComments } from '../../utils/ignore'; /** * Transform #snippet into a function @@ -14,9 +14,9 @@ import { surroundWithIgnoreComments } from '../../utils/ignore'; * ``` * --> if standalone: * ```ts - * const foo = (bar) => { + * const foo = (bar) => { async () => { * .. - * } + * };return return __sveltets_2_any(0)}; * ``` * --> if slot prop: * ```ts @@ -32,15 +32,14 @@ export function handleSnippet( ): void { const isImplicitProp = component !== undefined; const endSnippet = str.original.lastIndexOf('{', snippetBlock.end - 1); - // Return something to silence the "snippet type not assignable to return type void" error - str.overwrite( - endSnippet, - snippetBlock.end, - `};return __sveltets_2_any(0)}${isImplicitProp ? '' : ';'}`, - { - contentOnly: true - } - ); + + const afterSnippet = isImplicitProp + ? `};return __sveltets_2_any(0)}` + : `};return __sveltets_2_any(0)};`; + + str.overwrite(endSnippet, snippetBlock.end, afterSnippet, { + contentOnly: true + }); const lastParameter = snippetBlock.parameters?.at(-1); @@ -50,13 +49,24 @@ export function handleSnippet( lastParameter?.typeAnnotation?.end ?? lastParameter?.end ?? snippetBlock.expression.end ) + 1; + let parameters: [number, number] | undefined; + + if (snippetBlock.parameters?.length) { + const firstParameter = snippetBlock.parameters[0]; + const start = firstParameter?.leadingComments?.[0]?.start ?? firstParameter.start; + const end = lastParameter.typeAnnotation?.end ?? lastParameter.end; + parameters = [start, end]; + } + + // inner async function for potential #await blocks + const afterParameters = ` => { async ()${IGNORE_POSITION_COMMENT} => {`; + if (isImplicitProp) { str.overwrite(snippetBlock.start, snippetBlock.expression.start, '', { contentOnly: true }); const transforms: TransformationArray = ['(']; - if (snippetBlock.parameters?.length) { - const start = snippetBlock.parameters[0].start; - const end = lastParameter.typeAnnotation?.end ?? lastParameter.end; - transforms.push([start, end]); + if (parameters) { + transforms.push(parameters); + const [start, end] = parameters; str.overwrite(snippetBlock.expression.end, start, '', { contentOnly: true }); @@ -64,55 +74,30 @@ export function handleSnippet( } else { str.overwrite(snippetBlock.expression.end, startEnd, '', { contentOnly: true }); } - transforms.push(') => {async () => {'); // inner async function for potential #await blocks + transforms.push(')' + afterParameters); transforms.push([startEnd, snippetBlock.end]); - component.addProp( - [[snippetBlock.expression.start, snippetBlock.expression.end]], + component.addImplicitSnippetProp( + [snippetBlock.expression.start, snippetBlock.expression.end], transforms ); } else { - let generic = ''; - if (snippetBlock.parameters?.length) { - generic = `<[${snippetBlock.parameters - .map((p) => { - let typeAnnotation = p.typeAnnotation; - if (!typeAnnotation && p.type === 'AssignmentPattern') { - typeAnnotation = p.left?.typeAnnotation; - if (!typeAnnotation) { - typeAnnotation = p.right?.typeAnnotation; - } - } - - // fall back to `any` to silence "implicit any" errors; JSDoc people can't add types to snippets - let type = 'any'; - if (typeAnnotation?.typeAnnotation) { - type = str.original.slice( - typeAnnotation.typeAnnotation.start, - typeAnnotation.typeAnnotation.end - ); - } - if (p.optional || p.type === 'AssignmentPattern') { - type += '?'; - } - return type; - }) - .join(', ')}]>`; - } - - const typeAnnotation = surroundWithIgnoreComments(`: import('svelte').Snippet${generic}`); const transforms: TransformationArray = [ - 'var ', + 'const ', [snippetBlock.expression.start, snippetBlock.expression.end], - typeAnnotation + ' = (' + IGNORE_POSITION_COMMENT, + ' = (' ]; - if (snippetBlock.parameters?.length) { - const start = snippetBlock.parameters[0].start; - const end = lastParameter.typeAnnotation?.end ?? lastParameter.end; - transforms.push([start, end]); + if (parameters) { + transforms.push(parameters); } - transforms.push(') => {async () => {'); // inner async function for potential #await blocks + transforms.push( + ')', + surroundWithIgnoreComments(`: ReturnType`), // shows up nicely preserved on hover, other alternatives don't + afterParameters + ); + transform(str, snippetBlock.start, startEnd, startEnd, transforms); } } @@ -162,3 +147,32 @@ export function handleImplicitChildren(componentNode: BaseNode, component: Inlin // it's enough to fake a children prop, we don't need to actually move the content inside (which would also reset control flow) component.addProp(['children'], ['() => { return __sveltets_2_any(0); }']); } + +export function hoistSnippetBlock(str: MagicString, blockOrEl: BaseNode) { + if (blockOrEl.type === 'InlineComponent') { + // implicit props, handled in InlineComponent + return; + } + + let targetPosition: number | undefined; + + for (const node of blockOrEl.children ?? []) { + if (node.type !== 'SnippetBlock') { + if (targetPosition === undefined && (node.type !== 'Text' || node.data.trim() !== '')) { + targetPosition = node.type === 'Text' ? node.end : node.start; + } + continue; + } + + // already first + if (targetPosition === undefined) { + continue; + } + + if (node.start === targetPosition) { + continue; + } + + str.move(node.start, node.end, targetPosition); + } +} diff --git a/packages/svelte2tsx/src/utils/ignore.ts b/packages/svelte2tsx/src/utils/ignore.ts index 81a370fc3..266a5324a 100644 --- a/packages/svelte2tsx/src/utils/ignore.ts +++ b/packages/svelte2tsx/src/utils/ignore.ts @@ -1,5 +1,7 @@ export const IGNORE_START_COMMENT = '/*Ωignore_startΩ*/'; export const IGNORE_END_COMMENT = '/*Ωignore_endΩ*/'; +/** to tell tooling to ignore the character at this position; can for example be used to ignore everything starting at this position */ +export const IGNORE_POSITION_COMMENT = '/*Ωignore_positionΩ*/'; /** * Surrounds given string with a start/end comment which marks it diff --git a/packages/svelte2tsx/svelte-shims-v4.d.ts b/packages/svelte2tsx/svelte-shims-v4.d.ts index 9ea027599..032c9b589 100644 --- a/packages/svelte2tsx/svelte-shims-v4.d.ts +++ b/packages/svelte2tsx/svelte-shims-v4.d.ts @@ -145,10 +145,6 @@ declare function __sveltets_2_cssProp(prop: Record): {}; // @ts-ignore Svelte v3/v4 don't have this declare function __sveltets_2_ensureSnippet(val: ReturnType | undefined | null): any; -// @ts-ignore Svelte v3/v4 don't have this -declare function __sveltets_2_snippet(): import('svelte').Snippet; -// @ts-ignore Svelte v3/v4 don't have this -declare function __sveltets_2_snippet(t: T): import('svelte').Snippet<[T]>; /** @internal PRIVATE API, DO NOT USE */ type __sveltets_2_SvelteAnimationReturnType = { diff --git a/packages/svelte2tsx/test/htmlx2jsx/samples/nested-snippet.v5/expectedv2.js b/packages/svelte2tsx/test/htmlx2jsx/samples/nested-snippet.v5/expectedv2.js new file mode 100644 index 000000000..1d25572a3 --- /dev/null +++ b/packages/svelte2tsx/test/htmlx2jsx/samples/nested-snippet.v5/expectedv2.js @@ -0,0 +1,36 @@ +if(true){ + const foo/*Ωignore_positionΩ*/ = ()/*Ωignore_startΩ*/: ReturnType/*Ωignore_endΩ*/ => { async ()/*Ωignore_positionΩ*/ => {};return __sveltets_2_any(0)};;__sveltets_2_ensureSnippet(foo()); + +} + + for(let item of __sveltets_2_ensureArray(arr)){ + const foo/*Ωignore_positionΩ*/ = ()/*Ωignore_startΩ*/: ReturnType/*Ωignore_endΩ*/ => { async ()/*Ωignore_positionΩ*/ => {};return __sveltets_2_any(0)};;__sveltets_2_ensureSnippet(foo()); + +} + +key; + const foo/*Ωignore_positionΩ*/ = ()/*Ωignore_startΩ*/: ReturnType/*Ωignore_endΩ*/ => { async ()/*Ωignore_positionΩ*/ => {};return __sveltets_2_any(0)};;__sveltets_2_ensureSnippet(foo()); + + + + const snippetBlock/*Ωignore_positionΩ*/ = ()/*Ωignore_startΩ*/: ReturnType/*Ωignore_endΩ*/ => { async ()/*Ωignore_positionΩ*/ => { + const foo/*Ωignore_positionΩ*/ = ()/*Ωignore_startΩ*/: ReturnType/*Ωignore_endΩ*/ => { async ()/*Ωignore_positionΩ*/ => {};return __sveltets_2_any(0)}; const foo2/*Ωignore_positionΩ*/ = ()/*Ωignore_startΩ*/: ReturnType/*Ωignore_endΩ*/ => { async ()/*Ωignore_positionΩ*/ => {};return __sveltets_2_any(0)};;__sveltets_2_ensureSnippet(foo()); + + +};return __sveltets_2_any(0)}; + + { const $$_value = await (Promise.resolve());{ const bar = $$_value; + const foo/*Ωignore_positionΩ*/ = ()/*Ωignore_startΩ*/: ReturnType/*Ωignore_endΩ*/ => { async ()/*Ωignore_positionΩ*/ => {};return __sveltets_2_any(0)};;__sveltets_2_ensureSnippet(foo()); + +}} + + + { svelteHTML.createElement("div", {}); + const foo/*Ωignore_positionΩ*/ = ()/*Ωignore_startΩ*/: ReturnType/*Ωignore_endΩ*/ => { async ()/*Ωignore_positionΩ*/ => {};return __sveltets_2_any(0)};;__sveltets_2_ensureSnippet(foo()); + + } + + { const $$_tnenopmoC0C = __sveltets_2_ensureComponent(Component); const $$_tnenopmoC0 = new $$_tnenopmoC0C({ target: __sveltets_2_any(), props: {children:() => { return __sveltets_2_any(0); },foo:() => { async ()/*Ωignore_positionΩ*/ => {};return __sveltets_2_any(0)},}});/*Ωignore_startΩ*/const {foo} = $$_tnenopmoC0.$$prop_def;/*Ωignore_endΩ*/ + ;__sveltets_2_ensureSnippet(foo()); + + Component} \ No newline at end of file diff --git a/packages/svelte2tsx/test/htmlx2jsx/samples/nested-snippet.v5/input.svelte b/packages/svelte2tsx/test/htmlx2jsx/samples/nested-snippet.v5/input.svelte new file mode 100644 index 000000000..219f003a5 --- /dev/null +++ b/packages/svelte2tsx/test/htmlx2jsx/samples/nested-snippet.v5/input.svelte @@ -0,0 +1,36 @@ +{#if true} + {@render foo()} + {#snippet foo()}{/snippet} +{/if} + +{#each arr as item} + {@render foo()} + {#snippet foo()}{/snippet} +{/each} + +{#key key} + {@render foo()} + {#snippet foo()}{/snippet} +{/key} + +{#snippet snippetBlock()} + {@render foo()} + {#snippet foo()}{/snippet} + {#snippet foo2()}{/snippet} +{/snippet} + +{#await Promise.resolve() then bar} + {@render foo()} + {#snippet foo()}{/snippet} +{/await} + + +
+ {@render foo()} + {#snippet foo()}{/snippet} +
+ + + {@render foo()} + {#snippet foo()}{/snippet} + \ No newline at end of file diff --git a/packages/svelte2tsx/test/htmlx2jsx/samples/snippet.v5/expectedv2.js b/packages/svelte2tsx/test/htmlx2jsx/samples/snippet.v5/expectedv2.js index 9a9e41d04..665aac36d 100644 --- a/packages/svelte2tsx/test/htmlx2jsx/samples/snippet.v5/expectedv2.js +++ b/packages/svelte2tsx/test/htmlx2jsx/samples/snippet.v5/expectedv2.js @@ -1,16 +1,16 @@ - var foo/*Ωignore_startΩ*/: import('svelte').Snippet<[any]>/*Ωignore_endΩ*/ = (x) => {async () => { + const foo/*Ωignore_positionΩ*/ = (x)/*Ωignore_startΩ*/: ReturnType/*Ωignore_endΩ*/ => { async ()/*Ωignore_positionΩ*/ => { { svelteHTML.createElement("div", {}); x; } };return __sveltets_2_any(0)}; - var bar/*Ωignore_startΩ*/: import('svelte').Snippet/*Ωignore_endΩ*/ = () => {async () => { + const bar/*Ωignore_positionΩ*/ = ()/*Ωignore_startΩ*/: ReturnType/*Ωignore_endΩ*/ => { async ()/*Ωignore_positionΩ*/ => { { svelteHTML.createElement("div", {}); } };return __sveltets_2_any(0)}; - var await_inside/*Ωignore_startΩ*/: import('svelte').Snippet/*Ωignore_endΩ*/ = () => {async () => { + const await_inside/*Ωignore_positionΩ*/ = ()/*Ωignore_startΩ*/: ReturnType/*Ωignore_endΩ*/ => { async ()/*Ωignore_positionΩ*/ => { { const $$_value = await (foo);{ const bar = $$_value; bar;}} };return __sveltets_2_any(0)}; - var defaultValue/*Ωignore_startΩ*/: import('svelte').Snippet<[any?]>/*Ωignore_endΩ*/ = (x = '') => {async () => { + const defaultValue/*Ωignore_positionΩ*/ = (x = '')/*Ωignore_startΩ*/: ReturnType/*Ωignore_endΩ*/ => { async ()/*Ωignore_positionΩ*/ => { { svelteHTML.createElement("div", {}); x; } };return __sveltets_2_any(0)}; @@ -18,19 +18,19 @@ ;__sveltets_2_ensureSnippet(bar()); ;__sveltets_2_ensureSnippet(await_inside()); - { const $$_tnenopmoC0C = __sveltets_2_ensureComponent(Component); new $$_tnenopmoC0C({ target: __sveltets_2_any(), props: {children:() => { return __sveltets_2_any(0); },bar:(x) => {async () => { + { const $$_tnenopmoC0C = __sveltets_2_ensureComponent(Component); const $$_tnenopmoC0 = new $$_tnenopmoC0C({ target: __sveltets_2_any(), props: {children:() => { return __sveltets_2_any(0); },bar:(x) => { async ()/*Ωignore_positionΩ*/ => { { svelteHTML.createElement("div", {}); x; } - };return __sveltets_2_any(0)},}}); + };return __sveltets_2_any(0)},}});/*Ωignore_startΩ*/const {bar} = $$_tnenopmoC0.$$prop_def;/*Ωignore_endΩ*/ { svelteHTML.createElement("div", {});asd; } Component} - { const $$_tsiL0C = __sveltets_2_ensureComponent(List); new $$_tsiL0C({ target: __sveltets_2_any(), props: { - "data":[1, 2, 3],row:(item) => {async () => { + { const $$_tsiL0C = __sveltets_2_ensureComponent(List); const $$_tsiL0 = new $$_tsiL0C({ target: __sveltets_2_any(), props: { + "data":[1, 2, 3],row:(item) => { async ()/*Ωignore_positionΩ*/ => { item; - };return __sveltets_2_any(0)},await_inside:() => {async () => { + };return __sveltets_2_any(0)},await_inside:() => { async ()/*Ωignore_positionΩ*/ => { { const $$_value = await (foo);{ const bar = $$_value; bar;}} - };return __sveltets_2_any(0)},}}); + };return __sveltets_2_any(0)},}});/*Ωignore_startΩ*/const {row, await_inside} = $$_tsiL0.$$prop_def;/*Ωignore_endΩ*/ List} @@ -38,4 +38,8 @@ List} -;__sveltets_2_ensureSnippet(children()); \ No newline at end of file +;__sveltets_2_ensureSnippet(children()); + + const jsDoc/*Ωignore_positionΩ*/ = (/**@type {number}*/a)/*Ωignore_startΩ*/: ReturnType/*Ωignore_endΩ*/ => { async ()/*Ωignore_positionΩ*/ => { + a; +};return __sveltets_2_any(0)}; \ No newline at end of file diff --git a/packages/svelte2tsx/test/htmlx2jsx/samples/snippet.v5/input.svelte b/packages/svelte2tsx/test/htmlx2jsx/samples/snippet.v5/input.svelte index 715538ca5..a9b1ea58c 100644 --- a/packages/svelte2tsx/test/htmlx2jsx/samples/snippet.v5/input.svelte +++ b/packages/svelte2tsx/test/htmlx2jsx/samples/snippet.v5/input.svelte @@ -39,3 +39,7 @@ {@render children()} + +{#snippet jsDoc(/**@type {number}*/a)} + {a} +{/snippet} diff --git a/packages/svelte2tsx/test/htmlx2jsx/samples/ts-in-template.v5/expectedv2.js b/packages/svelte2tsx/test/htmlx2jsx/samples/ts-in-template.v5/expectedv2.js index e6e47540d..be8b6454e 100644 --- a/packages/svelte2tsx/test/htmlx2jsx/samples/ts-in-template.v5/expectedv2.js +++ b/packages/svelte2tsx/test/htmlx2jsx/samples/ts-in-template.v5/expectedv2.js @@ -16,19 +16,19 @@ try { const $$_value = await (foo as Promise);{ const result: any = $$_val item as string; - var foo/*Ωignore_startΩ*/: import('svelte').Snippet<[string]>/*Ωignore_endΩ*/ = (bar: string) => {async () => { };return __sveltets_2_any(0)}; + const foo/*Ωignore_positionΩ*/ = (bar: string)/*Ωignore_startΩ*/: ReturnType/*Ωignore_endΩ*/ => { async ()/*Ωignore_positionΩ*/ => { };return __sveltets_2_any(0)}; - var foo2/*Ωignore_startΩ*/: import('svelte').Snippet<[string]>/*Ωignore_endΩ*/ = (bar : string) => {async () => { };return __sveltets_2_any(0)}; + const foo2/*Ωignore_positionΩ*/ = (bar : string)/*Ωignore_startΩ*/: ReturnType/*Ωignore_endΩ*/ => { async ()/*Ωignore_positionΩ*/ => { };return __sveltets_2_any(0)}; - var foo3/*Ωignore_startΩ*/: import('svelte').Snippet<[string | number]>/*Ωignore_endΩ*/ = (bar : string | number) => {async () => { };return __sveltets_2_any(0)}; + const foo3/*Ωignore_positionΩ*/ = (bar : string | number)/*Ωignore_startΩ*/: ReturnType/*Ωignore_endΩ*/ => { async ()/*Ωignore_positionΩ*/ => { };return __sveltets_2_any(0)}; - var foo4/*Ωignore_startΩ*/: import('svelte').Snippet<[string | number, (str: string)=>void]>/*Ωignore_endΩ*/ = (bar : string | number, baz : (str: string)=>void) => {async () => { };return __sveltets_2_any(0)}; + const foo4/*Ωignore_positionΩ*/ = (bar : string | number, baz : (str: string)=>void)/*Ωignore_startΩ*/: ReturnType/*Ωignore_endΩ*/ => { async ()/*Ωignore_positionΩ*/ => { };return __sveltets_2_any(0)}; - var foo5/*Ωignore_startΩ*/: import('svelte').Snippet<[{baz: string}]>/*Ωignore_endΩ*/ = (bar: {baz: string}) => {async () => { };return __sveltets_2_any(0)}; + const foo5/*Ωignore_positionΩ*/ = (bar: {baz: string})/*Ωignore_startΩ*/: ReturnType/*Ωignore_endΩ*/ => { async ()/*Ωignore_positionΩ*/ => { };return __sveltets_2_any(0)}; - var foo6/*Ωignore_startΩ*/: import('svelte').Snippet<[string?]>/*Ωignore_endΩ*/ = (bar?: string) => {async () => { };return __sveltets_2_any(0)}; + const foo6/*Ωignore_positionΩ*/ = (bar?: string)/*Ωignore_startΩ*/: ReturnType/*Ωignore_endΩ*/ => { async ()/*Ωignore_positionΩ*/ => { };return __sveltets_2_any(0)}; - var foo7/*Ωignore_startΩ*/: import('svelte').Snippet<[any, any?]>/*Ωignore_endΩ*/ = (bar, baz = '') => {async () => { };return __sveltets_2_any(0)}; + const foo7/*Ωignore_positionΩ*/ = (bar, baz = '')/*Ωignore_startΩ*/: ReturnType/*Ωignore_endΩ*/ => { async ()/*Ωignore_positionΩ*/ => { };return __sveltets_2_any(0)}; ;__sveltets_2_ensureSnippet(foo(bar as string)); diff --git a/packages/svelte2tsx/test/svelte2tsx/samples/snippet-instance-script.v5/expectedv2.ts b/packages/svelte2tsx/test/svelte2tsx/samples/snippet-instance-script.v5/expectedv2.ts index 43d1c7135..106c29183 100644 --- a/packages/svelte2tsx/test/svelte2tsx/samples/snippet-instance-script.v5/expectedv2.ts +++ b/packages/svelte2tsx/test/svelte2tsx/samples/snippet-instance-script.v5/expectedv2.ts @@ -1,6 +1,6 @@ /// ;function render() { - var bar/*Ωignore_startΩ*/: import('svelte').Snippet/*Ωignore_endΩ*/ = () => {async () => { foo; + const bar/*Ωignore_positionΩ*/ = ()/*Ωignore_startΩ*/: ReturnType/*Ωignore_endΩ*/ => { async ()/*Ωignore_positionΩ*/ => { foo; };return __sveltets_2_any(0)}; let foo = true; bar; @@ -8,7 +8,7 @@ async () => { }; -return { props: /** @type {Record} */ ({}), slots: {}, events: {} }} - -export default class Input__SvelteComponent_ extends __sveltets_2_createSvelte2TsxComponent(__sveltets_2_partial(__sveltets_2_with_any_event(render()))) { -} \ No newline at end of file +return { props: /** @type {Record} */ ({}), exports: {}, bindings: "", slots: {}, events: {} }} +const Input__SvelteComponent_ = __sveltets_2_isomorphic_component(__sveltets_2_partial(__sveltets_2_with_any_event(render()))); +/*Ωignore_startΩ*/type Input__SvelteComponent_ = InstanceType; +/*Ωignore_endΩ*/export default Input__SvelteComponent_; \ No newline at end of file