@@ -10,7 +10,7 @@ import { regex_valid_component_name } from '../phases/1-parse/state/element.js';
1010import { analyze_component } from '../phases/2-analyze/index.js' ;
1111import { get_rune } from '../phases/scope.js' ;
1212import { reset , reset_warning_filter } from '../state.js' ;
13- import { extract_identifiers , extract_all_identifiers_from_expression } from '../utils/ast.js' ;
13+ import { extract_all_identifiers_from_expression , extract_identifiers } from '../utils/ast.js' ;
1414import { migrate_svelte_ignore } from '../utils/extract_svelte_ignore.js' ;
1515import { validate_component_options } from '../validate-options.js' ;
1616import { is_svg , is_void } from '../../utils.js' ;
@@ -23,9 +23,10 @@ const style_placeholder = '/*$$__STYLE_CONTENT__$$*/';
2323 * May throw an error if the code is too complex to migrate automatically.
2424 *
2525 * @param {string } source
26+ * @param {string } [filename]
2627 * @returns {{ code: string; } }
2728 */
28- export function migrate ( source ) {
29+ export function migrate ( source , filename ) {
2930 try {
3031 // Blank CSS, could contain SCSS or similar that needs a preprocessor.
3132 // Since we don't care about CSS in this migration, we'll just ignore it.
@@ -37,7 +38,7 @@ export function migrate(source) {
3738 } ) ;
3839
3940 reset_warning_filter ( ( ) => false ) ;
40- reset ( source , { filename : 'migrate.svelte' } ) ;
41+ reset ( source , { filename : filename ?? 'migrate.svelte' } ) ;
4142
4243 let parsed = parse ( source ) ;
4344
@@ -64,6 +65,7 @@ export function migrate(source) {
6465 let state = {
6566 scope : analysis . instance . scope ,
6667 analysis,
68+ filename,
6769 str,
6870 indent,
6971 props : [ ] ,
@@ -86,12 +88,14 @@ export function migrate(source) {
8688 createBubbler : analysis . root . unique ( 'createBubbler' ) . name ,
8789 bubble : analysis . root . unique ( 'bubble' ) . name ,
8890 passive : analysis . root . unique ( 'passive' ) . name ,
89- nonpassive : analysis . root . unique ( 'nonpassive' ) . name
91+ nonpassive : analysis . root . unique ( 'nonpassive' ) . name ,
92+ svelte_self : analysis . root . unique ( 'SvelteSelf' ) . name
9093 } ,
9194 legacy_imports : new Set ( ) ,
9295 script_insertions : new Set ( ) ,
9396 derived_components : new Map ( ) ,
94- derived_labeled_statements : new Set ( )
97+ derived_labeled_statements : new Set ( ) ,
98+ has_svelte_self : false
9599 } ;
96100
97101 if ( parsed . module ) {
@@ -118,12 +122,21 @@ export function migrate(source) {
118122 state . script_insertions . size > 0 ||
119123 state . props . length > 0 ||
120124 analysis . uses_rest_props ||
121- analysis . uses_props ;
125+ analysis . uses_props ||
126+ state . has_svelte_self ;
122127
123128 if ( ! parsed . instance && need_script ) {
124129 str . appendRight ( 0 , '<script>' ) ;
125130 }
126131
132+ if ( state . has_svelte_self && filename ) {
133+ const file = filename . split ( '/' ) . pop ( ) ;
134+ str . appendRight (
135+ insertion_point ,
136+ `\n${ indent } import ${ state . names . svelte_self } from './${ file } ';`
137+ ) ;
138+ }
139+
127140 const specifiers = [ ...state . legacy_imports ] . map ( ( imported ) => {
128141 const local = state . names [ imported ] ;
129142 return imported === local ? imported : `${ imported } as ${ local } ` ;
@@ -294,6 +307,7 @@ export function migrate(source) {
294307 * scope: Scope;
295308 * str: MagicString;
296309 * analysis: ComponentAnalysis;
310+ * filename?: string;
297311 * indent: string;
298312 * props: Array<{ local: string; exported: string; init: string; bindable: boolean; slot_name?: string; optional: boolean; type: string; comment?: string; type_only?: boolean; needs_refine_type?: boolean; }>;
299313 * props_insertion_point: number;
@@ -302,8 +316,9 @@ export function migrate(source) {
302316 * names: Record<string, string>;
303317 * legacy_imports: Set<string>;
304318 * script_insertions: Set<string>;
305- * derived_components: Map<string, string>,
306- * derived_labeled_statements: Set<LabeledStatement>
319+ * derived_components: Map<string, string>;
320+ * derived_labeled_statements: Set<LabeledStatement>;
321+ * has_svelte_self: boolean;
307322 * }} State
308323 */
309324
@@ -724,6 +739,32 @@ const template = {
724739 }
725740 next ( ) ;
726741 } ,
742+ SvelteSelf ( node , { state, next } ) {
743+ if ( ! state . filename ) {
744+ const indent = guess_indent ( state . str . original . substring ( node . start , node . end ) ) ;
745+ state . str . prependRight (
746+ node . start ,
747+ `<!-- @migration-task: migrate this by hand or call the migrate function with the filename of this file -->\n${ indent } `
748+ ) ;
749+ return ;
750+ }
751+ let end = node . end - 1 ;
752+ if ( node . fragment . nodes . length > 0 ) {
753+ end = node . fragment . nodes [ 0 ] . start ;
754+ }
755+ if ( node . attributes . length > 0 ) {
756+ end = node . attributes [ 0 ] . start ;
757+ }
758+ state . str . overwrite ( node . start + 1 , end - 1 , `${ state . names . svelte_self } ` ) ;
759+ if ( node . fragment . nodes . length > 0 ) {
760+ const start_closing =
761+ state . str . original . indexOf ( '<' , node . fragment . nodes [ node . fragment . nodes . length - 1 ] . end ) +
762+ 2 ;
763+ state . str . overwrite ( start_closing , node . end - 1 , `${ state . names . svelte_self } ` ) ;
764+ }
765+ state . has_svelte_self = true ;
766+ next ( ) ;
767+ } ,
727768 SvelteElement ( node , { state, next } ) {
728769 if ( node . tag . type === 'Literal' ) {
729770 let is_static = true ;
0 commit comments