1
1
/** @import { VariableDeclarator, Node, Identifier, AssignmentExpression, LabeledStatement, ExpressionStatement } from 'estree' */
2
- /** @import { Visitors } from 'zimmerframe' */
2
+ /** @import { Visitors, Context } from 'zimmerframe' */
3
3
/** @import { ComponentAnalysis } from '../phases/types.js' */
4
4
/** @import { Scope, ScopeRoot } from '../phases/scope.js' */
5
5
/** @import { AST, Binding, SvelteNode, ValidatedCompileOptions } from '#compiler' */
@@ -323,10 +323,11 @@ export function migrate(source, { filename } = {}) {
323
323
* derived_components: Map<string, string>;
324
324
* derived_labeled_statements: Set<LabeledStatement>;
325
325
* has_svelte_self: boolean;
326
+ * migrate_prop_component_type?: boolean;
326
327
* }} State
327
328
*/
328
329
329
- /** @type {Visitors<SvelteNode, State> } */
330
+ /** @type {Visitors<SvelteNode | { type: "TSTypeReference", typeName: Identifier, start: number, end: number } , State> } */
330
331
const instance_script = {
331
332
_ ( node , { state, next } ) {
332
333
// @ts -expect-error
@@ -343,8 +344,37 @@ const instance_script = {
343
344
}
344
345
next ( ) ;
345
346
} ,
346
- Identifier ( node , { state, path } ) {
347
+ TSTypeReference ( node , { state, path } ) {
348
+ // we don't want to overwrite in case it's an exported prop because
349
+ // we already take care of that in extract_type_and_comment
350
+ if (
351
+ path [ 1 ] &&
352
+ path [ 1 ] . type === 'ExportNamedDeclaration' &&
353
+ path [ 1 ] . declaration ?. type === 'VariableDeclaration' &&
354
+ path [ 1 ] . declaration ?. kind === 'let' &&
355
+ ! state . migrate_prop_component_type
356
+ )
357
+ return ;
358
+ if ( state . analysis . runes ) return ;
359
+ if ( node . typeName . type === 'Identifier' ) {
360
+ const binding = state . scope . get ( node . typeName . name ) ;
361
+ if (
362
+ binding &&
363
+ binding . declaration_kind === 'import' &&
364
+ binding . initial ?. type === 'ImportDeclaration' &&
365
+ binding . initial . source . value ?. toString ( ) . endsWith ( '.svelte' )
366
+ ) {
367
+ state . str . overwrite (
368
+ node . start ,
369
+ node . end ,
370
+ `ReturnType<typeof ${ state . str . original . substring ( node . start , node . end ) } >`
371
+ ) ;
372
+ }
373
+ }
374
+ } ,
375
+ Identifier ( node , { state, path, next } ) {
347
376
handle_identifier ( node , state , path ) ;
377
+ next ( ) ;
348
378
} ,
349
379
ImportDeclaration ( node , { state } ) {
350
380
state . props_insertion_point = node . end ?? state . props_insertion_point ;
@@ -370,7 +400,8 @@ const instance_script = {
370
400
state . str . remove ( /** @type {number } */ ( node . start ) , /** @type {number } */ ( node . end ) ) ;
371
401
}
372
402
} ,
373
- VariableDeclaration ( node , { state, path, visit } ) {
403
+ VariableDeclaration ( node , context ) {
404
+ const { state, path, visit, next } = context ;
374
405
if ( state . scope !== state . analysis . instance . scope ) {
375
406
return ;
376
407
}
@@ -465,7 +496,7 @@ const instance_script = {
465
496
: '' ,
466
497
optional : ! ! declarator . init ,
467
498
bindable : binding . updated ,
468
- ...extract_type_and_comment ( declarator , state . str , path )
499
+ ...extract_type_and_comment ( declarator , state . str , context )
469
500
} ) ;
470
501
}
471
502
@@ -653,6 +684,7 @@ const instance_script = {
653
684
while ( state . str . original [ end ] !== '\n' ) end ++ ;
654
685
state . str . update ( start , end , '' ) ;
655
686
}
687
+ next ( ) ;
656
688
} ,
657
689
BreakStatement ( node , { state, path } ) {
658
690
if ( path [ 1 ] . type !== 'LabeledStatement' ) return ;
@@ -1144,9 +1176,10 @@ function migrate_slot_usage(node, path, state) {
1144
1176
/**
1145
1177
* @param {VariableDeclarator } declarator
1146
1178
* @param {MagicString } str
1147
- * @param {SvelteNode[] } path
1179
+ * @param {Context< SvelteNode | { type: "TSTypeReference", typeName: Identifier, start: number, end: number }, State> } context
1148
1180
*/
1149
- function extract_type_and_comment ( declarator , str , path ) {
1181
+ function extract_type_and_comment ( declarator , str , context ) {
1182
+ const path = context . path ;
1150
1183
const parent = path . at ( - 1 ) ;
1151
1184
1152
1185
// Try to find jsdoc above the declaration
@@ -1166,7 +1199,14 @@ function extract_type_and_comment(declarator, str, path) {
1166
1199
while ( str . original [ start ] === ' ' ) {
1167
1200
start ++ ;
1168
1201
}
1169
- return { type : str . original . substring ( start , declarator . id . typeAnnotation . end ) , comment } ;
1202
+ context . visit ( declarator . id . typeAnnotation , {
1203
+ ...context . state ,
1204
+ migrate_prop_component_type : true
1205
+ } ) ;
1206
+ return {
1207
+ type : str . snip ( start , declarator . id . typeAnnotation . end ) . toString ( ) ,
1208
+ comment
1209
+ } ;
1170
1210
}
1171
1211
1172
1212
// try to find a comment with a type annotation, hinting at jsdoc
0 commit comments