Skip to content

Commit 96a4467

Browse files
committed
feat(@schematics/angular): add migration to remove emitDecoratorMetadata
Add migration to remove 'emitDecoratorMetadata' TypeScript compiler option. Decorator metadata is no longer needed by Angular. Read more about this option here: https://www.typescriptlang.org/docs/handbook/decorators.html#metadata
1 parent c986832 commit 96a4467

File tree

3 files changed

+114
-0
lines changed

3 files changed

+114
-0
lines changed

packages/schematics/angular/migrations/migration-collection.json

+5
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,11 @@
134134
"version": "12.0.0-next.1",
135135
"factory": "./update-12/update-zonejs",
136136
"description": "Update 'zone.js' to version 0.11.x. Read more about this here: https://github.com/angular/angular/blob/master/packages/zone.js/CHANGELOG.md#breaking-changes-since-zonejs-v0111"
137+
},
138+
"remove-emit-decorator-metadata": {
139+
"version": "12.0.0-next.2",
140+
"factory": "./update-12/remove-emit-decorator-metadata",
141+
"description": "Remove 'emitDecoratorMetadata' TypeScript compiler option. Decorator metadata is no longer needed by Angular. Read more about this here: https://www.typescriptlang.org/docs/handbook/decorators.html#metadata"
137142
}
138143
}
139144
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/**
2+
* @license
3+
* Copyright Google Inc. All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
import { join } from '@angular-devkit/core';
9+
import { DirEntry, Rule } from '@angular-devkit/schematics';
10+
import { JSONFile } from '../../utility/json-file';
11+
12+
function* visitJsonFiles(directory: DirEntry): IterableIterator<string> {
13+
for (const path of directory.subfiles) {
14+
if (!path.endsWith('.json')) {
15+
continue;
16+
}
17+
18+
yield join(directory.path, path);
19+
}
20+
21+
for (const path of directory.subdirs) {
22+
if (path === 'node_modules' || path.startsWith('.')) {
23+
continue;
24+
}
25+
26+
yield* visitJsonFiles(directory.dir(path));
27+
}
28+
}
29+
30+
export default function (): Rule {
31+
return tree => {
32+
for (const path of visitJsonFiles(tree.root)) {
33+
const content = tree.read(path);
34+
if (content?.toString().includes('"emitDecoratorMetadata"')) {
35+
const json = new JSONFile(tree, path);
36+
json.remove(['compilerOptions', 'emitDecoratorMetadata']);
37+
}
38+
}
39+
};
40+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/**
2+
* @license
3+
* Copyright Google Inc. All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
import { EmptyTree } from '@angular-devkit/schematics';
9+
import { SchematicTestRunner, UnitTestTree } from '@angular-devkit/schematics/testing';
10+
import { parse as parseJson } from 'jsonc-parser';
11+
12+
describe('Migration to remove "emitDecoratorMetadata" compiler option', () => {
13+
const schematicName = 'remove-emit-decorator-metadata';
14+
15+
const schematicRunner = new SchematicTestRunner(
16+
'migrations',
17+
require.resolve('../migration-collection.json'),
18+
);
19+
20+
// tslint:disable-next-line: no-any
21+
function readJsonFile(tree: UnitTestTree, filePath: string): any {
22+
return parseJson(tree.readContent(filePath).toString());
23+
}
24+
25+
let tree: UnitTestTree;
26+
beforeEach(() => {
27+
tree = new UnitTestTree(new EmptyTree());
28+
});
29+
30+
it(`should rename 'emitDecoratorMetadata' when set to false`, async () => {
31+
tree.create('/tsconfig.json', JSON.stringify({
32+
compilerOptions: {
33+
emitDecoratorMetadata: false,
34+
strict: true,
35+
},
36+
}, undefined, 2));
37+
38+
const newTree = await schematicRunner.runSchematicAsync(schematicName, {}, tree).toPromise();
39+
const { compilerOptions } = readJsonFile(newTree, '/tsconfig.json');
40+
expect(compilerOptions['emitDecoratorMetadata']).toBeUndefined();
41+
expect(compilerOptions['strict']).toBeTrue();
42+
});
43+
44+
it(`should rename 'emitDecoratorMetadata' when set to true`, async () => {
45+
tree.create('/tsconfig.json', JSON.stringify({
46+
compilerOptions: {
47+
emitDecoratorMetadata: true,
48+
strict: true,
49+
},
50+
}, undefined, 2));
51+
52+
const newTree = await schematicRunner.runSchematicAsync(schematicName, {}, tree).toPromise();
53+
const { compilerOptions } = readJsonFile(newTree, '/tsconfig.json');
54+
expect(compilerOptions['emitDecoratorMetadata']).toBeUndefined();
55+
expect(compilerOptions['strict']).toBeTrue();
56+
});
57+
58+
it(`should not rename 'emitDecoratorMetadata' when it's not under 'compilerOptions'`, async () => {
59+
tree.create('/foo.json', JSON.stringify({
60+
options: {
61+
emitDecoratorMetadata: true,
62+
},
63+
}, undefined, 2));
64+
65+
const newTree = await schematicRunner.runSchematicAsync(schematicName, {}, tree).toPromise();
66+
const { options } = readJsonFile(newTree, '/foo.json');
67+
expect(options['emitDecoratorMetadata']).toBeTrue();
68+
});
69+
});

0 commit comments

Comments
 (0)