fix(ngcc): insert definitions after statement (#34677)

If a class was defined as a class expression
in a variable declaration, the definitions
were being inserted before the statment's
final semi-colon.

Now the insertion point will be after the
full statement.

Fixes #34648

PR Close #34677
This commit is contained in:
Pete Bacon Darwin 2020-01-08 15:03:30 +00:00 committed by Alex Rickabaugh
parent 9f65b787d0
commit 8815ace418
2 changed files with 31 additions and 3 deletions

View File

@ -102,7 +102,8 @@ export class EsmRenderingFormatter implements RenderingFormatter {
if (!classSymbol) { if (!classSymbol) {
throw new Error(`Compiled class does not have a valid symbol: ${compiledClass.name}`); throw new Error(`Compiled class does not have a valid symbol: ${compiledClass.name}`);
} }
const insertionPoint = classSymbol.declaration.valueDeclaration.getEnd(); const declarationStatement = getDeclarationStatement(classSymbol.declaration.valueDeclaration);
const insertionPoint = declarationStatement.getEnd();
output.appendLeft(insertionPoint, '\n' + definitions); output.appendLeft(insertionPoint, '\n' + definitions);
} }
@ -273,7 +274,18 @@ export class EsmRenderingFormatter implements RenderingFormatter {
} }
} }
function findStatement(node: ts.Node) { function getDeclarationStatement(node: ts.Node): ts.Statement {
let statement = node;
while (statement) {
if (ts.isVariableStatement(statement) || ts.isClassDeclaration(statement)) {
return statement;
}
statement = statement.parent;
}
throw new Error(`Class is not defined in a declaration statement: ${node.getText()}`);
}
function findStatement(node: ts.Node): ts.Statement|undefined {
while (node) { while (node) {
if (ts.isExpressionStatement(node) || ts.isReturnStatement(node)) { if (ts.isExpressionStatement(node) || ts.isReturnStatement(node)) {
return node; return node;

View File

@ -74,10 +74,12 @@ B.decorators = [
{ type: OtherB }, { type: OtherB },
{ type: Directive, args: [{ selector: '[b]' }] } { type: Directive, args: [{ selector: '[b]' }] }
]; ];
export class C {} var C_1;
let C = C_1 = class C {};
C.decorators = [ C.decorators = [
{ type: Directive, args: [{ selector: '[c]' }] }, { type: Directive, args: [{ selector: '[c]' }] },
]; ];
export C;
let compileNgModuleFactory = compileNgModuleFactory__PRE_R3__; let compileNgModuleFactory = compileNgModuleFactory__PRE_R3__;
let badlyFormattedVariable = __PRE_R3__badlyFormattedVariable; let badlyFormattedVariable = __PRE_R3__badlyFormattedVariable;
@ -220,6 +222,20 @@ export class A {`);
export class A {} export class A {}
SOME DEFINITION TEXT SOME DEFINITION TEXT
A.decorators = [ A.decorators = [
`);
});
it('should insert the definitions after the variable declaration of class expressions',
() => {
const {renderer, decorationAnalyses, sourceFile} = setup([PROGRAM]);
const output = new MagicString(PROGRAM.contents);
const compiledClass =
decorationAnalyses.get(sourceFile) !.compiledClasses.find(c => c.name === 'C') !;
renderer.addDefinitions(output, compiledClass, 'SOME DEFINITION TEXT');
expect(output.toString()).toContain(`
let C = C_1 = class C {};
SOME DEFINITION TEXT
C.decorators = [
`); `);
}); });
}); });