Skip to content

Commit 89360ab

Browse files
alan-agius4clydin
authored andcommitted
fix(@schematics/angular): only run emitDecoratorMetadata removal migration in safe workspaces
Removal of `emitDecoratorMetadata` might cause runtime errors on projects which don't use the Angular Compiler to compile TypeScript code and therefore dependent on Decorators metadata during runtime. One such example of these builders is `@nrwl/jest`. (cherry picked from commit 7521a87)
1 parent 29e3c38 commit 89360ab

File tree

2 files changed

+85
-1
lines changed

2 files changed

+85
-1
lines changed

packages/schematics/angular/migrations/update-12/remove-emit-decorator-metadata.ts

+21-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import { join } from '@angular-devkit/core';
1010
import { DirEntry, Rule } from '@angular-devkit/schematics';
1111
import { JSONFile } from '../../utility/json-file';
12+
import { allWorkspaceTargets, getWorkspace } from '../../utility/workspace';
1213

1314
function* visitJsonFiles(directory: DirEntry): IterableIterator<string> {
1415
for (const path of directory.subfiles) {
@@ -29,7 +30,26 @@ function* visitJsonFiles(directory: DirEntry): IterableIterator<string> {
2930
}
3031

3132
export default function (): Rule {
32-
return (tree) => {
33+
return async (tree, { logger }) => {
34+
const workspace = await getWorkspace(tree);
35+
const hasThirdPartyBuilders = [...allWorkspaceTargets(workspace)].some(([, target]) => {
36+
const { builder } = target;
37+
38+
return !(
39+
builder.startsWith('@angular-devkit/build-angular') ||
40+
builder.startsWith('@nguniversal/builders')
41+
);
42+
});
43+
44+
if (hasThirdPartyBuilders) {
45+
logger.warn(
46+
'Skipping migration as the workspace uses third-party builders which may ' +
47+
'require "emitDecoratorMetadata" TypeScript compiler option.',
48+
);
49+
50+
return;
51+
}
52+
3353
for (const path of visitJsonFiles(tree.root)) {
3454
const content = tree.read(path);
3555
if (content?.toString().includes('"emitDecoratorMetadata"')) {

packages/schematics/angular/migrations/update-12/remove-emit-decorator-metadata_spec.ts

+64
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import { EmptyTree } from '@angular-devkit/schematics';
1010
import { SchematicTestRunner, UnitTestTree } from '@angular-devkit/schematics/testing';
1111
import { parse as parseJson } from 'jsonc-parser';
12+
import { Builders } from '../../utility/workspace-models';
1213

1314
describe('Migration to remove "emitDecoratorMetadata" compiler option', () => {
1415
const schematicName = 'remove-emit-decorator-metadata';
@@ -26,6 +27,28 @@ describe('Migration to remove "emitDecoratorMetadata" compiler option', () => {
2627
let tree: UnitTestTree;
2728
beforeEach(() => {
2829
tree = new UnitTestTree(new EmptyTree());
30+
tree.create(
31+
'/angular.json',
32+
JSON.stringify(
33+
{
34+
version: 1,
35+
projects: {
36+
app: {
37+
root: '',
38+
sourceRoot: 'src',
39+
prefix: 'app',
40+
architect: {
41+
browser: {
42+
builder: Builders.Browser,
43+
},
44+
},
45+
},
46+
},
47+
},
48+
undefined,
49+
2,
50+
),
51+
);
2952
});
3053

3154
it(`should rename 'emitDecoratorMetadata' when set to false`, async () => {
@@ -88,4 +111,45 @@ describe('Migration to remove "emitDecoratorMetadata" compiler option', () => {
88111
const { options } = readJsonFile(newTree, '/foo.json');
89112
expect(options['emitDecoratorMetadata']).toBeTrue();
90113
});
114+
115+
it(`should not remove 'emitDecoratorMetadata' when one of the builders is a third-party`, async () => {
116+
tree.create(
117+
'/tsconfig.json',
118+
JSON.stringify(
119+
{
120+
compilerOptions: {
121+
emitDecoratorMetadata: true,
122+
strict: true,
123+
},
124+
},
125+
undefined,
126+
2,
127+
),
128+
);
129+
tree.overwrite(
130+
'/angular.json',
131+
JSON.stringify(
132+
{
133+
version: 1,
134+
projects: {
135+
app: {
136+
root: '',
137+
sourceRoot: 'src',
138+
prefix: 'app',
139+
architect: {
140+
browser: {
141+
builder: '@nrwl/jest',
142+
},
143+
},
144+
},
145+
},
146+
},
147+
undefined,
148+
2,
149+
),
150+
);
151+
const newTree = await schematicRunner.runSchematicAsync(schematicName, {}, tree).toPromise();
152+
const { compilerOptions } = readJsonFile(newTree, '/tsconfig.json');
153+
expect(compilerOptions['emitDecoratorMetadata']).toBeTrue();
154+
});
91155
});

0 commit comments

Comments
 (0)