From 13b4c1e8b8bf80aaf8a52604976521c428880e02 Mon Sep 17 00:00:00 2001 From: shobhit upadhyay Date: Wed, 15 Oct 2025 11:49:15 +0530 Subject: [PATCH 1/2] refactor: improve file writing logic in aem.service.ts, attaching reference entries and fix referenceTo typo in ContentMapper components acheiving selection of default CT in reference field advance setting --- api/src/services/aem.service.ts | 94 +++++++++++-------- ui/src/components/AdvancePropertise/index.tsx | 2 +- .../ContentMapper/contentMapper.interface.ts | 2 +- ui/src/components/ContentMapper/index.tsx | 4 +- 4 files changed, 57 insertions(+), 45 deletions(-) diff --git a/api/src/services/aem.service.ts b/api/src/services/aem.service.ts index 84d31c7b9..419174091 100644 --- a/api/src/services/aem.service.ts +++ b/api/src/services/aem.service.ts @@ -105,11 +105,12 @@ function findAssetByPath( } async function writeOneFile(indexPath: string, fileMeta: any) { - fs.writeFile(indexPath, JSON.stringify(fileMeta), (err) => { - if (err) { - console.error('Error writing file: 3', err); - } - }); + try { + await fs.promises.writeFile(indexPath, JSON.stringify(fileMeta)); + } catch (err) { + console.error('Error writing file:', err); + throw err; + } } async function writeFiles( @@ -121,23 +122,18 @@ async function writeFiles( try { const indexPath = path.join(entryPath, 'index.json'); const localePath = path.join(entryPath, `${locale}.json`); - fs.access(entryPath, async (err) => { - if (err) { - fs.mkdir(entryPath, { recursive: true }, async (err) => { - if (err) { - console.error('Error writing file: 2', err); - } else { - await writeOneFile(indexPath, fileMeta); - await writeOneFile(localePath, entryLocale); - } - }); - } else { - await writeOneFile(indexPath, fileMeta); - await writeOneFile(localePath, entryLocale); - } - }); - } catch (error) { + + try { + await fs.promises.access(entryPath); + } catch { + await fs.promises.mkdir(entryPath, { recursive: true }); + } + + await fs.promises.writeFile(indexPath, JSON.stringify(fileMeta)); + await fs.promises.writeFile(localePath, JSON.stringify(entryLocale)); +} catch (error) { console.error('Error writing files:', error); + throw error; } } @@ -484,19 +480,27 @@ function processFieldsRecursive(fields: any[], items: any, title: string, assetJ break; } case 'reference': { - for (const [, val] of Object.entries(items) as [string, Record][]) { + const fieldKey = getLastKey(field?.contentstackFieldUid); + const refCtUid = field?.referenceTo?.[0] || field?.uid; + + for (const [key, val] of Object.entries(items) as [string, Record][]) { + if (!val?.configured || (val[':type'] as string) === 'nt:folder') { + continue; + } + if ( - (typeof field?.uid === 'string' && !['title', 'url'].includes(field.uid)) && - field?.contentstackFieldType === "reference" && - (val[':type'] as string) !== 'nt:folder' && - val?.configured + (val[':type'] as string)?.includes('experiencefragment') && + typeof val?.localizedFragmentVariationPath === 'string' ) { - if (typeof val?.localizedFragmentVariationPath === 'string' && - val.localizedFragmentVariationPath.includes(`/${field?.uid}`)) { - obj[field?.uid as string] = [{ + const pathMatchesField = val.localizedFragmentVariationPath.includes(`/${field?.uid}`); + const pathMatchesRefType = val.localizedFragmentVariationPath.includes(`/${refCtUid}`); + + if (pathMatchesField || pathMatchesRefType) { + obj[fieldKey] = [{ "uid": val?.id, - "_content_type_uid": field?.uid, + "_content_type_uid": refCtUid }]; + break; } } } @@ -559,7 +563,6 @@ const createEntry = async ({ contentTypes, destinationStackId, projectId, - // keyMapper, project }: CreateEntryOptions) => { const srcFunc = 'createEntry'; @@ -569,17 +572,21 @@ const createEntry = async ({ const assetJson = path.join(assetsSave, ASSETS_SCHEMA_FILE); const exists = await isAssetJsonCreated(assetJson); let assetJsonData: Record = {}; + if (exists) { const assetData = await fs.promises.readFile(assetJson, 'utf-8'); if (typeof assetData === 'string') { assetJsonData = JSON.parse(assetData); } } + const entriesDir = path.resolve(packagePath ?? ''); const damPath = path.join(entriesDir, AEM_DAM_DIR); const entriesData: Record> = {}; const allLocales: object = { ...project?.master_locale, ...project?.locales }; const entryMapping: Record = {}; + + // FIRST PASS: Process all entries and build mappings for await (const fileName of read(entriesDir)) { const filePath = path.join(entriesDir, fileName); if (filePath?.startsWith?.(damPath)) { @@ -599,11 +606,11 @@ const createEntry = async ({ const data = containerCreator(contentType?.fieldMapping, items, title, assetJsonData); data.uid = uid; data.publish_details = []; + if (contentType?.contentstackUid && data && mappedLocale) { const message = getLogMessage( srcFunc, - `Entry title "${data?.title}"(${contentType?.contentstackUid} - }) in the ${mappedLocale} locale has been successfully transformed.`, + `Entry title "${data?.title}"(${contentType?.contentstackUid}) in the ${mappedLocale} locale has been successfully transformed.`, {} ); await customLogger( @@ -625,17 +632,22 @@ const createEntry = async ({ for (const entry of entries) { const flatData = deepFlattenObject(entry); for (const [key, value] of Object.entries(flatData)) { - if (key.endsWith('._content_type_uid')) { - const uidFeild = key.replace('._content_type_uid', ''); - if (uidFeild && typeof value === 'string') { - const refs: string[] = entryMapping?.[value]; - if (refs?.length) { - _.set(entry, `${uidFeild}.uid`, refs?.[0]); - } + if (key.endsWith('._content_type_uid') && typeof value === 'string') { + const uidField = key.replace('._content_type_uid', ''); + const refs: string[] = entryMapping?.[value]; + + if (refs?.length) { + _.set(entry, `${uidField}.uid`, refs[0]); + } else { + console.info(`✗ No entry found for content type: ${value}`); } } } } + const entriesObject: Record = {}; + for (const entry of entries) { + entriesObject[entry.uid] = entry; + } const fileMeta = { '1': `${locale}.json` }; const entryPath = path.join( process.cwd(), @@ -643,7 +655,7 @@ const createEntry = async ({ ctUid, locale ); - await writeFiles(entryPath, fileMeta, entries, locale); + await writeFiles(entryPath, fileMeta, entriesObject, locale); } } } diff --git a/ui/src/components/AdvancePropertise/index.tsx b/ui/src/components/AdvancePropertise/index.tsx index a33a25540..56b4b4d95 100644 --- a/ui/src/components/AdvancePropertise/index.tsx +++ b/ui/src/components/AdvancePropertise/index.tsx @@ -67,7 +67,7 @@ const AdvancePropertise = (props: SchemaProps) => { value: item })); - const referencedItems = props?.data?.referenceTo?.map((item: string) => ({ + const referencedItems = props?.data?.refrenceTo?.map((item: string) => ({ label: item, value: item })); diff --git a/ui/src/components/ContentMapper/contentMapper.interface.ts b/ui/src/components/ContentMapper/contentMapper.interface.ts index 0adaedd79..281c11fe6 100644 --- a/ui/src/components/ContentMapper/contentMapper.interface.ts +++ b/ui/src/components/ContentMapper/contentMapper.interface.ts @@ -67,7 +67,7 @@ export interface FieldMapType { contentstackUid: string; _invalid?: boolean; backupFieldUid: string; - referenceTo: string[]; + refrenceTo: string[]; } export interface Advanced { diff --git a/ui/src/components/ContentMapper/index.tsx b/ui/src/components/ContentMapper/index.tsx index 3272c7af0..0d6c51ddb 100644 --- a/ui/src/components/ContentMapper/index.tsx +++ b/ui/src/components/ContentMapper/index.tsx @@ -333,7 +333,7 @@ const ContentMapper = forwardRef(({ handleStepChange }: contentMapperProps, ref: // Make title and url field non editable useEffect(() => { tableData?.forEach((field) => { - if(field?.backupFieldType === 'reference' && field?.referenceTo?.length === 0) { + if(field?.backupFieldType === 'reference' && field?.refrenceTo?.length === 0) { field._canSelect = false; } else if (field?.backupFieldType !== 'text' && field?.backupFieldType !== 'url') { @@ -860,7 +860,7 @@ const ContentMapper = forwardRef(({ handleStepChange }: contentMapperProps, ref: if (row?.uid === rowId && row?.contentstackFieldUid === rowContentstackFieldUid) { const updatedRow = { ...row, - referenceTo: updatedSettings?.referenedItems, + refrenceTo: updatedSettings?.referenedItems, advanced: { ...row?.advanced, ...updatedSettings } }; return updatedRow; From c26e00c3d102e222a9fd7cf12878d3db4dcdf66d Mon Sep 17 00:00:00 2001 From: shobhit upadhyay Date: Wed, 15 Oct 2025 14:57:29 +0530 Subject: [PATCH 2/2] refactor: enhance file processing in aem.service.ts and add snake case UID formatting in uidCorrector function for dynamic attachement of values in boolean fields --- api/src/services/aem.service.ts | 24 +++++++++++------------- upload-api/migration-aem/helper/index.ts | 3 +++ 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/api/src/services/aem.service.ts b/api/src/services/aem.service.ts index 419174091..5e29f46dc 100644 --- a/api/src/services/aem.service.ts +++ b/api/src/services/aem.service.ts @@ -122,16 +122,16 @@ async function writeFiles( try { const indexPath = path.join(entryPath, 'index.json'); const localePath = path.join(entryPath, `${locale}.json`); - + try { await fs.promises.access(entryPath); } catch { await fs.promises.mkdir(entryPath, { recursive: true }); } - + await fs.promises.writeFile(indexPath, JSON.stringify(fileMeta)); await fs.promises.writeFile(localePath, JSON.stringify(entryLocale)); -} catch (error) { + } catch (error) { console.error('Error writing files:', error); throw error; } @@ -456,8 +456,9 @@ function processFieldsRecursive(fields: any[], items: any, title: string, assetJ break; } case 'boolean': { - const value = items?.[field?.uid]; - const uid = getLastKey(field?.contentstackFieldUid); + const aemFieldName = field?.otherCmsField ? getLastKey(field.otherCmsField, ' > ') : getLastKey(field?.uid); + const value = items?.[aemFieldName]; + const uid = getLastKey(field?.contentstackFieldUid); if (typeof value === 'boolean' || (typeof value === 'object' && value?.[':type']?.includes('separator'))) { obj[uid] = typeof value === 'boolean' ? value : true; } @@ -482,19 +483,16 @@ function processFieldsRecursive(fields: any[], items: any, title: string, assetJ case 'reference': { const fieldKey = getLastKey(field?.contentstackFieldUid); const refCtUid = field?.referenceTo?.[0] || field?.uid; - for (const [key, val] of Object.entries(items) as [string, Record][]) { if (!val?.configured || (val[':type'] as string) === 'nt:folder') { continue; } - if ( (val[':type'] as string)?.includes('experiencefragment') && typeof val?.localizedFragmentVariationPath === 'string' ) { const pathMatchesField = val.localizedFragmentVariationPath.includes(`/${field?.uid}`); const pathMatchesRefType = val.localizedFragmentVariationPath.includes(`/${refCtUid}`); - if (pathMatchesField || pathMatchesRefType) { obj[fieldKey] = [{ "uid": val?.id, @@ -572,14 +570,14 @@ const createEntry = async ({ const assetJson = path.join(assetsSave, ASSETS_SCHEMA_FILE); const exists = await isAssetJsonCreated(assetJson); let assetJsonData: Record = {}; - + if (exists) { const assetData = await fs.promises.readFile(assetJson, 'utf-8'); if (typeof assetData === 'string') { assetJsonData = JSON.parse(assetData); } } - + const entriesDir = path.resolve(packagePath ?? ''); const damPath = path.join(entriesDir, AEM_DAM_DIR); const entriesData: Record> = {}; @@ -606,7 +604,7 @@ const createEntry = async ({ const data = containerCreator(contentType?.fieldMapping, items, title, assetJsonData); data.uid = uid; data.publish_details = []; - + if (contentType?.contentstackUid && data && mappedLocale) { const message = getLogMessage( srcFunc, @@ -635,7 +633,7 @@ const createEntry = async ({ if (key.endsWith('._content_type_uid') && typeof value === 'string') { const uidField = key.replace('._content_type_uid', ''); const refs: string[] = entryMapping?.[value]; - + if (refs?.length) { _.set(entry, `${uidField}.uid`, refs[0]); } else { @@ -647,7 +645,7 @@ const createEntry = async ({ const entriesObject: Record = {}; for (const entry of entries) { entriesObject[entry.uid] = entry; - } + } const fileMeta = { '1': `${locale}.json` }; const entryPath = path.join( process.cwd(), diff --git a/upload-api/migration-aem/helper/index.ts b/upload-api/migration-aem/helper/index.ts index d6a766f90..011402e4f 100644 --- a/upload-api/migration-aem/helper/index.ts +++ b/upload-api/migration-aem/helper/index.ts @@ -203,6 +203,9 @@ export const uidCorrector = (uid: string) => { // Remove leading colon if present (e.g., ':items' becomes 'items') let newUid = uid.replace(/^:/, ''); + // Insert underscore before uppercase letters, then lowercase everything + newUid = newUid.replace(/([a-z0-9])([A-Z])/g, '$1_$2'); + // Replace spaces, hyphens, and colons with underscores newUid = newUid.replace(/[ :-]/g, '_');