diff --git a/packages/schematics/angular/migrations/update-12/remove-emit-decorator-metadata.ts b/packages/schematics/angular/migrations/update-12/remove-emit-decorator-metadata.ts index 72dd09cde96a..cc4716f1497e 100644 --- a/packages/schematics/angular/migrations/update-12/remove-emit-decorator-metadata.ts +++ b/packages/schematics/angular/migrations/update-12/remove-emit-decorator-metadata.ts @@ -9,6 +9,7 @@ import { join } from '@angular-devkit/core'; import { DirEntry, Rule } from '@angular-devkit/schematics'; import { JSONFile } from '../../utility/json-file'; +import { allWorkspaceTargets, getWorkspace } from '../../utility/workspace'; function* visitJsonFiles(directory: DirEntry): IterableIterator { for (const path of directory.subfiles) { @@ -29,7 +30,26 @@ function* visitJsonFiles(directory: DirEntry): IterableIterator { } export default function (): Rule { - return (tree) => { + return async (tree, { logger }) => { + const workspace = await getWorkspace(tree); + const hasThirdPartyBuilders = [...allWorkspaceTargets(workspace)].some(([, target]) => { + const { builder } = target; + + return !( + builder.startsWith('@angular-devkit/build-angular') || + builder.startsWith('@nguniversal/builders') + ); + }); + + if (hasThirdPartyBuilders) { + logger.warn( + 'Skipping migration as the workspace uses third-party builders which may ' + + 'require "emitDecoratorMetadata" TypeScript compiler option.', + ); + + return; + } + for (const path of visitJsonFiles(tree.root)) { const content = tree.read(path); if (content?.toString().includes('"emitDecoratorMetadata"')) { diff --git a/packages/schematics/angular/migrations/update-12/remove-emit-decorator-metadata_spec.ts b/packages/schematics/angular/migrations/update-12/remove-emit-decorator-metadata_spec.ts index 93f1a3a351f5..d2a9a7b4207f 100644 --- a/packages/schematics/angular/migrations/update-12/remove-emit-decorator-metadata_spec.ts +++ b/packages/schematics/angular/migrations/update-12/remove-emit-decorator-metadata_spec.ts @@ -9,6 +9,7 @@ import { EmptyTree } from '@angular-devkit/schematics'; import { SchematicTestRunner, UnitTestTree } from '@angular-devkit/schematics/testing'; import { parse as parseJson } from 'jsonc-parser'; +import { Builders } from '../../utility/workspace-models'; describe('Migration to remove "emitDecoratorMetadata" compiler option', () => { const schematicName = 'remove-emit-decorator-metadata'; @@ -26,6 +27,28 @@ describe('Migration to remove "emitDecoratorMetadata" compiler option', () => { let tree: UnitTestTree; beforeEach(() => { tree = new UnitTestTree(new EmptyTree()); + tree.create( + '/angular.json', + JSON.stringify( + { + version: 1, + projects: { + app: { + root: '', + sourceRoot: 'src', + prefix: 'app', + architect: { + browser: { + builder: Builders.Browser, + }, + }, + }, + }, + }, + undefined, + 2, + ), + ); }); it(`should rename 'emitDecoratorMetadata' when set to false`, async () => { @@ -88,4 +111,45 @@ describe('Migration to remove "emitDecoratorMetadata" compiler option', () => { const { options } = readJsonFile(newTree, '/foo.json'); expect(options['emitDecoratorMetadata']).toBeTrue(); }); + + it(`should not remove 'emitDecoratorMetadata' when one of the builders is a third-party`, async () => { + tree.create( + '/tsconfig.json', + JSON.stringify( + { + compilerOptions: { + emitDecoratorMetadata: true, + strict: true, + }, + }, + undefined, + 2, + ), + ); + tree.overwrite( + '/angular.json', + JSON.stringify( + { + version: 1, + projects: { + app: { + root: '', + sourceRoot: 'src', + prefix: 'app', + architect: { + browser: { + builder: '@nrwl/jest', + }, + }, + }, + }, + }, + undefined, + 2, + ), + ); + const newTree = await schematicRunner.runSchematicAsync(schematicName, {}, tree).toPromise(); + const { compilerOptions } = readJsonFile(newTree, '/tsconfig.json'); + expect(compilerOptions['emitDecoratorMetadata']).toBeTrue(); + }); });