Skip to content

Commit

Permalink
fix(@schematics/angular): only run emitDecoratorMetadata removal mi…
Browse files Browse the repository at this point in the history
…gration 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)
  • Loading branch information
alan-agius4 authored and clydin committed May 4, 2021
1 parent 29e3c38 commit 89360ab
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -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<string> {
for (const path of directory.subfiles) {
Expand All @@ -29,7 +30,26 @@ function* visitJsonFiles(directory: DirEntry): IterableIterator<string> {
}

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"')) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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 () => {
Expand Down Expand Up @@ -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();
});
});

0 comments on commit 89360ab

Please sign in to comment.