Skip to content

Commit 0cd600b

Browse files
committed
feat: added support for more code variations
1 parent 5ebce9a commit 0cd600b

File tree

3 files changed

+195
-26
lines changed

3 files changed

+195
-26
lines changed

src/codebaseHelpers/ImportAndAddItemToInitializerArrayProperty.ts

Lines changed: 44 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ export class ImportAndAddItemToInitializerArrayProperty {
2121
private referenceAdded: boolean = false;
2222
private importAdded: boolean = false;
2323
private filesToAddImportInFilePaths = new Set<string>();
24-
private variableDeclarationReplacementMap = new Map<ts.VariableDeclaration, ts.VariableDeclaration>();
24+
private declarationReplacementMap = new Map<ts.Declaration, ts.Declaration>();
2525

2626
private linkingError: boolean = false;
2727

@@ -441,38 +441,60 @@ export class ImportAndAddItemToInitializerArrayProperty {
441441
declaration, declaration.name, declaration.exclamationToken, declaration.type,
442442
updateWithTypeExpression(declaration.initializer,
443443
(valueExpression) => {
444-
if (ts.isArrayLiteralExpression(valueExpression)) {
445-
const resExpression = this.updateArrayLiteralExpression(valueExpression, undefined);
444+
const resExpression = this.updateExpression(valueExpression, valueExpression.getSourceFile());
446445

447-
if (valueExpression != (resExpression))
448-
declarationUpdated = true;
446+
if (valueExpression != resExpression)
447+
declarationUpdated = true;
449448

450-
return resExpression;
451-
}
449+
return resExpression;
450+
}
451+
)
452+
);
452453

453-
if (ts.isObjectLiteralExpression(valueExpression) && this.treatObjectLiteralExpressionValuesAsList) {
454-
const resExpression = this.updateObjectLiteralExpression(valueExpression, undefined);
454+
if (declarationUpdated) {
455+
this.declarationReplacementMap.set(declaration, newDeclaration);
455456

456-
if (valueExpression != (resExpression))
457-
declarationUpdated = true;
457+
this.codebase.markSourceFileAsUpdated(declaration.getSourceFile());
458+
}
459+
} else if (
460+
// *export []*
461+
// *export {}*
462+
ts.isExportAssignment(declaration)
463+
) {
464+
if (
465+
!this.updateOtherRelevantFiles &&
466+
path.resolve(sourceFile.fileName) != path.resolve(this.codebase.entryFilePath)
467+
)
468+
return;
458469

459-
return resExpression;
460-
}
470+
let declarationUpdated = false;
471+
const newDeclaration = ts.factory.updateExportAssignment(
472+
declaration, declaration.decorators, declaration.modifiers,
473+
updateWithTypeExpression(declaration.expression,
474+
(valueExpression) => {
475+
const resExpression = this.updateExpression(valueExpression, valueExpression.getSourceFile());
461476

462-
return valueExpression;
477+
if (valueExpression != resExpression)
478+
declarationUpdated = true;
479+
480+
return resExpression;
463481
}
464482
)
465483
);
466484

467485
if (declarationUpdated) {
468-
this.variableDeclarationReplacementMap.set(declaration, newDeclaration);
486+
this.declarationReplacementMap.set(declaration, newDeclaration);
469487

470488
this.codebase.markSourceFileAsUpdated(declaration.getSourceFile());
471489
}
472490
} else if (
473491
// *import {value} from "./somewhere"*
474-
ts.isImportSpecifier(declaration)
492+
ts.isImportSpecifier(declaration) ||
493+
ts.isImportClause(declaration)
475494
) {
495+
if (declaration.name == null)
496+
return;
497+
476498
const declarationNamedImportSymbol = this.codebase.checker.getSymbolAtLocation(declaration.name);
477499

478500
if (declarationNamedImportSymbol == null)
@@ -570,12 +592,12 @@ export class ImportAndAddItemToInitializerArrayProperty {
570592
]);
571593
}
572594

573-
private updateDeclaration(declaration: ts.VariableDeclaration): ts.VariableDeclaration {
574-
const res = this.variableDeclarationReplacementMap.get(declaration);
595+
private updateDeclaration<T extends ts.Declaration>(declaration: T): T {
596+
const res = this.declarationReplacementMap.get(declaration);
575597

576598
if (res != null) {
577-
this.variableDeclarationReplacementMap.delete(declaration);
578-
return res;
599+
this.declarationReplacementMap.delete(declaration);
600+
return res as T;
579601
}
580602

581603
return declaration;
@@ -590,7 +612,8 @@ export class ImportAndAddItemToInitializerArrayProperty {
590612
statement.declarationList.declarations.map(this.updateDeclaration)
591613
)
592614
);
593-
}
615+
} else if (ts.isExportAssignment(statement))
616+
return this.updateDeclaration(statement);
594617

595618
return statement;
596619
})

src/commands/AddReferencesCommand.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,6 @@ export class AddReferencesCommand implements yargs.CommandModule<object, command
1010

1111
cwd = process.cwd();
1212

13-
constructor() {
14-
this.builder = this.builder.bind(this);
15-
}
16-
1713
builder(args: yargs.Argv) {
1814
return args
1915
.usage(`Usage: $0 ${this.command} --dataSource <path> [options]`)
@@ -50,7 +46,7 @@ export class AddReferencesCommand implements yargs.CommandModule<object, command
5046
});
5147
}
5248

53-
async handler(args: commandArgs) {
49+
handler = async (args: commandArgs) => {
5450
const cwd = this.cwd ?? process.cwd();
5551
let addedMigrationFiles: string[] = [];
5652
let addedEntityFiles: string[] = [];

test/codebaseHelpers/ImportAndAddItemToInitializerArrayProperty.test.ts

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,156 @@ describe("Update DataSource initializer in data-source.ts file", () => {
318318
});
319319
});
320320

321+
it("external file with default exported variable list", async () => {
322+
await testDataSourceFileWithLinkToEntitiesInOtherFile({
323+
entityName,
324+
dataSourceCode: `
325+
import entities from "./entities.js"
326+
327+
export const AppDataSource = new DataSource({
328+
type: "sqlite",
329+
database: "database.db",
330+
entities: entities
331+
});
332+
`,
333+
files: [{
334+
path: "entities.ts",
335+
content: `
336+
import { SomeModal } from "./entities/SomeModal.js";
337+
338+
const entities1 = [
339+
SomeModal
340+
];
341+
342+
export default entities1;
343+
`
344+
}, {
345+
path: "entities/SomeModal.ts",
346+
content: `
347+
export class SomeModal {}
348+
`
349+
}],
350+
testCode: `
351+
const entities: any = dataSourceResult.AppDataSource.options.entities;
352+
expect(entities).to.be.an("array");
353+
expect(entities.length).to.be.gt(0);
354+
expect(entities[entities.length - 1].name).to.be.eq(${JSON.stringify(entityName)});
355+
`
356+
});
357+
});
358+
359+
it("external file with default exported list", async () => {
360+
await testDataSourceFileWithLinkToEntitiesInOtherFile({
361+
entityName,
362+
dataSourceCode: `
363+
import entities from "./entities.js"
364+
365+
export const AppDataSource = new DataSource({
366+
type: "sqlite",
367+
database: "database.db",
368+
entities: entities
369+
});
370+
`,
371+
files: [{
372+
path: "entities.ts",
373+
content: `
374+
import { SomeModal } from "./entities/SomeModal.js";
375+
376+
export default [
377+
SomeModal
378+
];
379+
`
380+
}, {
381+
path: "entities/SomeModal.ts",
382+
content: `
383+
export class SomeModal {}
384+
`
385+
}],
386+
testCode: `
387+
const entities: any = dataSourceResult.AppDataSource.options.entities;
388+
expect(entities).to.be.an("array");
389+
expect(entities.length).to.be.gt(0);
390+
expect(entities[entities.length - 1].name).to.be.eq(${JSON.stringify(entityName)});
391+
`
392+
});
393+
});
394+
395+
it("external file with default exported variable object", async () => {
396+
await testDataSourceFileWithLinkToEntitiesInOtherFile({
397+
entityName,
398+
dataSourceCode: `
399+
import entities from "./entities.js"
400+
401+
export const AppDataSource = new DataSource({
402+
type: "sqlite",
403+
database: "database.db",
404+
entities: entities
405+
});
406+
`,
407+
files: [{
408+
path: "entities.ts",
409+
content: `
410+
import { SomeModal } from "./entities/SomeModal.js";
411+
412+
const entities1 = {
413+
SomeModal
414+
};
415+
416+
export default entities1;
417+
`
418+
}, {
419+
path: "entities/SomeModal.ts",
420+
content: `
421+
export class SomeModal {}
422+
`
423+
}],
424+
testCode: `
425+
const entities: any = dataSourceResult.AppDataSource.options.entities;
426+
expect(entities).to.be.an("object");
427+
const entityNamesList: (string | undefined)[] = Object.values(entities).map((entity: any) => entity?.name);
428+
expect(entityNamesList.length).to.be.gt(0);
429+
expect(entityNamesList).to.include(${JSON.stringify(entityName)});
430+
`
431+
});
432+
});
433+
434+
it("external file with default exported object", async () => {
435+
await testDataSourceFileWithLinkToEntitiesInOtherFile({
436+
entityName,
437+
dataSourceCode: `
438+
import entities from "./entities.js"
439+
440+
export const AppDataSource = new DataSource({
441+
type: "sqlite",
442+
database: "database.db",
443+
entities: entities
444+
});
445+
`,
446+
files: [{
447+
path: "entities.ts",
448+
content: `
449+
import { SomeModal } from "./entities/SomeModal.js";
450+
451+
export default {
452+
SomeModal
453+
};
454+
`
455+
}, {
456+
path: "entities/SomeModal.ts",
457+
content: `
458+
export class SomeModal {}
459+
`
460+
}],
461+
testCode: `
462+
const entities: any = dataSourceResult.AppDataSource.options.entities;
463+
expect(entities).to.be.an("object");
464+
const entityNamesList: (string | undefined)[] = Object.values(entities).map((entity: any) => entity?.name);
465+
expect(entityNamesList.length).to.be.gt(0);
466+
expect(entityNamesList).to.include(${JSON.stringify(entityName)});
467+
`
468+
});
469+
});
470+
321471
it("external file with exported list - shorthand property assignment", async () => {
322472
await testDataSourceFileWithLinkToEntitiesInOtherFile({
323473
entityName,

0 commit comments

Comments
 (0)