Skip to content

Commit 0cf1001

Browse files
Jonathan MeierthePunderWoman
authored andcommitted
feat(compiler-cli): support host directives with direct external references in fast type declaration emission (#61469)
In the initial implementation for experimental fast type declaration emission introduced in e62fb35, external references in host directives were not supported at all. This change adds support for direct external references in host directives. Any other expressions indirectly using external references are still not supported. PR Close #61469
1 parent ba66a12 commit 0cf1001

3 files changed

Lines changed: 385 additions & 22 deletions

File tree

packages/compiler-cli/src/ngtsc/annotations/directive/src/shared.ts

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
emitDistinctChangesOnlyDefaultValue,
1212
Expression,
1313
ExternalExpr,
14+
ExternalReference,
1415
ForwardRefHandling,
1516
getSafePropertyAccessString,
1617
MaybeForwardRefExpression,
@@ -395,6 +396,7 @@ export function extractDirectiveMetadata(
395396
: extractHostDirectives(
396397
rawHostDirectives,
397398
evaluator,
399+
reflector,
398400
compilationMode,
399401
createForwardRefResolver(isCore),
400402
emitDeclarationOnly,
@@ -1733,6 +1735,7 @@ function getHostBindingErrorNode(error: ParseError, hostExpr: ts.Expression): ts
17331735
function extractHostDirectives(
17341736
rawHostDirectives: ts.Expression,
17351737
evaluator: PartialEvaluator,
1738+
reflector: ReflectionHost,
17361739
compilationMode: CompilationMode,
17371740
forwardRefResolver: ForeignFunctionResolver,
17381741
emitDeclarationOnly: boolean,
@@ -1768,7 +1771,7 @@ function extractHostDirectives(
17681771
}
17691772
}
17701773

1771-
let directive: Reference<ClassDeclaration> | Expression;
1774+
let directive: Reference<ClassDeclaration> | Expression | ExternalReference;
17721775
let nameForErrors = (fieldName: string) => '@Directive.hostDirectives';
17731776
if (compilationMode === CompilationMode.LOCAL && hostReference instanceof DynamicValue) {
17741777
// At the moment in local compilation we only support simple array for host directives, i.e.,
@@ -1780,22 +1783,38 @@ function extractHostDirectives(
17801783
!ts.isIdentifier(hostReference.node) &&
17811784
!ts.isPropertyAccessExpression(hostReference.node)
17821785
) {
1786+
const compilationModeName = emitDeclarationOnly
1787+
? 'experimental declaration-only emission'
1788+
: 'local compilation';
17831789
throw new FatalDiagnosticError(
17841790
ErrorCode.LOCAL_COMPILATION_UNSUPPORTED_EXPRESSION,
17851791
hostReference.node,
1786-
`In local compilation mode, host directive cannot be an expression. Use an identifier instead`,
1792+
`In ${compilationModeName} mode, host directive cannot be an expression. Use an identifier instead`,
17871793
);
17881794
}
17891795

17901796
if (emitDeclarationOnly) {
1791-
throw new FatalDiagnosticError(
1792-
ErrorCode.LOCAL_COMPILATION_UNSUPPORTED_EXPRESSION,
1793-
hostReference.node,
1794-
'External references in host directives are not supported in experimental declaration-only emission mode',
1795-
);
1797+
if (ts.isIdentifier(hostReference.node)) {
1798+
const importInfo = reflector.getImportOfIdentifier(hostReference.node);
1799+
if (importInfo) {
1800+
directive = new ExternalReference(importInfo.from, importInfo.name);
1801+
} else {
1802+
throw new FatalDiagnosticError(
1803+
ErrorCode.LOCAL_COMPILATION_UNSUPPORTED_EXPRESSION,
1804+
hostReference.node,
1805+
`In experimental declaration-only emission mode, host directive cannot use indirect external indentifiers. Use a direct external identifier instead`,
1806+
);
1807+
}
1808+
} else {
1809+
throw new FatalDiagnosticError(
1810+
ErrorCode.LOCAL_COMPILATION_UNSUPPORTED_EXPRESSION,
1811+
hostReference.node,
1812+
`In experimental declaration-only emission mode, host directive cannot be an expression. Use an identifier instead`,
1813+
);
1814+
}
1815+
} else {
1816+
directive = new WrappedNodeExpr(hostReference.node);
17961817
}
1797-
1798-
directive = new WrappedNodeExpr(hostReference.node);
17991818
} else if (hostReference instanceof Reference) {
18001819
directive = hostReference as Reference<ClassDeclaration>;
18011820
nameForErrors = (fieldName: string) =>
@@ -1865,6 +1884,11 @@ function toHostDirectiveMetadata(
18651884
context,
18661885
refEmitter,
18671886
);
1887+
} else if (hostDirective.directive instanceof ExternalReference) {
1888+
directive = {
1889+
value: new ExternalExpr(hostDirective.directive),
1890+
type: new ExternalExpr(hostDirective.directive),
1891+
};
18681892
} else {
18691893
directive = {
18701894
value: hostDirective.directive,

packages/compiler-cli/src/ngtsc/metadata/src/api.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,12 @@
66
* found in the LICENSE file at https://angular.dev/license
77
*/
88

9-
import {DirectiveMeta as T2DirectiveMeta, Expression, SchemaMetadata} from '@angular/compiler';
9+
import {
10+
DirectiveMeta as T2DirectiveMeta,
11+
Expression,
12+
SchemaMetadata,
13+
ExternalReference,
14+
} from '@angular/compiler';
1015
import ts from 'typescript';
1116

1217
import {Reference} from '../../imports';
@@ -305,7 +310,7 @@ export interface HostDirectiveMeta {
305310
* which indicates the expression could not be resolved due to being imported from some external
306311
* file. In this case, the expression is the raw expression as appears in the decorator.
307312
*/
308-
directive: Reference<ClassDeclaration> | Expression;
313+
directive: Reference<ClassDeclaration> | Expression | ExternalReference;
309314

310315
/** Whether the reference to the host directive is a forward reference. */
311316
isForwardReference: boolean;

0 commit comments

Comments
 (0)