11import fs from 'fs' ;
22import path from 'path' ;
3+ import read from 'fs-readdir-recursive' ;
34import { IReadFiles } from "./types/index.interface" ;
45import { MergeStrategy } from "./types/index.interface" ;
56import { v4 as uuidv4 } from "uuid" ;
@@ -242,10 +243,9 @@ export function countComponentTypes(component: any, result: Record<string, numbe
242243 if ( ! component || typeof component !== "object" ) return result ;
243244
244245 // Check for ':type' at current level
245- const typeField = component [ ":type" ] ?. value ;
246- if ( typeField ) {
247- result [ typeField ] = ( result [ typeField ] || 0 ) + 1 ;
248- }
246+ const t = component [ ":type" ] ;
247+ const typeField = typeof t === "string" ? t : t ?. value ;
248+ if ( typeField ) result [ typeField ] = ( result [ typeField ] || 0 ) + 1 ;
249249
250250 // Recursively check nested properties
251251 for ( const key in component ) {
@@ -333,4 +333,78 @@ export function ensureField(
333333 if ( ! found ) {
334334 mainSchema . unshift ( fieldConfig ) ;
335335 }
336+ }
337+
338+ /**
339+ * Helper function that recursively searches for carousel components and extracts item types
340+ */
341+ function findCarouselsRecursive ( obj : any , itemTypes : Set < string > ) : void {
342+ if ( ! obj || typeof obj !== 'object' ) return ;
343+
344+ const typeValue = obj [ ':type' ] || obj [ 'type' ] ;
345+ const isCarousel = typeof typeValue === 'string' && typeValue . includes ( 'carousel' ) ;
346+
347+ if ( isCarousel && obj [ ':items' ] ) {
348+ // Get the items object
349+ const items = obj [ ':items' ] ;
350+
351+ if ( items && typeof items === 'object' ) {
352+ // Iterate through each item in the carousel
353+ for ( const [ key , value ] of Object . entries ( items ) ) {
354+ if ( value && typeof value === 'object' ) {
355+ const itemType = ( value as any ) [ ':type' ] ;
356+
357+ if ( itemType && typeof itemType === 'string' ) {
358+ // Extract component name from path
359+ const componentName = itemType . split ( '/' ) . pop ( ) ;
360+ if ( componentName ) {
361+ itemTypes . add ( componentName ) ;
362+ }
363+ }
364+ }
365+ }
366+ }
367+ }
368+
369+ // Recursively search nested objects
370+ if ( Array . isArray ( obj ) ) {
371+ obj . forEach ( item => findCarouselsRecursive ( item , itemTypes ) ) ;
372+ } else {
373+ Object . values ( obj ) . forEach ( value => findCarouselsRecursive ( value , itemTypes ) ) ;
374+ }
375+ }
376+
377+ /**
378+ * Scans all JSON files to find all unique component types used in carousel items
379+ * @param packagePath - Path to the AEM package
380+ * @returns Set of all component types found in any carousel
381+ */
382+ export async function scanAllCarouselItemTypes ( packagePath : string ) : Promise < Set < string > > {
383+ const carouselItemTypes = new Set < string > ( ) ;
384+ const filesDir = path . resolve ( packagePath ) ;
385+
386+ try {
387+ const allFiles = read ( filesDir ) ;
388+ const jsonFiles = allFiles . filter ( f => f . endsWith ( '.json' ) ) ;
389+
390+ for ( const fileName of jsonFiles ) {
391+ const filePath = path . join ( filesDir , fileName ) ;
392+
393+ try {
394+ const content = await fs . promises . readFile ( filePath , 'utf-8' ) ;
395+ const data = JSON . parse ( content ) ;
396+
397+ // Recursively search for carousel components
398+ findCarouselsRecursive ( data , carouselItemTypes ) ;
399+
400+ } catch ( err ) {
401+ // Skip invalid JSON files
402+ continue ;
403+ }
404+ }
405+ return carouselItemTypes ;
406+ } catch ( err ) {
407+ console . error ( '❌ Error scanning carousel items:' , err ) ;
408+ return carouselItemTypes ;
409+ }
336410}
0 commit comments