Skip to content

Commit 616b411

Browse files
pkozlowski-opensourcealxhub
authored andcommitted
fix(migrations): properly migrate output aliases (#58411)
Before this fix the output migration was incorrectly assuming that the @output decorator takes its params as an object. What happens in reality is that the @output decorator is taking alias as the only argument, without any object literal wrapper. PR Close #58411
1 parent d504452 commit 616b411

File tree

3 files changed

+35
-27
lines changed

3 files changed

+35
-27
lines changed

packages/core/schematics/migrations/output-migration/output-migration.spec.ts

Lines changed: 5 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -42,34 +42,22 @@ describe('outputs', () => {
4242

4343
it('should take alias into account', async () => {
4444
await verifyDeclaration({
45-
before: `@Output({alias: 'otherChange'}) readonly someChange = new EventEmitter();`,
45+
before: `@Output('otherChange') readonly someChange = new EventEmitter();`,
4646
after: `readonly someChange = output({ alias: 'otherChange' });`,
4747
});
4848
});
4949

50-
it('should support alias as statically analyzable reference', async () => {
51-
await verify({
52-
before: `
50+
it('should not migrate aliases that do not evaluate to static string', async () => {
51+
await verifyNoChange(`
5352
import {Directive, Output, EventEmitter} from '@angular/core';
5453
55-
const aliasParam = { alias: 'otherChange' } as const;
54+
const someConst = 'otherChange' as const;
5655
5756
@Directive()
5857
export class TestDir {
5958
@Output(aliasParam) someChange = new EventEmitter();
6059
}
61-
`,
62-
after: `
63-
import {Directive, output} from '@angular/core';
64-
65-
const aliasParam = { alias: 'otherChange' } as const;
66-
67-
@Directive()
68-
export class TestDir {
69-
readonly someChange = output(aliasParam);
70-
}
71-
`,
72-
});
60+
`);
7361
});
7462

7563
it('should add readonly modifier', async () => {

packages/core/schematics/migrations/output-migration/output-migration.ts

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -148,13 +148,21 @@ export class OutputMigration extends TsurgeFunnelMigration<
148148
outputFile,
149149
)
150150
) {
151-
filesWithOutputDeclarations.add(node.getSourceFile());
152-
addOutputReplacement(
153-
outputFieldReplacements,
154-
outputDef.id,
155-
outputFile,
156-
calculateDeclarationReplacement(info, node, outputDef.aliasParam),
157-
);
151+
const aliasParam = outputDef.aliasParam;
152+
const aliasOptionValue = aliasParam ? evaluator.evaluate(aliasParam) : undefined;
153+
154+
if (aliasOptionValue == undefined || typeof aliasOptionValue === 'string') {
155+
filesWithOutputDeclarations.add(node.getSourceFile());
156+
addOutputReplacement(
157+
outputFieldReplacements,
158+
outputDef.id,
159+
outputFile,
160+
calculateDeclarationReplacement(info, node, aliasOptionValue?.toString()),
161+
);
162+
} else {
163+
problematicUsages[outputDef.id] = true;
164+
problematicDeclarationCount++;
165+
}
158166
}
159167
} else {
160168
problematicDeclarationCount++;

packages/core/schematics/migrations/output-migration/output-replacements.ts

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
import ts from 'typescript';
1010

11-
import {ImportManager} from '../../../../compiler-cli/private/migrations';
11+
import {ImportManager, PartialEvaluator} from '../../../../compiler-cli/private/migrations';
1212
import {
1313
ProgramInfo,
1414
ProjectFile,
@@ -25,7 +25,7 @@ const printer = ts.createPrinter();
2525
export function calculateDeclarationReplacement(
2626
info: ProgramInfo,
2727
node: ts.PropertyDeclaration,
28-
aliasParam?: ts.Expression,
28+
aliasParam?: string,
2929
): Replacement {
3030
const sf = node.getSourceFile();
3131
const payloadTypes =
@@ -36,7 +36,19 @@ export function calculateDeclarationReplacement(
3636
const outputCall = ts.factory.createCallExpression(
3737
ts.factory.createIdentifier('output'),
3838
payloadTypes,
39-
aliasParam ? [aliasParam] : [],
39+
aliasParam !== undefined
40+
? [
41+
ts.factory.createObjectLiteralExpression(
42+
[
43+
ts.factory.createPropertyAssignment(
44+
'alias',
45+
ts.factory.createStringLiteral(aliasParam, true),
46+
),
47+
],
48+
false,
49+
),
50+
]
51+
: [],
4052
);
4153

4254
const existingModifiers = (node.modifiers ?? []).filter(

0 commit comments

Comments
 (0)