From f3c093df24b7c87e4caee51a10a070a2baab2f34 Mon Sep 17 00:00:00 2001 From: Kristiyan Kostadinov Date: Thu, 20 Aug 2026 10:43:58 +0200 Subject: [PATCH] refactor(compiler-cli): add compiler option for enabling source locations Adds an internal config options that allows us to enable source locations. --- .../compiler-cli/compiler_options.api.md | 1 + .../partial_component_linker_1.ts | 1 + .../annotations/component/src/handler.ts | 2 ++ .../component/test/component_spec.ts | 1 + .../src/ngtsc/core/api/src/public_options.ts | 9 +++++- .../src/ngtsc/core/src/compiler.ts | 3 ++ .../test/ngtsc/attach_source_location_spec.ts | 29 +++++++++++++++---- packages/compiler/src/compiler.ts | 1 - packages/compiler/src/jit_compiler_facade.ts | 2 ++ packages/compiler/src/render3/view/api.ts | 10 +++++-- .../compiler/src/render3/view/compiler.ts | 4 +-- packages/compiler/src/render3/view/config.ts | 14 +-------- 12 files changed, 52 insertions(+), 25 deletions(-) diff --git a/goldens/public-api/compiler-cli/compiler_options.api.md b/goldens/public-api/compiler-cli/compiler_options.api.md index 84f01a5a265..e560e1f7e7f 100644 --- a/goldens/public-api/compiler-cli/compiler_options.api.md +++ b/goldens/public-api/compiler-cli/compiler_options.api.md @@ -7,6 +7,7 @@ // @public export interface BazelAndG3Options { annotateForClosureCompiler?: boolean; + enableTemplateSourceLocations?: boolean; _experimentalAllowEmitDeclarationOnly?: boolean; generateDeepReexports?: boolean; generateExtraImportsInLocalMode?: boolean; diff --git a/packages/compiler-cli/linker/src/file_linker/partial_linkers/partial_component_linker_1.ts b/packages/compiler-cli/linker/src/file_linker/partial_linkers/partial_component_linker_1.ts index cb78ec15134..2b86a517c68 100644 --- a/packages/compiler-cli/linker/src/file_linker/partial_linkers/partial_component_linker_1.ts +++ b/packages/compiler-cli/linker/src/file_linker/partial_linkers/partial_component_linker_1.ts @@ -255,6 +255,7 @@ export class PartialComponentLinkerVersion1< declarations, hasDirectiveDependencies: !baseMeta.isStandalone || hasDirectiveDependencies, foreignImports: null, + enableTemplateSourceLocations: false, }; } 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 8ca2b49ec7b..13c9baa4047 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/component/src/handler.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/component/src/handler.ts @@ -291,6 +291,7 @@ export class ComponentDecoratorHandler implements DecoratorHandler< private readonly enableSelectorless: boolean, private readonly emitDeclarationOnly: boolean, private readonly legacyOptionalChaining: boolean, + private readonly enableTemplateSourceLocations: boolean, ) { this.extractTemplateOptions = { enableI18nLegacyMessageIdFormat: this.enableI18nLegacyMessageIdFormat, @@ -1037,6 +1038,7 @@ export class ComponentDecoratorHandler implements DecoratorHandler< rawImports: rawImports !== null ? new o.WrappedNodeExpr(rawImports) : undefined, relativeTemplatePath, foreignImports: null, + enableTemplateSourceLocations: this.enableTemplateSourceLocations, }, typeCheckMeta: extractDirectiveTypeCheckMeta(node, inputs, this.reflector), classMetadata: this.includeClassMetadata diff --git a/packages/compiler-cli/src/ngtsc/annotations/component/test/component_spec.ts b/packages/compiler-cli/src/ngtsc/annotations/component/test/component_spec.ts index 3d43ac0fe15..33f024c4402 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/component/test/component_spec.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/component/test/component_spec.ts @@ -164,6 +164,7 @@ function setup( /* enableSelectorless */ false, /* emitDeclarationOnly */ false, /* enableInlineStyles */ true, + /* enableTemplateSourceLocations */ false, ); return {reflectionHost, handler, resourceLoader, metaRegistry}; } diff --git a/packages/compiler-cli/src/ngtsc/core/api/src/public_options.ts b/packages/compiler-cli/src/ngtsc/core/api/src/public_options.ts index 340178ca2c5..f811c4fa3ba 100644 --- a/packages/compiler-cli/src/ngtsc/core/api/src/public_options.ts +++ b/packages/compiler-cli/src/ngtsc/core/api/src/public_options.ts @@ -340,11 +340,18 @@ export interface BazelAndG3Options { _experimentalAllowEmitDeclarationOnly?: boolean; /** - * Whether to follow the Javascript optional chaining specs: returning `undefined` instead of `null` for null-safe navigation operations. + * Whether to follow the Javascript optional chaining specs: returning `undefined` instead of + * `null` for null-safe navigation operations. * * Defaults to `false`. */ legacyOptionalChaining?: boolean; + + /** + * Whether to generate additional code that adds the source location + * of elements to the DOM as an attribute. + */ + enableTemplateSourceLocations?: boolean; } /** diff --git a/packages/compiler-cli/src/ngtsc/core/src/compiler.ts b/packages/compiler-cli/src/ngtsc/core/src/compiler.ts index fed0edec07b..4bee79965b1 100644 --- a/packages/compiler-cli/src/ngtsc/core/src/compiler.ts +++ b/packages/compiler-cli/src/ngtsc/core/src/compiler.ts @@ -397,6 +397,7 @@ export class NgCompiler { private readonly implicitStandaloneValue: boolean; private readonly enableSelectorless: boolean; private readonly emitDeclarationOnly: boolean; + private readonly enableTemplateSourceLocations: boolean; /** * `NgCompiler` can be reused for multiple compilations (for resource-only changes), and each @@ -472,6 +473,7 @@ export class NgCompiler { this.angularCoreVersion === null || coreVersionSupportsFeature(this.angularCoreVersion, '>= 18.1.0'); this.enableSelectorless = options['_enableSelectorless'] ?? false; + this.enableTemplateSourceLocations = options['enableTemplateSourceLocations'] ?? false; this.emitDeclarationOnly = !!options.emitDeclarationOnly && !!options._experimentalAllowEmitDeclarationOnly; // Standalone by default is enabled since v19. We need to toggle it here, @@ -1549,6 +1551,7 @@ export class NgCompiler { this.enableSelectorless, this.emitDeclarationOnly, this.options.legacyOptionalChaining ?? LEGACY_OPTIONAL_CHAINING_DEFAULT, + this.enableTemplateSourceLocations, ), // TODO(alxhub): understand why the cast here is necessary (something to do with `null` diff --git a/packages/compiler-cli/test/ngtsc/attach_source_location_spec.ts b/packages/compiler-cli/test/ngtsc/attach_source_location_spec.ts index 98b2f54bb09..f0fd8b126d3 100644 --- a/packages/compiler-cli/test/ngtsc/attach_source_location_spec.ts +++ b/packages/compiler-cli/test/ngtsc/attach_source_location_spec.ts @@ -6,7 +6,6 @@ * found in the LICENSE file at https://angular.dev/license */ -import {setEnableTemplateSourceLocations} from '@angular/compiler'; import {runInEachFileSystem} from '../../src/ngtsc/file_system/testing'; import {loadStandardTestFiles} from '../../src/ngtsc/testing'; import {NgtscTestEnvironment} from './env'; @@ -18,16 +17,33 @@ runInEachFileSystem(() => { let env!: NgtscTestEnvironment; beforeEach(() => { - setEnableTemplateSourceLocations(true); env = NgtscTestEnvironment.setup(testFiles); - env.tsconfig(); }); - afterEach(() => { - setEnableTemplateSourceLocations(false); + it('should not attach template source locations by default', () => { + env.tsconfig(); + env.write( + `test.ts`, + ` + import {Component} from '@angular/core'; + + @Component({ + template: \` +
+ Hello +
+ \`, + }) + class Comp {} + `, + ); + env.driveMain(); + const content = env.getContents('test.js'); + expect(content).not.toContain('ɵɵattachSourceLocations'); }); it('should attach the source location in an inline template', () => { + env.tsconfig({enableTemplateSourceLocations: true}); env.write( `test.ts`, ` @@ -52,6 +68,7 @@ runInEachFileSystem(() => { }); it('should attach the source location in an external template', () => { + env.tsconfig({enableTemplateSourceLocations: true}); env.write( 'test.html', ` @@ -79,6 +96,7 @@ runInEachFileSystem(() => { }); it('should attach the source location to structural directives', () => { + env.tsconfig({enableTemplateSourceLocations: true}); env.write( `test.ts`, ` @@ -107,6 +125,7 @@ runInEachFileSystem(() => { }); it('should not attach the source location to ng-container', () => { + env.tsconfig({enableTemplateSourceLocations: true}); env.write( `test.ts`, ` diff --git a/packages/compiler/src/compiler.ts b/packages/compiler/src/compiler.ts index d4b59dbf793..f033b185b97 100644 --- a/packages/compiler/src/compiler.ts +++ b/packages/compiler/src/compiler.ts @@ -265,7 +265,6 @@ export {outputAst}; export {CompilerFacadeImpl} from './jit_compiler_facade'; export {FactoryTarget} from './compiler_facade_interface'; export {QueryFlags} from './render3/view/query_generation'; -export {setEnableTemplateSourceLocations} from './render3/view/config'; export * from './typecheck/api'; export * from './typecheck/host_bindings'; diff --git a/packages/compiler/src/jit_compiler_facade.ts b/packages/compiler/src/jit_compiler_facade.ts index a154df165aa..05316a7d045 100644 --- a/packages/compiler/src/jit_compiler_facade.ts +++ b/packages/compiler/src/jit_compiler_facade.ts @@ -363,6 +363,7 @@ export class CompilerFacadeImpl implements CompilerFacade { i18nUseExternalIds: true, relativeTemplatePath: null, foreignImports: null, + enableTemplateSourceLocations: false, }; const jitExpressionSourceMap = `ng:///${facade.name}.js`; return this.compileComponentFromMeta(angularCoreEnv, jitExpressionSourceMap, meta); @@ -724,6 +725,7 @@ function convertDeclareComponentFacadeToMetadata( hasDirectiveDependencies, legacyOptionalChaining: decl.legacyOptionalChaining ?? LEGACY_OPTIONAL_CHAINING_DEFAULT, foreignImports: null, + enableTemplateSourceLocations: false, }; } diff --git a/packages/compiler/src/render3/view/api.ts b/packages/compiler/src/render3/view/api.ts index d161e8b8366..9b544e14c85 100644 --- a/packages/compiler/src/render3/view/api.ts +++ b/packages/compiler/src/render3/view/api.ts @@ -310,6 +310,12 @@ export interface R3ComponentMetadata< * Foreign components imported by the component. */ foreignImports: R3ForeignComponentMetadata[] | null; + + /** + * Whether to generate additional code that adds the source location + * of elements to the DOM as an attribute. + */ + enableTemplateSourceLocations?: boolean; } /** @@ -364,9 +370,7 @@ export interface R3TemplateDependency { * A dependency that's used within a component template */ export type R3TemplateDependencyMetadata = - | R3DirectiveDependencyMetadata - | R3PipeDependencyMetadata - | R3NgModuleDependencyMetadata; + R3DirectiveDependencyMetadata | R3PipeDependencyMetadata | R3NgModuleDependencyMetadata; /** * Information about a directive that is used in a component template. Only the stable, public diff --git a/packages/compiler/src/render3/view/compiler.ts b/packages/compiler/src/render3/view/compiler.ts index 961cfdebb97..624ec7d623a 100644 --- a/packages/compiler/src/render3/view/compiler.ts +++ b/packages/compiler/src/render3/view/compiler.ts @@ -27,7 +27,7 @@ import { R3HostMetadata, R3TemplateDependency, } from './api'; -import {getTemplateSourceLocationsEnabled} from './config'; +import {ENABLE_TEMPLATE_SOURCE_LOCATIONS} from './config'; import {createContentQueriesFunction, createViewQueriesFunction} from './query_generation'; import {makeBindingParser} from './template'; import {asLiteral, conditionallyCreateDirectiveBindingLiteral, DefinitionMap} from './util'; @@ -214,7 +214,7 @@ export function compileComponentFromMetadata( meta.defer, allDeferrableDepsFn, meta.relativeTemplatePath, - getTemplateSourceLocationsEnabled(), + meta.enableTemplateSourceLocations || ENABLE_TEMPLATE_SOURCE_LOCATIONS, meta.legacyOptionalChaining, meta.foreignImports, ); diff --git a/packages/compiler/src/render3/view/config.ts b/packages/compiler/src/render3/view/config.ts index eb7d2f41f37..cc08351370d 100644 --- a/packages/compiler/src/render3/view/config.ts +++ b/packages/compiler/src/render3/view/config.ts @@ -13,16 +13,4 @@ * tools enable it via a local change. Any modifications to this flag need to update the * internal tooling as well. */ -let ENABLE_TEMPLATE_SOURCE_LOCATIONS = false; - -/** - * Utility function to enable source locations. Intended to be used **only** inside unit tests. - */ -export function setEnableTemplateSourceLocations(value: boolean): void { - ENABLE_TEMPLATE_SOURCE_LOCATIONS = value; -} - -/** Gets whether template source locations are enabled. */ -export function getTemplateSourceLocationsEnabled(): boolean { - return ENABLE_TEMPLATE_SOURCE_LOCATIONS; -} +export const ENABLE_TEMPLATE_SOURCE_LOCATIONS = false;