Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -117,4 +117,28 @@ describe('BackendGenerator', () => {
"
`);
});

it('deduplicates namespace aliases when two resources share a preferred name', async () => {
const gen = new BackendGenerator(outputDir, logger);

// Simulate: REST API "mergeStudents" and Lambda function "mergeStudents"
const apiAlias = gen.reserveAlias('mergeStudents', 'api');
const fnAlias = gen.reserveAlias('mergeStudents', 'function');

expect(apiAlias).toBe('mergeStudents');
expect(fnAlias).toBe('mergeStudentsFunction');
expect(apiAlias).not.toBe(fnAlias);

gen.addNamespaceImport(apiAlias, './api/mergeStudents/resource');
gen.addPostDefineBackendStatement(`${apiAlias}.defineMergeStudentsApi(backend)`);
gen.addNamespaceImport(fnAlias, './function/mergeStudents/resource');
gen.addDefineBackendEntry('mergeStudents', fnAlias, 'mergeStudents');

const ops = await gen.plan();
await ops[0].execute();

const content = await fs.readFile(path.join(outputDir, 'amplify', 'backend.ts'), 'utf-8');
const importLines = content.split('\n').filter((l) => l.startsWith('import * as mergeStudents '));
expect(importLines).toHaveLength(1);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -100,9 +100,10 @@ export class AnalyticsKinesisGenerator implements Planner {
await fs.mkdir(analyticsDir, { recursive: true });
await fs.writeFile(path.join(analyticsDir, 'resource.ts'), content, 'utf-8');

this.backendGenerator.addNamespaceImport('analytics', './analytics/resource');
this.backendGenerator.addPostDefineBackendCall(DEFINE_ANALYTICS_VARIABLE_NAME, `analytics.defineAnalytics(backend)`);
this.backendGenerator.addPostRefactorCall(`analytics.postRefactor(${DEFINE_ANALYTICS_VARIABLE_NAME});`);
const alias = this.backendGenerator.reserveAlias('analytics', 'analytics');
this.backendGenerator.addNamespaceImport(alias, './analytics/resource');
this.backendGenerator.addPostDefineBackendCall(DEFINE_ANALYTICS_VARIABLE_NAME, `${alias}.defineAnalytics(backend)`);
this.backendGenerator.addPostRefactorCall(`${alias}.postRefactor(${DEFINE_ANALYTICS_VARIABLE_NAME});`);
},
},
];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,11 +97,12 @@ export class AuthGenerator implements Planner {
await fs.mkdir(authDir, { recursive: true });
await fs.writeFile(path.join(authDir, 'resource.ts'), content, 'utf-8');

this.backendGenerator.addNamespaceImport('auth', './auth/resource');
this.backendGenerator.addDefineBackendEntry('auth', 'auth', 'auth');
this.backendGenerator.addApplyEscapeHatchesCall({ alias: 'auth', extraArgs: [] });
const alias = this.backendGenerator.reserveAlias('auth', 'auth');
this.backendGenerator.addNamespaceImport(alias, './auth/resource');
this.backendGenerator.addDefineBackendEntry('auth', alias, 'auth');
this.backendGenerator.addApplyEscapeHatchesCall({ alias, extraArgs: [] });
if (userPool.Domain) {
this.backendGenerator.addPostRefactorCall('auth.postRefactor(backend)');
this.backendGenerator.addPostRefactorCall(`${alias}.postRefactor(backend)`);
}
},
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,9 @@ export class ReferenceAuthGenerator implements Planner {
await fs.mkdir(authDir, { recursive: true });
await fs.writeFile(path.join(authDir, 'resource.ts'), content, 'utf-8');

this.backendGenerator.addNamespaceImport('auth', './auth/resource');
this.backendGenerator.addDefineBackendEntry('auth', 'auth', 'auth');
const alias = this.backendGenerator.reserveAlias('auth', 'auth');
this.backendGenerator.addNamespaceImport(alias, './auth/resource');
this.backendGenerator.addDefineBackendEntry('auth', alias, 'auth');
},
},
];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,38 @@ export class BackendGenerator implements Planner {
private readonly outputDir: string;
private readonly renderer = new BackendRenderer();
private readonly logger: SpinningLogger;
private readonly usedAliases = new Set<string>();

public constructor(outputDir: string, logger: SpinningLogger) {
this.outputDir = outputDir;
this.logger = logger;
}

/**
* Reserves a unique import alias for a namespace import.
* Returns `preferred` if not yet taken; otherwise appends the capitalized
* category (e.g. `mergeStudentsFunction`). If that is also taken, appends
* an incrementing numeric suffix (e.g. `mergeStudentsFunction2`).
*/
public reserveAlias(preferred: string, category: string): string {
if (!this.usedAliases.has(preferred)) {
this.usedAliases.add(preferred);
return preferred;
}
const categoryAlias = preferred + category.charAt(0).toUpperCase() + category.slice(1);
if (!this.usedAliases.has(categoryAlias)) {
this.usedAliases.add(categoryAlias);
return categoryAlias;
}
let suffix = 2;
while (this.usedAliases.has(categoryAlias + suffix)) {
suffix++;
}
const final = categoryAlias + suffix;
this.usedAliases.add(final);
return final;
}

/**
* Adds a namespace import: `import * as alias from 'source';`
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ export class CustomResourceGenerator implements Planner {
* Contributes import and defineXxx call for this custom resource to backend.ts.
*/
private contributeToBackend(constructClassName: string): void {
const alias = this.resourceName;
const alias = this.backendGenerator.reserveAlias(this.resourceName, 'custom');
const defineFnName = `define${constructClassName}`;

this.backendGenerator.addNamespaceImport(alias, `./custom/${this.resourceName}/resource`);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -197,10 +197,11 @@ export class DataGenerator implements Planner {
await fs.mkdir(dataDir, { recursive: true });
await fs.writeFile(path.join(dataDir, 'resource.ts'), content, 'utf-8');

this.backendGenerator.addNamespaceImport('data', './data/resource');
this.backendGenerator.addDefineBackendEntry('data', 'data', 'data');
const alias = this.backendGenerator.reserveAlias('data', 'data');
this.backendGenerator.addNamespaceImport(alias, './data/resource');
this.backendGenerator.addDefineBackendEntry('data', alias, 'data');
if (needsEscapeHatches) {
this.backendGenerator.addApplyEscapeHatchesCall({ alias: 'data', extraArgs: [] });
this.backendGenerator.addApplyEscapeHatchesCall({ alias, extraArgs: [] });
}
},
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ export class FunctionGenerator implements Planner {
await fs.writeFile(path.join(dirPath, 'resource.ts'), content, 'utf-8');
await this.copyFunctionSource(resourceName, dirPath);

const alias = resourceName;
const alias = this.backendGenerator.reserveAlias(resourceName, 'function');
this.backendGenerator.addNamespaceImport(alias, `./function/${resourceName}/resource`);
this.backendGenerator.addDefineBackendEntry(resourceName, alias, resourceName);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,9 @@ export class GeoGenerator implements Planner {
await fs.mkdir(geoDir, { recursive: true });
await fs.writeFile(path.join(geoDir, 'resource.ts'), content, 'utf-8');

this.backendGenerator.addNamespaceImport('geo', './geo/resource');
this.backendGenerator.addPostDefineBackendStatement(`geo.defineGeo(backend)`);
const alias = this.backendGenerator.reserveAlias('geo', 'geo');
this.backendGenerator.addNamespaceImport(alias, './geo/resource');
this.backendGenerator.addPostDefineBackendStatement(`${alias}.defineGeo(backend)`);
},
},
];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@ export class RestApiGenerator implements Planner {
await fs.mkdir(apiDir, { recursive: true });
await fs.writeFile(path.join(apiDir, 'resource.ts'), content, 'utf-8');

const alias = restApi.apiName;
this.backendGenerator.addNamespaceImport(alias, `./api/${alias}/resource`);
const alias = this.backendGenerator.reserveAlias(restApi.apiName, 'api');
this.backendGenerator.addNamespaceImport(alias, `./api/${restApi.apiName}/resource`);
this.backendGenerator.addPostDefineBackendStatement(`${alias}.${restApi.exportedFunctionName}(backend)`);
},
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ export class DynamoDBGenerator implements Planner {
execute: async () => {
const capitalizedName = this.resource.resourceName.charAt(0).toUpperCase() + this.resource.resourceName.slice(1);
const functionName = `defineStorage${capitalizedName}`;
const storageAlias = `storage${capitalizedName}`;

// Write the resource.ts file for this DynamoDB table
const resourceDir = path.join(this.outputDir, 'amplify', 'storage', this.resource.resourceName);
Expand All @@ -65,6 +64,7 @@ export class DynamoDBGenerator implements Planner {
await fs.writeFile(path.join(resourceDir, 'resource.ts'), content, 'utf-8');

// Contribute to backend.ts
const storageAlias = this.backendGenerator.reserveAlias(`storage${capitalizedName}`, 'storage');
this.backendGenerator.addNamespaceImport(storageAlias, `./storage/${this.resource.resourceName}/resource`);
this.backendGenerator.addPostDefineBackendCall(this.resource.resourceName, `${storageAlias}.${functionName}(backend)`);
this.backendGenerator.addPostRefactorCall(`${storageAlias}.postRefactor(${this.resource.resourceName});`);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,10 +101,11 @@ export class S3Generator implements Planner {
await fs.mkdir(storageDir, { recursive: true });
await fs.writeFile(path.join(storageDir, 'resource.ts'), content, 'utf-8');

this.backendGenerator.addNamespaceImport('storage', './storage/resource');
this.backendGenerator.addDefineBackendEntry('storage', 'storage', 'storage');
this.backendGenerator.addApplyEscapeHatchesCall({ alias: 'storage', extraArgs: [] });
this.backendGenerator.addPostRefactorCall('storage.postRefactor(backend);');
const alias = this.backendGenerator.reserveAlias('storage', 'storage');
this.backendGenerator.addNamespaceImport(alias, './storage/resource');
this.backendGenerator.addDefineBackendEntry('storage', alias, 'storage');
this.backendGenerator.addApplyEscapeHatchesCall({ alias, extraArgs: [] });
this.backendGenerator.addPostRefactorCall(`${alias}.postRefactor(backend);`);
},
},
];
Expand Down
Loading