@@ -228,6 +228,24 @@ async function checkMigrationNeeded(rootDir: string): Promise<MigrationCheck> {
228228 return result
229229}
230230
231+ // Convert Vue template attrs like `title="Hello" :width="1200"` to a JS object string
232+ function attrsToProps ( attrs : string ) : string {
233+ if ( ! attrs )
234+ return ''
235+ const props : string [ ] = [ ]
236+ // Match :prop="expr" or prop="value" or prop (boolean)
237+ const attrRegex = / : ( \w + ) = " ( [ ^ " ] * ) " | ( \w + ) = " ( [ ^ " ] * ) " | ( \w + ) / g
238+ for ( const m of attrs . matchAll ( attrRegex ) ) {
239+ if ( m [ 1 ] ) // dynamic :prop="expr"
240+ props . push ( `${ m [ 1 ] } : ${ m [ 2 ] } ` )
241+ else if ( m [ 3 ] ) // static prop="value"
242+ props . push ( `${ m [ 3 ] } : '${ m [ 4 ] } '` )
243+ else if ( m [ 5 ] ) // boolean prop
244+ props . push ( `${ m [ 5 ] } : true` )
245+ }
246+ return props . length ? `{ ${ props . join ( ', ' ) } }` : ''
247+ }
248+
231249// Migrate defineOgImage API
232250function migrateDefineOgImageApi ( dryRun : boolean ) : { changes: Array < { file : string , count : number } > } {
233251 const cwd = process . cwd ( )
@@ -241,6 +259,42 @@ function migrateDefineOgImageApi(dryRun: boolean): { changes: Array<{ file: stri
241259 let modified = false
242260 let changeCount = 0
243261
262+ // Pattern 0: <OgImageScreenshot /> and <OgImage /> component usage → composable
263+ // Handles self-closing and open/close tags, with or without props
264+ content = content . replace ( / < O g I m a g e S c r e e n s h o t ( [ ^ > ] * ?) \/ > / g, ( _match , attrs : string ) => {
265+ modified = true
266+ changeCount ++
267+ const propsStr = attrsToProps ( attrs . trim ( ) )
268+ return propsStr
269+ ? `<!-- Migrated: use defineOgImageScreenshot(${ propsStr } ) in <script setup> -->`
270+ : `<!-- Migrated: use defineOgImageScreenshot() in <script setup> -->`
271+ } )
272+ content = content . replace ( / < O g I m a g e S c r e e n s h o t ( [ ^ > ] * ) > [ \s \S ] * ?< \/ O g I m a g e S c r e e n s h o t > / g, ( _match , attrs : string ) => {
273+ modified = true
274+ changeCount ++
275+ const propsStr = attrsToProps ( attrs . trim ( ) )
276+ return propsStr
277+ ? `<!-- Migrated: use defineOgImageScreenshot(${ propsStr } ) in <script setup> -->`
278+ : `<!-- Migrated: use defineOgImageScreenshot() in <script setup> -->`
279+ } )
280+ // OgImage but not OgImageScreenshot (use word boundary via negative lookahead)
281+ content = content . replace ( / < O g I m a g e (? ! S c r e e n s h o t ) ( [ ^ > ] * ?) \/ > / g, ( _match , attrs : string ) => {
282+ modified = true
283+ changeCount ++
284+ const propsStr = attrsToProps ( attrs . trim ( ) )
285+ return propsStr
286+ ? `<!-- Migrated: use defineOgImage(${ propsStr } ) in <script setup> -->`
287+ : `<!-- Migrated: use defineOgImage() in <script setup> -->`
288+ } )
289+ content = content . replace ( / < O g I m a g e (? ! S c r e e n s h o t ) ( [ ^ > ] * ) > [ \s \S ] * ?< \/ O g I m a g e > / g, ( _match , attrs : string ) => {
290+ modified = true
291+ changeCount ++
292+ const propsStr = attrsToProps ( attrs . trim ( ) )
293+ return propsStr
294+ ? `<!-- Migrated: use defineOgImage(${ propsStr } ) in <script setup> -->`
295+ : `<!-- Migrated: use defineOgImage() in <script setup> -->`
296+ } )
297+
244298 // Pattern 1: defineOgImageComponent → defineOgImage
245299 if ( / d e f i n e O g I m a g e C o m p o n e n t \s * \( / . test ( content ) ) {
246300 content = content . replace ( / d e f i n e O g I m a g e C o m p o n e n t \s * \( / g, 'defineOgImage(' )
@@ -430,6 +484,7 @@ async function runMigrate(args: string[]): Promise<void> {
430484 if ( migrationCheck . needsNuxtFonts ) {
431485 tasks . push ( 'Install @nuxt/fonts module' )
432486 }
487+ tasks . push ( 'Migrate <OgImage> and <OgImageScreenshot> components to composables' )
433488 tasks . push ( 'Update defineOgImage() calls to new API' )
434489
435490 p . note ( tasks . map ( t => `• ${ t } ` ) . join ( '\n' ) , 'Migration tasks' )
0 commit comments