diff --git a/packages/bazel/src/ng_module/ng_module.bzl b/packages/bazel/src/ng_module/ng_module.bzl index 6e1d28c959e28e..6d88d18b7ec270 100644 --- a/packages/bazel/src/ng_module/ng_module.bzl +++ b/packages/bazel/src/ng_module/ng_module.bzl @@ -5,7 +5,6 @@ """Run Angular's AOT template compiler """ -load("//packages/bazel/src/ng_module:partial_compilation.bzl", "NgPartialCompilationInfo") load( "//packages/bazel/src:external.bzl", "COMMON_ATTRIBUTES", @@ -23,6 +22,7 @@ load( "ts_providers_dict_to_struct", "tsc_wrapped_tsconfig", ) +load("//packages/bazel/src/ng_module:partial_compilation.bzl", "NgPartialCompilationInfo") # enable_perf_logging controls whether Ivy's performance tracing system will be enabled for any # compilation which includes this provider. @@ -180,6 +180,7 @@ def _ngc_tsconfig(ctx, files, srcs, **kwargs): # for aliased exports. We disable relative paths and always use manifest paths in google3. "_useHostForImportGeneration": (not _is_bazel()), "_useManifestPathsAsModuleName": (not _is_bazel()), + "_isAngularCoreCompilation": ctx.attr.is_angular_core_compilation, } if is_perf_requested(ctx): @@ -474,6 +475,10 @@ NG_MODULE_ATTRIBUTES = { executable = True, cfg = "exec", ), + "is_angular_core_compilation": attr.bool( + default = False, + doc = "Whether this is a compilation of Angular core.", + ), "_partial_compilation_flag": attr.label( default = "//packages/bazel/src:partial_compilation", providers = [NgPartialCompilationInfo], diff --git a/packages/compiler-cli/private/migrations.ts b/packages/compiler-cli/private/migrations.ts index 689d07ca952d8b..28acb9798f5af0 100644 --- a/packages/compiler-cli/private/migrations.ts +++ b/packages/compiler-cli/private/migrations.ts @@ -11,7 +11,7 @@ * package requires for migration schematics. */ -export {forwardRefResolver} from '../src/ngtsc/annotations'; +export {createForwardRefResolver} from '../src/ngtsc/annotations'; export {AbsoluteFsPath} from '../src/ngtsc/file_system'; export {Reference} from '../src/ngtsc/imports'; export { diff --git a/packages/compiler-cli/src/ngtsc/annotations/common/src/evaluation.ts b/packages/compiler-cli/src/ngtsc/annotations/common/src/evaluation.ts index b5fdc2ca041c34..4f302a5bd0f1a7 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/common/src/evaluation.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/common/src/evaluation.ts @@ -22,12 +22,16 @@ export function resolveEnumValue( metadata: Map, field: string, enumSymbolName: string, + isCore: boolean, ): number | null { let resolved: number | null = null; if (metadata.has(field)) { const expr = metadata.get(field)!; const value = evaluator.evaluate(expr) as any; - if (value instanceof EnumValue && isAngularCoreReference(value.enumRef, enumSymbolName)) { + if ( + value instanceof EnumValue && + isAngularCoreReference(value.enumRef, enumSymbolName, isCore) + ) { resolved = value.resolved as number; } else { throw createValueHasWrongTypeError( diff --git a/packages/compiler-cli/src/ngtsc/annotations/common/src/util.ts b/packages/compiler-cli/src/ngtsc/annotations/common/src/util.ts index 533fad06ac1374..e08c8d0c14359a 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/common/src/util.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/common/src/util.ts @@ -107,8 +107,14 @@ export function isAngularCore(decorator: Decorator): decorator is Decorator & {i return decorator.import !== null && decorator.import.from === CORE_MODULE; } -export function isAngularCoreReference(reference: Reference, symbolName: string): boolean { - return reference.ownedByModuleGuess === CORE_MODULE && reference.debugName === symbolName; +export function isAngularCoreReference( + reference: Reference, + symbolName: string, + isCore: boolean, +): boolean { + return ( + (reference.ownedByModuleGuess === CORE_MODULE || isCore) && reference.debugName === symbolName + ); } export function findAngularDecorator( @@ -225,22 +231,19 @@ export function tryUnwrapForwardRef( * @param args the arguments to the invocation of the forwardRef expression * @returns an unwrapped argument if `ref` pointed to forwardRef, or null otherwise */ -export const forwardRefResolver: ForeignFunctionResolver = ( - fn, - callExpr, - resolve, - unresolvable, -) => { - if (!isAngularCoreReference(fn, 'forwardRef') || callExpr.arguments.length !== 1) { - return unresolvable; - } - const expanded = expandForwardRef(callExpr.arguments[0]); - if (expanded !== null) { - return resolve(expanded); - } else { - return unresolvable; - } -}; +export function createForwardRefResolver(isCore: boolean): ForeignFunctionResolver { + return (fn, callExpr, resolve, unresolvable) => { + if (!isAngularCoreReference(fn, 'forwardRef', isCore) || callExpr.arguments.length !== 1) { + return unresolvable; + } + const expanded = expandForwardRef(callExpr.arguments[0]); + if (expanded !== null) { + return resolve(expanded); + } else { + return unresolvable; + } + }; +} /** * Combines an array of resolver functions into a one. diff --git a/packages/compiler-cli/src/ngtsc/annotations/component/src/handler.ts b/packages/compiler-cli/src/ngtsc/annotations/component/src/handler.ts index caa23d7b79189c..b379c593f1f80f 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/component/src/handler.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/component/src/handler.ts @@ -132,11 +132,11 @@ import { compileInputTransformFields, compileNgFactoryDefField, compileResults, + createForwardRefResolver, extractClassDebugInfo, extractClassMetadata, extractSchemas, findAngularDecorator, - forwardRefResolver, getDirectiveDiagnostics, getProviderDiagnostics, InjectableClassRegistry, @@ -492,7 +492,13 @@ export class ComponentDecoratorHandler } = directiveResult; const encapsulation: number = (this.compilationMode !== CompilationMode.LOCAL - ? resolveEnumValue(this.evaluator, component, 'encapsulation', 'ViewEncapsulation') + ? resolveEnumValue( + this.evaluator, + component, + 'encapsulation', + 'ViewEncapsulation', + this.isCore, + ) : resolveEncapsulationEnumValueLocally(component.get('encapsulation'))) ?? ViewEncapsulation.Emulated; @@ -503,6 +509,7 @@ export class ComponentDecoratorHandler component, 'changeDetection', 'ChangeDetectionStrategy', + this.isCore, ); } else if (component.has('changeDetection')) { changeDetection = new o.WrappedNodeExpr(component.get('changeDetection')!); @@ -597,7 +604,7 @@ export class ComponentDecoratorHandler ) { const importResolvers = combineResolvers([ createModuleWithProvidersResolver(this.reflector, this.isCore), - forwardRefResolver, + createForwardRefResolver(this.isCore), ]); const importDiagnostics: ts.Diagnostic[] = []; diff --git a/packages/compiler-cli/src/ngtsc/annotations/directive/src/shared.ts b/packages/compiler-cli/src/ngtsc/annotations/directive/src/shared.ts index 93d26886f74eab..a8990d99b62e3e 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/directive/src/shared.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/directive/src/shared.ts @@ -47,6 +47,7 @@ import { import { DynamicValue, EnumValue, + ForeignFunctionResolver, PartialEvaluator, ResolvedValue, traceDynamicValue, @@ -65,9 +66,9 @@ import { import {CompilationMode} from '../../../transform'; import { assertLocalCompilationUnresolvedConst, + createForwardRefResolver, createSourceSpan, createValueHasWrongTypeError, - forwardRefResolver, getAngularDecorators, getConstructorDependencies, isAngularDecorator, @@ -373,7 +374,12 @@ export function extractDirectiveMetadata( const hostDirectives = rawHostDirectives === null ? null - : extractHostDirectives(rawHostDirectives, evaluator, compilationMode); + : extractHostDirectives( + rawHostDirectives, + evaluator, + compilationMode, + createForwardRefResolver(isCore), + ); if (compilationMode !== CompilationMode.LOCAL && hostDirectives !== null) { // In global compilation mode where we do type checking, the template type-checker will need to @@ -1672,6 +1678,7 @@ function extractHostDirectives( rawHostDirectives: ts.Expression, evaluator: PartialEvaluator, compilationMode: CompilationMode, + forwardRefResolver: ForeignFunctionResolver, ): HostDirectiveMeta[] { const resolved = evaluator.evaluate(rawHostDirectives, forwardRefResolver); if (!Array.isArray(resolved)) { diff --git a/packages/compiler-cli/src/ngtsc/annotations/index.ts b/packages/compiler-cli/src/ngtsc/annotations/index.ts index 742ff6dcd57d4e..f1ed6df6a09a76 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/index.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/index.ts @@ -9,7 +9,7 @@ /// export { - forwardRefResolver, + createForwardRefResolver, findAngularDecorator, getAngularDecorators, isAngularDecorator, diff --git a/packages/compiler-cli/src/ngtsc/annotations/ng_module/src/handler.ts b/packages/compiler-cli/src/ngtsc/annotations/ng_module/src/handler.ts index 1cfb85862b9241..9c70fcd11bc0b0 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/ng_module/src/handler.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/ng_module/src/handler.ts @@ -91,11 +91,11 @@ import { combineResolvers, compileDeclareFactory, compileNgFactoryDefField, + createForwardRefResolver, createValueHasWrongTypeError, extractClassMetadata, extractSchemas, findAngularDecorator, - forwardRefResolver, getProviderDiagnostics, getValidConstructorDependencies, InjectableClassRegistry, @@ -348,6 +348,7 @@ export class NgModuleDecoratorHandler return {}; } + const forwardRefResolver = createForwardRefResolver(this.isCore); const moduleResolvers = combineResolvers([ createModuleWithProvidersResolver(this.reflector, this.isCore), forwardRefResolver, diff --git a/packages/compiler-cli/src/ngtsc/core/api/src/options.ts b/packages/compiler-cli/src/ngtsc/core/api/src/options.ts index 99ea91f02bceb4..6740d2210da6e0 100644 --- a/packages/compiler-cli/src/ngtsc/core/api/src/options.ts +++ b/packages/compiler-cli/src/ngtsc/core/api/src/options.ts @@ -126,6 +126,15 @@ export interface InternalOptions { * Whether to check the event side of two-way bindings. */ _checkTwoWayBoundEvents?: boolean; + + /** + * Whether this is a compilation of Angular core itself. + * + * By default, we detect this automatically based on the existence of `r3_symbols.ts` + * in the compilation, but there are other test targets within the `core` package that + * import e.g. `Component` relatively and should be detected by the compiler. + */ + _isAngularCoreCompilation?: boolean; } /** diff --git a/packages/compiler-cli/src/ngtsc/core/src/compiler.ts b/packages/compiler-cli/src/ngtsc/core/src/compiler.ts index 7ecdbbe2768f12..acdc2f523c2e58 100644 --- a/packages/compiler-cli/src/ngtsc/core/src/compiler.ts +++ b/packages/compiler-cli/src/ngtsc/core/src/compiler.ts @@ -1257,7 +1257,8 @@ export class NgCompiler { } private makeCompilation(): LazyCompilationState { - const isCore = isAngularCorePackage(this.inputProgram); + const isCore = + this.options._isAngularCoreCompilation ?? isAngularCorePackage(this.inputProgram); // Note: If this compilation builds `@angular/core`, we always build in full compilation // mode. Code inside the core package is always compatible with itself, so it does not diff --git a/tools/defaults.bzl b/tools/defaults.bzl index 035dfab56ba47d..1c510a0e826c79 100644 --- a/tools/defaults.bzl +++ b/tools/defaults.bzl @@ -1,26 +1,26 @@ """Re-export of some bazel rules with repository-wide defaults.""" -load("@rules_pkg//:pkg.bzl", "pkg_tar") load("@build_bazel_rules_nodejs//:index.bzl", "generated_file_test", _npm_package_bin = "npm_package_bin", _pkg_npm = "pkg_npm") -load("@npm//@bazel/jasmine:index.bzl", _jasmine_node_test = "jasmine_node_test") -load("@npm//@bazel/concatjs:index.bzl", _ts_config = "ts_config", _ts_library = "ts_library") -load("@npm//@bazel/rollup:index.bzl", _rollup_bundle = "rollup_bundle") -load("@npm//@bazel/terser:index.bzl", "terser_minified") -load("@npm//@bazel/protractor:index.bzl", _protractor_web_test_suite = "protractor_web_test_suite") -load("@npm//typescript:index.bzl", "tsc") -load("@npm//@angular/build-tooling/bazel/app-bundling:index.bzl", _app_bundle = "app_bundle") -load("@npm//@angular/build-tooling/bazel/http-server:index.bzl", _http_server = "http_server") -load("@npm//@angular/build-tooling/bazel/karma:index.bzl", _karma_web_test = "karma_web_test", _karma_web_test_suite = "karma_web_test_suite") -load("@npm//@angular/build-tooling/bazel/api-golden:index.bzl", _api_golden_test = "api_golden_test", _api_golden_test_npm_package = "api_golden_test_npm_package") load("@npm//@angular/build-tooling/bazel:extract_js_module_output.bzl", "extract_js_module_output") load("@npm//@angular/build-tooling/bazel:extract_types.bzl", _extract_types = "extract_types") +load("@npm//@angular/build-tooling/bazel/api-golden:index.bzl", _api_golden_test = "api_golden_test", _api_golden_test_npm_package = "api_golden_test_npm_package") +load("@npm//@angular/build-tooling/bazel/app-bundling:index.bzl", _app_bundle = "app_bundle") load("@npm//@angular/build-tooling/bazel/esbuild:index.bzl", _esbuild = "esbuild", _esbuild_config = "esbuild_config", _esbuild_esm_bundle = "esbuild_esm_bundle") -load("@npm//@angular/build-tooling/bazel/spec-bundling:spec-entrypoint.bzl", "spec_entrypoint") +load("@npm//@angular/build-tooling/bazel/http-server:index.bzl", _http_server = "http_server") +load("@npm//@angular/build-tooling/bazel/karma:index.bzl", _karma_web_test = "karma_web_test", _karma_web_test_suite = "karma_web_test_suite") load("@npm//@angular/build-tooling/bazel/spec-bundling:index.bzl", "spec_bundle") +load("@npm//@angular/build-tooling/bazel/spec-bundling:spec-entrypoint.bzl", "spec_entrypoint") +load("@npm//@bazel/concatjs:index.bzl", _ts_config = "ts_config", _ts_library = "ts_library") +load("@npm//@bazel/jasmine:index.bzl", _jasmine_node_test = "jasmine_node_test") +load("@npm//@bazel/protractor:index.bzl", _protractor_web_test_suite = "protractor_web_test_suite") +load("@npm//@bazel/rollup:index.bzl", _rollup_bundle = "rollup_bundle") +load("@npm//@bazel/terser:index.bzl", "terser_minified") load("@npm//tsec:index.bzl", _tsec_test = "tsec_test") +load("@npm//typescript:index.bzl", "tsc") +load("@rules_pkg//:pkg.bzl", "pkg_tar") +load("//adev/shared-docs/pipeline/api-gen:generate_api_docs.bzl", _generate_api_docs = "generate_api_docs") load("//packages/bazel:index.bzl", _ng_module = "ng_module", _ng_package = "ng_package") load("//tools/esm-interop:index.bzl", "enable_esm_node_module_loader", _nodejs_binary = "nodejs_binary", _nodejs_test = "nodejs_test") -load("//adev/shared-docs/pipeline/api-gen:generate_api_docs.bzl", _generate_api_docs = "generate_api_docs") _DEFAULT_TSCONFIG_TEST = "//packages:tsconfig-test" _INTERNAL_NG_MODULE_COMPILER = "//packages/bazel/src/ngc-wrapped" @@ -170,6 +170,11 @@ def ng_module(name, tsconfig = None, entry_point = None, testonly = False, deps if not entry_point: entry_point = "public_api.ts" + + is_angular_core_compilation = False + if native.package_name().startswith("packages/core"): + is_angular_core_compilation = True + _ng_module( name = name, flat_module_out_file = name, @@ -184,6 +189,7 @@ def ng_module(name, tsconfig = None, entry_point = None, testonly = False, deps # `package_name` can be set to allow for the Bazel NodeJS linker to run. This # allows for resolution of the given target within the `node_modules/`. package_name = package_name, + is_angular_core_compilation = is_angular_core_compilation, perf_flag = "//packages/compiler-cli:ng_perf", **kwargs )