From 5bd9fbd2c3ab4467074fac5e4d689b3c85bf08cd Mon Sep 17 00:00:00 2001 From: JoostK Date: Thu, 17 Aug 2023 22:14:38 +0200 Subject: [PATCH] fix(compiler-cli): enforce a minimum version to be used when a library uses input transform (#51413) Angular 16.1 introduced the input transform feature, requiring the partial compilation output to be extended with a reference to the input transform function. This has resulted in a subtle breaking change, where older versions of the Angular linker can no longer consume libraries that have started to use this feature. We do try to support using a 16.1 library from an Angular 16.0 application, but if a library actually adopts a new feature then this is no longer possible. In such cases, it is desirable to report a message telling the user that their version of the Angular compiler is too old, as determined by the `"minVersion"` property that is present in each partial declaration. This version would still indicate that the declaration required at least Angular 14.0 to be compiled, but this is not accurate once input transforms are being used. Consequently, this error would not be reported, causing a less informative error once the input transform was being observed. Fixes #51411 PR Close #51413 --- .../r3_view_compiler_input_outputs/GOLDEN_PARTIAL.js | 2 +- packages/compiler/src/render3/partial/directive.ts | 11 +++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_input_outputs/GOLDEN_PARTIAL.js b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_input_outputs/GOLDEN_PARTIAL.js index ae85326c80b..37124a772ea 100644 --- a/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_input_outputs/GOLDEN_PARTIAL.js +++ b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_input_outputs/GOLDEN_PARTIAL.js @@ -111,7 +111,7 @@ function toNumber(value) { export class MyDirective { } MyDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDER", ngImport: i0, type: MyDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); -MyDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "0.0.0-PLACEHOLDER", type: MyDirective, selector: "[my-directive]", inputs: { functionDeclarationInput: ["functionDeclarationInput", "functionDeclarationInput", toNumber], inlineFunctionInput: ["inlineFunctionInput", "inlineFunctionInput", (value, _) => value ? 1 : 0] }, ngImport: i0 }); +MyDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "16.1.0", version: "0.0.0-PLACEHOLDER", type: MyDirective, selector: "[my-directive]", inputs: { functionDeclarationInput: ["functionDeclarationInput", "functionDeclarationInput", toNumber], inlineFunctionInput: ["inlineFunctionInput", "inlineFunctionInput", (value, _) => value ? 1 : 0] }, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDER", ngImport: i0, type: MyDirective, decorators: [{ type: Directive, args: [{ selector: '[my-directive]' }] diff --git a/packages/compiler/src/render3/partial/directive.ts b/packages/compiler/src/render3/partial/directive.ts index a2787b5de64..be5db58e5d4 100644 --- a/packages/compiler/src/render3/partial/directive.ts +++ b/packages/compiler/src/render3/partial/directive.ts @@ -22,7 +22,7 @@ import {toOptionalLiteralMap} from './util'; * * Do not include any prerelease in these versions as they are ignored. */ -const MINIMUM_PARTIAL_LINKER_VERSION = '14.0.0'; +const MINIMUM_PARTIAL_LINKER_VERSION = '16.1.0'; /** * Compile a directive declaration defined by the `R3DirectiveMetadata`. @@ -45,7 +45,14 @@ export function createDirectiveDefinitionMap(meta: R3DirectiveMetadata): DefinitionMap { const definitionMap = new DefinitionMap(); - definitionMap.set('minVersion', o.literal(MINIMUM_PARTIAL_LINKER_VERSION)); + const hasTransformFunctions = + Object.values(meta.inputs).some(input => input.transformFunction !== null); + // Note: in order to allow consuming Angular libraries that have been compiled with 16.1+ in + // Angular 16.0, we only force a minimum version of 16.1 if input transform feature as introduced + // in 16.1 is actually used. + const minVersion = hasTransformFunctions ? MINIMUM_PARTIAL_LINKER_VERSION : '14.0.0'; + + definitionMap.set('minVersion', o.literal(minVersion)); definitionMap.set('version', o.literal('0.0.0-PLACEHOLDER')); // e.g. `type: MyDirective`