Skip to content

Commit 32c625d

Browse files
crisbetodylhunn
authored andcommitted
fix(compiler-cli): handle forwardRef in imports of standalone component (#45869)
Fixes that the compiler wasn't resolving `forwardRef` values when they're used in the `imports` of a standalone component. PR Close #45869
1 parent 10691c6 commit 32c625d

File tree

6 files changed

+161
-41
lines changed

6 files changed

+161
-41
lines changed

packages/compiler-cli/src/ngtsc/annotations/component/src/handler.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import {TypeCheckContext} from '../../../typecheck/api';
2626
import {ExtendedTemplateChecker} from '../../../typecheck/extended/api';
2727
import {getSourceFile} from '../../../util/src/typescript';
2828
import {Xi18nContext} from '../../../xi18n';
29-
import {compileDeclareFactory, compileNgFactoryDefField, compileResults, extractClassMetadata, extractSchemas, findAngularDecorator, getDirectiveDiagnostics, getProviderDiagnostics, isExpressionForwardReference, readBaseClass, resolveEnumValue, resolveImportedFile, resolveLiteral, resolveProvidersRequiringFactory, ResourceLoader, toFactoryMetadata, wrapFunctionExpressionsInParens} from '../../common';
29+
import {compileDeclareFactory, compileNgFactoryDefField, compileResults, extractClassMetadata, extractSchemas, findAngularDecorator, forwardRefResolver, getDirectiveDiagnostics, getProviderDiagnostics, isExpressionForwardReference, readBaseClass, resolveEnumValue, resolveImportedFile, resolveLiteral, resolveProvidersRequiringFactory, ResourceLoader, toFactoryMetadata, wrapFunctionExpressionsInParens} from '../../common';
3030
import {extractDirectiveMetadata, parseFieldArrayValue} from '../../directive';
3131
import {NgModuleSymbol} from '../../ng_module';
3232

@@ -267,7 +267,7 @@ export class ComponentDecoratorHandler implements
267267
isPoisoned = true;
268268
} else if (component.has('imports')) {
269269
const expr = component.get('imports')!;
270-
const imported = this.evaluator.evaluate(expr);
270+
const imported = this.evaluator.evaluate(expr, forwardRefResolver);
271271
const {imports: flattened, diagnostics: importDiagnostics} =
272272
validateAndFlattenComponentImports(imported, expr);
273273

packages/compiler-cli/test/compliance/test_cases/r3_compiler_compliance/components_and_directives/standalone/GOLDEN_PARTIAL.js

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,3 +341,47 @@ export declare class Module {
341341
static ɵinj: i0.ɵɵInjectorDeclaration<Module>;
342342
}
343343

344+
/****************************************************************************************************
345+
* PARTIAL FILE: forward_ref.js
346+
****************************************************************************************************/
347+
import { Component, forwardRef } from '@angular/core';
348+
import * as i0 from "@angular/core";
349+
export class TestComponent {
350+
}
351+
TestComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDER", ngImport: i0, type: TestComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
352+
TestComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "0.0.0-PLACEHOLDER", type: TestComponent, isStandalone: true, selector: "test", ngImport: i0, template: '<other-standalone></other-standalone>', isInline: true, dependencies: [{ kind: "component", type: i0.forwardRef(function () { return StandaloneComponent; }), selector: "other-standalone" }] });
353+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDER", ngImport: i0, type: TestComponent, decorators: [{
354+
type: Component,
355+
args: [{
356+
selector: 'test',
357+
standalone: true,
358+
imports: [forwardRef(() => StandaloneComponent)],
359+
template: '<other-standalone></other-standalone>',
360+
}]
361+
}] });
362+
export class StandaloneComponent {
363+
}
364+
StandaloneComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDER", ngImport: i0, type: StandaloneComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
365+
StandaloneComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "0.0.0-PLACEHOLDER", type: StandaloneComponent, isStandalone: true, selector: "other-standalone", ngImport: i0, template: '', isInline: true });
366+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDER", ngImport: i0, type: StandaloneComponent, decorators: [{
367+
type: Component,
368+
args: [{
369+
selector: 'other-standalone',
370+
standalone: true,
371+
template: '',
372+
}]
373+
}] });
374+
375+
/****************************************************************************************************
376+
* PARTIAL FILE: forward_ref.d.ts
377+
****************************************************************************************************/
378+
import * as i0 from "@angular/core";
379+
export declare class TestComponent {
380+
static ɵfac: i0.ɵɵFactoryDeclaration<TestComponent, never>;
381+
static ɵcmp: i0.ɵɵComponentDeclaration<TestComponent, "test", never, {}, {}, never, never, true>;
382+
}
383+
export declare class StandaloneComponent {
384+
static ɵfac: i0.ɵɵFactoryDeclaration<StandaloneComponent, never>;
385+
static ɵcmp: i0.ɵɵComponentDeclaration<StandaloneComponent, "other-standalone", never, {}, {}, never, never, true>;
386+
}
387+

packages/compiler-cli/test/compliance/test_cases/r3_compiler_compliance/components_and_directives/standalone/TEST_CASES.json

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,20 @@
8484
]
8585
}
8686
]
87+
},
88+
{
89+
"description": "should handle a forwardRef in the imports of a standalone component",
90+
"inputFiles": [
91+
"forward_ref.ts"
92+
],
93+
"expectations": [
94+
{
95+
"failureMessage": "Invalid component definition",
96+
"files": [
97+
"forward_ref.js"
98+
]
99+
}
100+
]
87101
}
88102
]
89103
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
TestComponent.ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({
2+
type: TestComponent,
3+
selectors: [
4+
["test"]
5+
],
6+
standalone: true,
7+
features: [i0.ɵɵStandaloneFeature],
8+
decls: 1,
9+
vars: 0,
10+
template: function TestComponent_Template(rf, ctx) {
11+
if (rf & 1) {
12+
i0.ɵɵelement(0, "other-standalone");
13+
}
14+
},
15+
dependencies: function () {
16+
return [StandaloneComponent];
17+
},
18+
encapsulation: 2
19+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import {Component, forwardRef} from '@angular/core';
2+
3+
@Component({
4+
selector: 'test',
5+
standalone: true,
6+
imports: [forwardRef(() => StandaloneComponent)],
7+
template: '<other-standalone></other-standalone>',
8+
})
9+
export class TestComponent {
10+
}
11+
12+
@Component({
13+
selector: 'other-standalone',
14+
standalone: true,
15+
template: '',
16+
})
17+
export class StandaloneComponent {
18+
}

0 commit comments

Comments
 (0)