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