Skip to content

Commit f498bd2

Browse files
author
naman-contentstack
committed
chore: optimise code
1 parent d96e20b commit f498bd2

File tree

26 files changed

+405
-144
lines changed

26 files changed

+405
-144
lines changed

.talismanrc

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,12 @@
11
fileignoreconfig:
2-
- filename: packages/contentstack-asset-management/src/import/spaces.ts
3-
checksum: e972d66f6a889f72d72ba48112a12f9447de39285cfb568d3b99a4969cf9f5f9
2+
- filename: packages/contentstack-import-setup/src/types/default-config.ts
3+
checksum: 415cfa0e70dec18ca933534c8663fa7f5454c59123f8d3c74a8da38f50a91741
4+
- filename: packages/contentstack-asset-management/src/types/import-setup-asset-mapper.ts
5+
checksum: 410afe12a9decf2051d488e8dd5740c7d0f19ff88cc2c4258fa57b9283bc7e57
6+
- filename: packages/contentstack-import-setup/src/import/import-setup.ts
7+
checksum: 1927d72dde473f93b976096282742122bef2f6c2178611781d9ba2c210527566
8+
- filename: packages/contentstack-import-setup/src/utils/import-setup-asset-mapper-params.ts
9+
checksum: b646e603db48d86067e4ed29f5d699d52b4c45ded9cbe992e29167b839aa2575
10+
- filename: packages/contentstack-asset-management/src/import-setup/import-setup-asset-mappers.ts
11+
checksum: 944b033c4edc4b4b7a0cfe19b372af87b2243f58bdf3528c544c863600b204b6
412
version: '1.0'

packages/contentstack-asset-management/src/import-setup/import-setup-asset-mappers.ts

Lines changed: 40 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,8 @@ import { join, resolve } from 'node:path';
44

55
import { formatError, log } from '@contentstack/cli-utilities';
66

7-
import {
8-
IMPORT_ASSETS_MAPPER_DIR_SEGMENTS,
9-
IMPORT_ASSETS_MAPPER_FILES,
10-
PROCESS_NAMES,
11-
PROCESS_STATUS,
12-
} from '../constants/index';
13-
import type { AssetManagementAPIConfig } from '../types/asset-management-api';
7+
import { IMPORT_ASSETS_MAPPER_FILES, PROCESS_NAMES, PROCESS_STATUS } from '../constants/index';
8+
import type { AssetManagementAPIConfig, ImportContext } from '../types/asset-management-api';
149
import type { AssetMapperImportSetupResult, RunAssetMapperImportSetupParams } from '../types/import-setup-asset-mapper';
1510
import ImportAssets from '../import/assets';
1611
import { AssetManagementAdapter } from '../utils/asset-management-api-adapter';
@@ -57,6 +52,7 @@ export default class ImportSetupAssetMappers extends AssetManagementImportSetupA
5752
}
5853

5954
async start(): Promise<AssetMapperImportSetupResult> {
55+
const p = this.params;
6056
const {
6157
contentDir,
6258
mapperBaseDir,
@@ -66,12 +62,13 @@ export default class ImportSetupAssetMappers extends AssetManagementImportSetupA
6662
apiKey,
6763
host,
6864
context,
69-
fetchConcurrency,
70-
} = this.params;
65+
} = p;
66+
67+
const apiConcurrencyResolved = p.apiConcurrency ?? p.fetchConcurrency;
7168

7269
if (!assetManagementUrl) {
7370
log.info(
74-
'Asset Management export detected but region.assetManagementUrl is not configured. Skipping asset mapper setup.',
71+
'AM 2.0 export detected but assetManagementUrl is not configured in the region settings. Skipping AM 2.0 asset mapper setup.',
7572
context,
7673
);
7774
return { kind: 'skipped', reason: 'missing_asset_management_url' };
@@ -83,8 +80,14 @@ export default class ImportSetupAssetMappers extends AssetManagementImportSetupA
8380

8481
const parentProgressManager = this.resolveParentProgress();
8582

86-
const spacesRootPath = resolve(contentDir, 'spaces');
87-
const mapperDirPath = join(mapperBaseDir, ...IMPORT_ASSETS_MAPPER_DIR_SEGMENTS);
83+
const spacesDirSegment = p.spacesDirName ?? 'spaces';
84+
const spacesRootPath = resolve(contentDir, spacesDirSegment);
85+
const mapperRoot = p.mapperRootDir ?? 'mapper';
86+
const mapperAssetsMod = p.mapperAssetsModuleDir ?? 'assets';
87+
const mapperDirPath = join(mapperBaseDir, mapperRoot, mapperAssetsMod);
88+
const uidFile = p.mapperUidFileName ?? IMPORT_ASSETS_MAPPER_FILES.UID_MAPPING;
89+
const urlFile = p.mapperUrlFileName ?? IMPORT_ASSETS_MAPPER_FILES.URL_MAPPING;
90+
const spaceUidFile = p.mapperSpaceUidFileName ?? IMPORT_ASSETS_MAPPER_FILES.SPACE_UID_MAPPING;
8891
const duplicateAssetMapperPath = join(mapperDirPath, IMPORT_ASSETS_MAPPER_FILES.DUPLICATE_ASSETS);
8992

9093
const apiConfig: AssetManagementAPIConfig = {
@@ -93,14 +96,30 @@ export default class ImportSetupAssetMappers extends AssetManagementImportSetupA
9396
context,
9497
};
9598

96-
const importContext = {
99+
const importContext: ImportContext = {
97100
spacesRootPath,
98101
sourceApiKey: source_stack,
99102
apiKey,
100103
host,
101104
org_uid,
102105
context,
103-
apiConcurrency: fetchConcurrency,
106+
apiConcurrency: apiConcurrencyResolved,
107+
spacesDirName: p.spacesDirName,
108+
fieldsDir: p.fieldsDir,
109+
assetTypesDir: p.assetTypesDir,
110+
fieldsFileName: p.fieldsFileName,
111+
assetTypesFileName: p.assetTypesFileName,
112+
foldersFileName: p.foldersFileName,
113+
assetsFileName: p.assetsFileName,
114+
fieldsImportInvalidKeys: p.fieldsImportInvalidKeys,
115+
assetTypesImportInvalidKeys: p.assetTypesImportInvalidKeys,
116+
uploadAssetsConcurrency: p.uploadAssetsConcurrency,
117+
importFoldersConcurrency: p.importFoldersConcurrency,
118+
mapperRootDir: mapperRoot,
119+
mapperAssetsModuleDir: mapperAssetsMod,
120+
mapperUidFileName: uidFile,
121+
mapperUrlFileName: urlFile,
122+
mapperSpaceUidFileName: spaceUidFile,
104123
};
105124

106125
try {
@@ -115,7 +134,10 @@ export default class ImportSetupAssetMappers extends AssetManagementImportSetupA
115134

116135
const { spaceDirs, readFailed } = this.listExportedSpaceDirectories(spacesRootPath);
117136
if (spaceDirs.length === 0 && !readFailed) {
118-
log.info('No Asset Management space directories (am*) found under spaces/.', context);
137+
log.info(
138+
`No Asset Management space directories (am*) found under ${spacesDirSegment}/.`,
139+
context,
140+
);
119141
}
120142

121143
const allUidMap: Record<string, string> = {};
@@ -146,21 +168,9 @@ export default class ImportSetupAssetMappers extends AssetManagementImportSetupA
146168

147169
await mkdir(mapperDirPath, { recursive: true });
148170

149-
await writeFile(
150-
join(mapperDirPath, IMPORT_ASSETS_MAPPER_FILES.UID_MAPPING),
151-
JSON.stringify(allUidMap),
152-
'utf8',
153-
);
154-
await writeFile(
155-
join(mapperDirPath, IMPORT_ASSETS_MAPPER_FILES.URL_MAPPING),
156-
JSON.stringify(allUrlMap),
157-
'utf8',
158-
);
159-
await writeFile(
160-
join(mapperDirPath, IMPORT_ASSETS_MAPPER_FILES.SPACE_UID_MAPPING),
161-
JSON.stringify(spaceUidMap),
162-
'utf8',
163-
);
171+
await writeFile(join(mapperDirPath, uidFile), JSON.stringify(allUidMap), 'utf8');
172+
await writeFile(join(mapperDirPath, urlFile), JSON.stringify(allUrlMap), 'utf8');
173+
await writeFile(join(mapperDirPath, spaceUidFile), JSON.stringify(spaceUidMap), 'utf8');
164174

165175
await writeFile(duplicateAssetMapperPath, JSON.stringify({}), 'utf8');
166176

packages/contentstack-asset-management/src/types/import-setup-asset-mapper.ts

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,39 @@
11
export type RunAssetMapperImportSetupParams = {
22
contentDir: string;
3-
/** Parent of `mapper/assets` (typically import-setup `backupDir`). */
3+
/** Parent of the assets mapper directory (typically import-setup `backupDir`). */
44
mapperBaseDir: string;
55
assetManagementUrl?: string;
66
org_uid?: string;
77
source_stack?: string;
88
apiKey: string;
99
host: string;
1010
context: Record<string, unknown>;
11+
/**
12+
* Max parallel AM API calls for list/read paths.
13+
* Takes precedence over {@link fetchConcurrency}.
14+
*/
15+
apiConcurrency?: number;
16+
/**
17+
* @deprecated Use {@link apiConcurrency}.
18+
*/
1119
fetchConcurrency?: number;
20+
/** Relative dir under content dir for AM export root (default `spaces`). */
21+
spacesDirName?: string;
22+
fieldsDir?: string;
23+
assetTypesDir?: string;
24+
fieldsFileName?: string;
25+
assetTypesFileName?: string;
26+
foldersFileName?: string;
27+
assetsFileName?: string;
28+
fieldsImportInvalidKeys?: string[];
29+
assetTypesImportInvalidKeys?: string[];
30+
mapperRootDir?: string;
31+
mapperAssetsModuleDir?: string;
32+
mapperUidFileName?: string;
33+
mapperUrlFileName?: string;
34+
mapperSpaceUidFileName?: string;
35+
uploadAssetsConcurrency?: number;
36+
importFoldersConcurrency?: number;
1237
};
1338

1439
export type AssetMapperImportSetupResult =

packages/contentstack-asset-management/test/unit/import-setup/import-setup-asset-mappers.test.ts

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,4 +169,90 @@ describe('ImportSetupAssetMappers', () => {
169169
fs.rmSync(contentDir, { recursive: true, force: true });
170170
fs.rmSync(backupDir, { recursive: true, force: true });
171171
});
172+
173+
it('respects custom spacesDirName, mapper path segments, and mapper file names', async () => {
174+
const contentDir = tmpRoot();
175+
const backupDir = tmpRoot();
176+
fs.mkdirSync(path.join(contentDir, 'custom_spaces', 'amspace99'), { recursive: true });
177+
fs.mkdirSync(backupDir, { recursive: true });
178+
179+
stub(AssetManagementAdapter.prototype, 'init').resolves();
180+
stub(AssetManagementAdapter.prototype, 'listSpaces').resolves({
181+
spaces: [{ uid: 'amspace99' }],
182+
});
183+
184+
const buildStub = stub(ImportAssets.prototype, 'buildIdentityMappersFromExport').callsFake(async function mock(
185+
this: ImportAssets,
186+
spaceDir: string,
187+
) {
188+
expect(spaceDir).to.equal(path.join(contentDir, 'custom_spaces', 'amspace99'));
189+
expect((this as any).importContext.assetsFileName).to.equal('custom-assets.json');
190+
expect((this as any).importContext.apiConcurrency).to.equal(7);
191+
return { uidMap: { a: 'a' }, urlMap: { u: 'u' } };
192+
});
193+
194+
const mappers = new ImportSetupAssetMappers({
195+
contentDir,
196+
mapperBaseDir: backupDir,
197+
assetManagementUrl: 'https://am.example.com',
198+
org_uid: 'org-uid-test',
199+
apiKey: 'k',
200+
host: 'https://api.contentstack.io/v3',
201+
context: {},
202+
spacesDirName: 'custom_spaces',
203+
mapperRootDir: 'mappers_root',
204+
mapperAssetsModuleDir: 'am_assets',
205+
mapperUidFileName: 'uid-custom.json',
206+
mapperUrlFileName: 'url-custom.json',
207+
mapperSpaceUidFileName: 'space-custom.json',
208+
assetsFileName: 'custom-assets.json',
209+
apiConcurrency: 7,
210+
});
211+
212+
const result = await mappers.start();
213+
214+
expect(result.kind).to.equal('success');
215+
expect(buildStub.calledOnce).to.be.true;
216+
217+
const mapperDir = path.join(backupDir, 'mappers_root', 'am_assets');
218+
expect(JSON.parse(fs.readFileSync(path.join(mapperDir, 'uid-custom.json'), 'utf8'))).to.deep.equal({ a: 'a' });
219+
expect(JSON.parse(fs.readFileSync(path.join(mapperDir, 'url-custom.json'), 'utf8'))).to.deep.equal({ u: 'u' });
220+
expect(JSON.parse(fs.readFileSync(path.join(mapperDir, 'space-custom.json'), 'utf8'))).to.deep.equal({
221+
amspace99: 'amspace99',
222+
});
223+
224+
fs.rmSync(contentDir, { recursive: true, force: true });
225+
fs.rmSync(backupDir, { recursive: true, force: true });
226+
});
227+
228+
it('uses fetchConcurrency when apiConcurrency is omitted', async () => {
229+
const contentDir = tmpRoot();
230+
const backupDir = tmpRoot();
231+
fs.mkdirSync(path.join(contentDir, 'spaces', 'amX'), { recursive: true });
232+
fs.mkdirSync(backupDir, { recursive: true });
233+
234+
stub(AssetManagementAdapter.prototype, 'init').resolves();
235+
stub(AssetManagementAdapter.prototype, 'listSpaces').resolves({ spaces: [{ uid: 'amX' }] });
236+
237+
stub(ImportAssets.prototype, 'buildIdentityMappersFromExport').callsFake(async function fetchConcCheck(
238+
this: ImportAssets,
239+
) {
240+
expect((this as any).importContext.apiConcurrency).to.equal(3);
241+
return { uidMap: {}, urlMap: {} };
242+
});
243+
244+
await new ImportSetupAssetMappers({
245+
contentDir,
246+
mapperBaseDir: backupDir,
247+
assetManagementUrl: 'https://am.example.com',
248+
org_uid: 'org',
249+
apiKey: 'k',
250+
host: 'https://api.contentstack.io/v3',
251+
context: {},
252+
fetchConcurrency: 3,
253+
}).start();
254+
255+
fs.rmSync(contentDir, { recursive: true, force: true });
256+
fs.rmSync(backupDir, { recursive: true, force: true });
257+
});
172258
});

packages/contentstack-import-setup/src/config/index.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,41 @@ const config: DefaultConfig = {
4040
fileName: 'assets.json',
4141
fetchConcurrency: 5,
4242
},
43+
'asset-management': {
44+
dependencies: [],
45+
dirName: 'spaces',
46+
fieldsDir: 'fields',
47+
assetTypesDir: 'asset_types',
48+
fieldsFileName: 'fields.json',
49+
assetTypesFileName: 'asset-types.json',
50+
foldersFileName: 'folders.json',
51+
assetsFileName: 'assets.json',
52+
fieldsImportInvalidKeys: [
53+
'created_at',
54+
'created_by',
55+
'updated_at',
56+
'updated_by',
57+
'is_system',
58+
'asset_types_count',
59+
],
60+
assetTypesImportInvalidKeys: [
61+
'created_at',
62+
'created_by',
63+
'updated_at',
64+
'updated_by',
65+
'is_system',
66+
'category',
67+
'preview_image_url',
68+
'category_detail',
69+
],
70+
mapperRootDir: 'mapper',
71+
mapperAssetsModuleDir: 'assets',
72+
mapperUidFileName: 'uid-mapping.json',
73+
mapperUrlFileName: 'url-mapping.json',
74+
mapperSpaceUidFileName: 'space-uid-mapping.json',
75+
uploadAssetsConcurrency: 2,
76+
importFoldersConcurrency: 1,
77+
},
4378
'content-types': {
4479
dirName: 'content_types',
4580
fileName: 'content_types.json',
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/** Aligned with contentstack-import `PATH_CONSTANTS` for AM mapper defaults. */
2+
export const PATH_CONSTANTS = {
3+
MAPPER: 'mapper',
4+
FILES: {
5+
UID_MAPPING: 'uid-mapping.json',
6+
URL_MAPPING: 'url-mapping.json',
7+
SPACE_UID_MAPPING: 'space-uid-mapping.json',
8+
},
9+
MAPPER_MODULES: {
10+
ASSETS: 'assets',
11+
},
12+
} as const;

packages/contentstack-import-setup/src/import/import-setup.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,11 @@ export default class ImportSetup {
5050
* @returns {Promise<Array<void | string>>}
5151
*/
5252
protected async generateDependencyTree() {
53-
type ModulesKey = keyof typeof this.config.modules;
5453
const visited: Set<string> = new Set();
5554
const assignedDependencies: Set<string> = new Set(); // Track assigned dependencies
5655

56+
type ModulesKey = keyof typeof this.config.modules;
57+
5758
const getAllDependencies = (module: ModulesKey): Modules[] => {
5859
if (visited.has(module)) return [];
5960

packages/contentstack-import-setup/src/import/modules/assets.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,11 @@ export default class AssetImportSetup extends BaseImportSetup {
4242
async start() {
4343
try {
4444
if (this.config.assetManagementEnabled) {
45-
const assetManagementUrl = this.config.region?.assetManagementUrl;
45+
const assetManagementUrl = this.config.assetManagementUrl ?? this.config.region?.assetManagementUrl;
4646
if (!assetManagementUrl) {
4747
log(
4848
this.config,
49-
'Asset Management export detected but region.assetManagementUrl is not configured. Skipping asset mapper setup.',
49+
'AM 2.0 export detected but assetManagementUrl is not configured in the region settings. Skipping AM 2.0 asset mapper setup.',
5050
'info',
5151
);
5252
return;

packages/contentstack-import-setup/src/types/default-config.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,25 @@ export default interface DefaultConfig {
3030
dependencies?: Modules[];
3131
fetchConcurrency: number;
3232
};
33+
'asset-management': {
34+
dirName: string;
35+
fieldsDir: string;
36+
assetTypesDir: string;
37+
fieldsFileName: string;
38+
assetTypesFileName: string;
39+
foldersFileName: string;
40+
assetsFileName: string;
41+
fieldsImportInvalidKeys: string[];
42+
assetTypesImportInvalidKeys: string[];
43+
mapperRootDir: string;
44+
mapperAssetsModuleDir: string;
45+
mapperUidFileName: string;
46+
mapperUrlFileName: string;
47+
mapperSpaceUidFileName: string;
48+
uploadAssetsConcurrency: number;
49+
importFoldersConcurrency: number;
50+
dependencies?: Modules[];
51+
};
3352
'content-types': {
3453
dirName: string;
3554
fileName: string;

packages/contentstack-import-setup/src/types/import-config.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ export default interface ImportConfig extends DefaultConfig, ExternalConfig {
5050
authenticationMethod?: string;
5151
/** Set when export layout is Asset Management (`spaces/` + stack settings key `am_v2`). */
5252
assetManagementEnabled?: boolean;
53+
/** AM 2.0 base URL from region / detection (`detectAssetManagementExportFromContentDir`). */
54+
assetManagementUrl?: string;
5355
}
5456

5557
type branch = {

0 commit comments

Comments
 (0)