Skip to content

Commit 7db0fe6

Browse files
authored
(fix) kit auto type fixes (#1936)
- recognize export const snapshot - add types at correct position when initializer given - recognize +page/layout@ files - recognize const fn even if it has needless parenthesis around it
1 parent 6ff486a commit 7db0fe6

File tree

7 files changed

+67
-19
lines changed

7 files changed

+67
-19
lines changed

packages/svelte2tsx/index.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ export const internalHelpers: {
115115
fileName: string,
116116
options: InternalHelpers.KitFilesSettings
117117
) => boolean;
118-
isKitRouteFile: (fileName: string, basename: string) =>boolean,
118+
isKitRouteFile: (basename: string) => boolean,
119119
isClientHooksFile: (
120120
fileName: string,
121121
basename: string,

packages/svelte2tsx/src/helpers/sveltekit.ts

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ const kitPageFiles = new Set(['+page', '+layout', '+page.server', '+layout.serve
2626
export function isKitFile(fileName: string, options: KitFilesSettings): boolean {
2727
const basename = path.basename(fileName);
2828
return (
29-
isKitRouteFile(fileName, basename) ||
29+
isKitRouteFile(basename) ||
3030
isServerHooksFile(fileName, basename, options.serverHooksPath) ||
3131
isClientHooksFile(fileName, basename, options.clientHooksPath) ||
3232
isParamsFile(fileName, basename, options.paramsPath)
@@ -36,12 +36,12 @@ export function isKitFile(fileName: string, options: KitFilesSettings): boolean
3636
/**
3737
* Determines whether or not a given file is a SvelteKit-specific route file
3838
*/
39-
export function isKitRouteFile(fileName: string, basename: string): boolean {
39+
export function isKitRouteFile(basename: string): boolean {
4040
if (basename.includes('@')) {
4141
// +page@foo -> +page
4242
basename = basename.split('@')[0];
4343
} else {
44-
basename = basename.slice(0, -path.extname(fileName).length);
44+
basename = basename.slice(0, -path.extname(basename).length);
4545
}
4646

4747
return kitPageFiles.has(basename);
@@ -97,7 +97,7 @@ export function upsertKitFile(
9797
): { text: string; addedCode: AddedCode[] } {
9898
let basename = path.basename(fileName);
9999
const result =
100-
upserKitRouteFile(ts, fileName, basename, getSource, surround) ??
100+
upserKitRouteFile(ts, basename, getSource, surround) ??
101101
upserKitServerHooksFile(
102102
ts,
103103
fileName,
@@ -141,12 +141,11 @@ export function upsertKitFile(
141141

142142
function upserKitRouteFile(
143143
ts: _ts,
144-
fileName: string,
145144
basename: string,
146145
getSource: () => ts.SourceFile | undefined,
147146
surround: (text: string) => string
148147
) {
149-
if (!isKitRouteFile(fileName, basename)) return;
148+
if (!isKitRouteFile(basename)) return;
150149

151150
const source = getSource();
152151
if (!source) return;

packages/svelte2tsx/src/helpers/typescript.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,18 @@ export function findExports(ts: _ts, source: ts.SourceFile, isTsFile: boolean) {
5252
(ts.isSatisfiesExpression(declaration.initializer) &&
5353
ts.isParenthesizedExpression(declaration.initializer.expression) &&
5454
(ts.isFunctionExpression(declaration.initializer.expression.expression) ||
55-
ts.isArrowFunction(declaration.initializer.expression.expression))))
55+
ts.isArrowFunction(declaration.initializer.expression.expression))) ||
56+
(ts.isParenthesizedExpression(declaration.initializer) &&
57+
(ts.isFunctionExpression(declaration.initializer.expression) ||
58+
ts.isArrowFunction(declaration.initializer.expression))))
5659
) {
5760
const node = ts.isSatisfiesExpression(declaration.initializer)
5861
? ((declaration.initializer.expression as ts.ParenthesizedExpression)
5962
.expression as ts.FunctionExpression | ts.ArrowFunction)
63+
: ts.isParenthesizedExpression(declaration.initializer)
64+
? (declaration.initializer.expression as
65+
| ts.FunctionExpression
66+
| ts.ArrowFunction)
6067
: declaration.initializer;
6168
exports.set(declaration.name.getText(), {
6269
type: 'function',

packages/svelte2tsx/src/svelte2tsx/nodes/ExportedNames.ts

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import MagicString from 'magic-string';
22
import ts from 'typescript';
3+
import { internalHelpers } from '../../helpers';
34
import { surroundWithIgnoreComments } from '../../utils/ignore';
45
import { preprendStr, overwriteStr } from '../../utils/magic-string';
56
import { findExportKeyword, getLastLeadingDoc, isInterfaceOrTypeDeclaration } from '../utils/tsAst';
@@ -18,8 +19,6 @@ interface ExportedName {
1819
doc?: string;
1920
}
2021

21-
const kitPageFiles = new Set(['+page.svelte', '+layout.svelte']);
22-
2322
export class ExportedNames {
2423
/**
2524
* Uses the $$Props type
@@ -52,6 +51,17 @@ export class ExportedNames {
5251
node.declarationList.forEachChild((n) => {
5352
if (ts.isVariableDeclaration(n) && ts.isIdentifier(n.name)) {
5453
this.addGetter(n.name);
54+
55+
const type = n.type || ts.getJSDocType(n);
56+
const isKitExport =
57+
internalHelpers.isKitRouteFile(this.basename) &&
58+
n.name.getText() === 'snapshot';
59+
// TS types are not allowed in JS files, but TS will still pick it up and the ignore comment will filter out the error
60+
const kitType = isKitExport && !type ? `: import('./$types').Snapshot` : '';
61+
const nameEnd = n.name.end + this.astOffset;
62+
if (kitType) {
63+
preprendStr(this.str, nameEnd, surroundWithIgnoreComments(kitType));
64+
}
5565
}
5666
});
5767
}
@@ -117,7 +127,7 @@ export class ExportedNames {
117127
const type = tsType || jsDocType;
118128
const name = identifier.getText();
119129
const isKitExport =
120-
kitPageFiles.has(this.basename) &&
130+
internalHelpers.isKitRouteFile(this.basename) &&
121131
(name === 'data' || name === 'form' || name === 'snapshot');
122132
// TS types are not allowed in JS files, but TS will still pick it up and the ignore comment will filter out the error
123133
const kitType =
@@ -132,6 +142,7 @@ export class ExportedNames {
132142
: 'Snapshot'
133143
}`
134144
: '';
145+
const nameEnd = identifier.end + this.astOffset;
135146
const end = declaration.end + this.astOffset;
136147

137148
if (
@@ -150,13 +161,26 @@ export class ExportedNames {
150161
) {
151162
const name = identifier.getText();
152163

153-
preprendStr(
154-
this.str,
155-
end,
156-
surroundWithIgnoreComments(`${kitType};${name} = __sveltets_2_any(${name});`)
157-
);
164+
if (nameEnd === end) {
165+
preprendStr(
166+
this.str,
167+
end,
168+
surroundWithIgnoreComments(
169+
`${kitType};${name} = __sveltets_2_any(${name});`
170+
)
171+
);
172+
} else {
173+
if (kitType) {
174+
preprendStr(this.str, nameEnd, surroundWithIgnoreComments(kitType));
175+
}
176+
preprendStr(
177+
this.str,
178+
end,
179+
surroundWithIgnoreComments(`;${name} = __sveltets_2_any(${name});`)
180+
);
181+
}
158182
} else if (kitType) {
159-
preprendStr(this.str, end, surroundWithIgnoreComments(`${kitType}`));
183+
preprendStr(this.str, nameEnd, surroundWithIgnoreComments(kitType));
160184
}
161185
};
162186

packages/svelte2tsx/test/helpers/index.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,4 +41,20 @@ describe('Internal Helpers - upsertKitFile', () => {
4141
`export async function GET(e: import('./$types').RequestEvent) : Response | Promise<Response> {}`
4242
);
4343
});
44+
45+
it('upserts load const with paranthesis', () => {
46+
upsert(
47+
'+page.ts',
48+
`export const load = (async (e) => {});`,
49+
`export const load = (async (e: import('./$types').PageLoadEvent) => {});`
50+
);
51+
});
52+
53+
it('recognizes page@', () => {
54+
upsert('[email protected]', `export const ssr = true;`, `export const ssr : boolean = true;`);
55+
});
56+
57+
it('recognizes layout@foo', () => {
58+
upsert('[email protected]', `export const ssr = true;`, `export const ssr : boolean = true;`);
59+
});
4460
});

packages/svelte2tsx/test/svelte2tsx/samples/sveltekit-autotypes/+page.svelte

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,6 @@
44
export const snapshot = {};
55
66
export let nope;
7+
export let form = {}
78
export let data: number;
89
</script>

packages/svelte2tsx/test/svelte2tsx/samples/sveltekit-autotypes/expectedv2.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,15 @@
33

44
let data/*Ωignore_startΩ*/: import('./$types').PageData;data = __sveltets_2_any(data);/*Ωignore_endΩ*/;
55
let form/*Ωignore_startΩ*/: import('./$types').ActionData;form = __sveltets_2_any(form);/*Ωignore_endΩ*/;
6-
const snapshot = {};
6+
const snapshot/*Ωignore_startΩ*/: import('./$types').Snapshot/*Ωignore_endΩ*/ = {};
77

88
let nope/*Ωignore_startΩ*/;nope = __sveltets_2_any(nope);/*Ωignore_endΩ*/;
9+
let form/*Ωignore_startΩ*/: import('./$types').ActionData/*Ωignore_endΩ*/ = {}
910
let data: number/*Ωignore_startΩ*/;data = __sveltets_2_any(data);/*Ωignore_endΩ*/;
1011
;
1112
async () => {};
1213
return { props: {data: data , form: form , snapshot: snapshot , nope: nope}, slots: {}, events: {} }}
1314

14-
export default class Page__SvelteComponent_ extends __sveltets_2_createSvelte2TsxComponent(__sveltets_2_partial(['snapshot'], __sveltets_2_with_any_event(render()))) {
15+
export default class Page__SvelteComponent_ extends __sveltets_2_createSvelte2TsxComponent(__sveltets_2_partial(['form','snapshot'], __sveltets_2_with_any_event(render()))) {
1516
get snapshot() { return __sveltets_2_nonNullable(this.$$prop_def.snapshot) }
1617
}

0 commit comments

Comments
 (0)