Skip to content

Commit

Permalink
fix(compiler-cli): show proper error for custom decorators in local c…
Browse files Browse the repository at this point in the history
…ompilation mode

At the moment local compilation mode does not support custom decorators, and it leads to unhandled errors. In this change a compile time diagnostic is produced in local mode for custom decorators. This is a temporary solution since there are few custom decorators are in use in g3. Custom decorators will be eventually supported in local mode.
  • Loading branch information
pmvald committed Jan 26, 2024
1 parent c3b0095 commit a8ee355
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 0 deletions.
26 changes: 26 additions & 0 deletions packages/compiler-cli/src/ngtsc/transform/src/compilation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -259,12 +259,21 @@ export class TraitCompiler implements ProgramTypeCheckAdapter {
let record: ClassRecord|null = this.recordFor(clazz);
let foundTraits: PendingTrait<unknown, unknown, SemanticSymbol|null, unknown>[] = [];

// A set to track the non-Angular decorators in local compilation mode. An error will be issued
// if non-Angular decorators is found in local compilation mode.
const nonNgDecoratorsInLocalMode =
this.compilationMode === CompilationMode.LOCAL ? new Set(decorators) : null;

for (const handler of this.handlers) {
const result = handler.detect(clazz, decorators);
if (result === undefined) {
continue;
}

if (nonNgDecoratorsInLocalMode !== null && result.decorator !== null) {
nonNgDecoratorsInLocalMode.delete(result.decorator);
}

const isPrimaryHandler = handler.precedence === HandlerPrecedence.PRIMARY;
const isWeakHandler = handler.precedence === HandlerPrecedence.WEAK;
const trait = Trait.pending(handler, result);
Expand Down Expand Up @@ -332,6 +341,23 @@ export class TraitCompiler implements ProgramTypeCheckAdapter {
}
}

if (nonNgDecoratorsInLocalMode !== null && nonNgDecoratorsInLocalMode.size > 0 &&
record !== null && record.metaDiagnostics === null) {
// Custom decorators found in local compilation mode! In this mode we don't support custom
// decorators yet. But will eventually do (b/320536434). For now a temporary error is thrown.
record.metaDiagnostics = [...nonNgDecoratorsInLocalMode].map(
decorator => ({
category: ts.DiagnosticCategory.Error,
code: Number('-99' + ErrorCode.DECORATOR_UNEXPECTED),
file: getSourceFile(clazz),
start: decorator.node.getStart(),
length: decorator.node.getWidth(),
messageText:
'In local compilation mode, Angular does not support custom decorators. Ensure all class decorators are from Angular.',
}));
record.traits = foundTraits = [];
}

return foundTraits.length > 0 ? foundTraits : null;
}

Expand Down
31 changes: 31 additions & 0 deletions packages/compiler-cli/test/ngtsc/local_compilation_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1734,5 +1734,36 @@ runInEachFileSystem(
}
});
});

describe('custom decorator', () => {
it('should produce diagnostic for each custom decorator', () => {
env.write('test.ts', `
import {Component} from '@angular/core';
import {customDecorator1, customDecorator2} from './some-where';
@customDecorator1('hello')
@Component({
template: ExternalString,
})
@customDecorator2
export class Main {
}
`);

const errors = env.driveDiagnostics();

expect(errors.length).toBe(2);

const text1 = ts.flattenDiagnosticMessageText(errors[0].messageText, '\n');
const text2 = ts.flattenDiagnosticMessageText(errors[1].messageText, '\n');

expect(errors[0].code).toBe(ngErrorCode(ErrorCode.DECORATOR_UNEXPECTED));
expect(errors[1].code).toBe(ngErrorCode(ErrorCode.DECORATOR_UNEXPECTED));
expect(text1).toContain(
'In local compilation mode, Angular does not support custom decorators');
expect(text2).toContain(
'In local compilation mode, Angular does not support custom decorators');
});
});
});
});

0 comments on commit a8ee355

Please sign in to comment.