11import { promises as fs } from 'node:fs'
2- import { join , relative } from 'node:path'
2+ import { basename , join , relative } from 'node:path'
3+ import { parse as parseSFC } from '@vue/compiler-sfc'
34import { Project } from 'ts-morph'
4- import { parse as parseSFC } from 'vue/compiler-sfc'
55
66interface FileRec { type : string , path : string , target ?: string , content : string }
77
@@ -128,7 +128,7 @@ function analyzeDependencies(
128128 return { dependencies, devDependencies, registryDependencies }
129129}
130130
131- async function walkVueFiles ( dir : string ) : Promise < string [ ] > {
131+ async function walkComponentFiles ( dir : string , rootDir : string ) : Promise < string [ ] > {
132132 const out : string [ ] = [ ]
133133 let entries : any [ ] = [ ]
134134 try {
@@ -140,15 +140,21 @@ async function walkVueFiles(dir: string): Promise<string[]> {
140140 for ( const entry of entries ) {
141141 const full = join ( dir , entry . name )
142142 if ( entry . isDirectory ( ) ) {
143- const nested = await walkVueFiles ( full )
143+ const nested = await walkComponentFiles ( full , rootDir )
144144 out . push ( ...nested )
145145 }
146- else if ( entry . isFile ( ) && entry . name . endsWith ( '.vue' ) ) {
147- out . push ( full )
148- }
149- else if ( entry . isFile ( ) && entry . name === 'index.ts' && ! full . endsWith ( '/src/index.ts' ) ) {
150- // Only include index.ts files that are not the root src/index.ts
151- out . push ( full )
146+ else if ( entry . isFile ( ) ) {
147+ // Include all .vue files
148+ if ( entry . name . endsWith ( '.vue' ) ) {
149+ out . push ( full )
150+ }
151+ // Include all .ts files except the root src/index.ts
152+ else if ( entry . name . endsWith ( '.ts' ) ) {
153+ const isRootIndex = full === join ( rootDir , 'index.ts' )
154+ if ( ! isRootIndex ) {
155+ out . push ( full )
156+ }
157+ }
152158 }
153159 }
154160 return out
@@ -185,9 +191,9 @@ export async function generateRegistryAssets(ctx: { rootDir: string }) {
185191 const allowedDeps = new Set ( Object . keys ( allDeps || { } ) . filter ( ( d : string ) => ! [ 'vue' , '@repo/shadcn-vue' , ...Array . from ( internalDeps ) ] . includes ( d ) ) )
186192 const allowedDevDeps = new Set ( Object . keys ( allDevDeps || { } ) . filter ( ( d : string ) => ! [ 'typescript' ] . includes ( d ) ) )
187193
188- const vueFiles = await walkVueFiles ( srcDir )
194+ const componentFiles = await walkComponentFiles ( srcDir , srcDir )
189195 const files : FileRec [ ] = [ ]
190- for ( const abs of vueFiles ) {
196+ for ( const abs of componentFiles ) {
191197 const raw = await fs . readFile ( abs , 'utf-8' )
192198 const parsed = raw
193199 . replace ( / @ r e p o \/ s h a d c n - v u e \/ / g, '@/' )
@@ -204,7 +210,7 @@ export async function generateRegistryAssets(ctx: { rootDir: string }) {
204210 for ( const abs of candidates ) {
205211 const raw = await fs . readFile ( abs , 'utf-8' )
206212 const parsed = raw . replace ( / @ r e p o \/ e l e m e n t s \/ / g, '@/components/ai-elements/' )
207- const name = abs . split ( '/' ) . pop ( ) as string
213+ const name = basename ( abs )
208214 exampleFiles . push ( { type : 'registry:block' , path : `components/ai-elements/examples/${ name } ` , target : '' , content : parsed } )
209215 }
210216 }
@@ -229,7 +235,8 @@ export async function generateRegistryAssets(ctx: { rootDir: string }) {
229235 } ) )
230236
231237 const exampleItems = exampleFiles . map ( ( ef ) => {
232- const name = ( ef . path . split ( '/' ) . pop ( ) as string ) . replace ( '.vue' , '' )
238+ const fileName = basename ( ef . path )
239+ const name = fileName . replace ( '.vue' , '' )
233240 return {
234241 name : `example-${ name } ` ,
235242 type : 'registry:block' ,
@@ -257,15 +264,26 @@ export async function generateRegistryAssets(ctx: { rootDir: string }) {
257264 const groupRegistryDeps = new Set < string > ( )
258265
259266 for ( const f of groupFiles ) {
260- const { descriptor } = parseSFC ( f . content )
261- const code = [ descriptor . script ?. content || '' , descriptor . scriptSetup ?. content || '' ] . join ( '\n' )
262- const imports = parseImportsFromCode ( code )
263- const analysis = analyzeDependencies ( imports , allowedDeps , allowedDevDeps )
264-
265- // Merge results
266- analysis . dependencies . forEach ( dep => groupDeps . add ( dep ) )
267- analysis . devDependencies . forEach ( dep => groupDevDeps . add ( dep ) )
268- analysis . registryDependencies . forEach ( dep => groupRegistryDeps . add ( dep ) )
267+ let code = ''
268+ // Handle Vue SFC files
269+ if ( f . path . endsWith ( '.vue' ) ) {
270+ const { descriptor } = parseSFC ( f . content )
271+ code = [ descriptor . script ?. content || '' , descriptor . scriptSetup ?. content || '' ] . join ( '\n' )
272+ }
273+ // Handle TypeScript files
274+ else if ( f . path . endsWith ( '.ts' ) ) {
275+ code = f . content
276+ }
277+
278+ if ( code ) {
279+ const imports = parseImportsFromCode ( code )
280+ const analysis = analyzeDependencies ( imports , allowedDeps , allowedDevDeps )
281+
282+ // Merge results
283+ analysis . dependencies . forEach ( dep => groupDeps . add ( dep ) )
284+ analysis . devDependencies . forEach ( dep => groupDevDeps . add ( dep ) )
285+ analysis . registryDependencies . forEach ( dep => groupRegistryDeps . add ( dep ) )
286+ }
269287 }
270288
271289 const itemJson = {
@@ -290,7 +308,8 @@ export async function generateRegistryAssets(ctx: { rootDir: string }) {
290308 }
291309
292310 for ( const ef of exampleFiles ) {
293- const name = ( ef . path . split ( '/' ) . pop ( ) as string ) . replace ( '.vue' , '' )
311+ const fileName = basename ( ef . path )
312+ const name = fileName . replace ( '.vue' , '' )
294313
295314 // Analyze dependencies for example files
296315 const { descriptor } = parseSFC ( ef . content )
0 commit comments