Skip to content

Commit 8cc566d

Browse files
clydinfilipesilva
authored andcommittedMay 20, 2020
fix(@schematics/angular): add migration to ensure tslint deprecation rule
This ensures that projects will be warned when deprecated APIs are used when linted.
1 parent 4ea0efd commit 8cc566d

File tree

3 files changed

+152
-0
lines changed

3 files changed

+152
-0
lines changed
 

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

+5
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,11 @@
9494
"version": "10.0.0-beta.6",
9595
"factory": "./update-10/update-angular-config",
9696
"description": "Remove various deprecated builders options from 'angular.json'."
97+
},
98+
"tslint-add-deprecation-rule": {
99+
"version": "10.0.0-beta.7",
100+
"factory": "./update-10/add-deprecation-rule-tslint",
101+
"description": "Adds the tslint deprecation rule to tslint JSON configuration files."
97102
}
98103
}
99104
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
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 { JsonAstObject, JsonValue } from '@angular-devkit/core';
9+
import { Rule } from '@angular-devkit/schematics';
10+
import { getPackageJsonDependency } from '../../utility/dependencies';
11+
import { findPropertyInAstObject, insertPropertyInAstObjectInOrder, removePropertyInAstObject } from '../../utility/json-utils';
12+
import { readJsonFileAsAstObject } from '../update-9/utils';
13+
14+
const TSLINT_CONFIG_PATH = '/tslint.json';
15+
const RULES_TO_ADD: Record<string, JsonValue> = {
16+
deprecation: {
17+
severity: 'warning',
18+
},
19+
};
20+
21+
export default function (): Rule {
22+
return (tree, context) => {
23+
const logger = context.logger;
24+
25+
// Update tslint dependency
26+
const current = getPackageJsonDependency(tree, 'tslint');
27+
28+
if (!current) {
29+
logger.info('Skipping: "tslint" in not a dependency of this workspace.');
30+
31+
return;
32+
}
33+
34+
// Update tslint config.
35+
const tslintJsonAst = readJsonFileAsAstObject(tree, TSLINT_CONFIG_PATH);
36+
if (!tslintJsonAst) {
37+
const config = ['tslint.js', 'tslint.yaml'].find(c => tree.exists(c));
38+
if (config) {
39+
logger.warn(`Skipping: Expected a JSON configuration file but found "${config}".`);
40+
} else {
41+
logger.warn('Skipping: Cannot find "tslint.json" configuration file.');
42+
}
43+
44+
return;
45+
}
46+
47+
for (const [name, value] of Object.entries(RULES_TO_ADD)) {
48+
const tslintJsonAst = readJsonFileAsAstObject(tree, TSLINT_CONFIG_PATH) as JsonAstObject;
49+
const rulesAst = findPropertyInAstObject(tslintJsonAst, 'rules');
50+
if (rulesAst?.kind !== 'object') {
51+
break;
52+
}
53+
54+
if (findPropertyInAstObject(rulesAst, name)) {
55+
// Skip as rule already exists.
56+
continue;
57+
}
58+
59+
const recorder = tree.beginUpdate(TSLINT_CONFIG_PATH);
60+
insertPropertyInAstObjectInOrder(recorder, rulesAst, name, value, 4);
61+
tree.commitUpdate(recorder);
62+
}
63+
};
64+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
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+
11+
describe('Migration of tslint to version 6', () => {
12+
const schematicRunner = new SchematicTestRunner(
13+
'migrations',
14+
require.resolve('../migration-collection.json'),
15+
);
16+
17+
let tree: UnitTestTree;
18+
const TSLINT_PATH = '/tslint.json';
19+
const PACKAGE_JSON_PATH = '/package.json';
20+
21+
const PACKAGE_JSON = {
22+
devDependencies: {
23+
tslint: '~6.1.0',
24+
},
25+
};
26+
27+
beforeEach(() => {
28+
tree = new UnitTestTree(new EmptyTree());
29+
tree.create(PACKAGE_JSON_PATH, JSON.stringify(PACKAGE_JSON, null, 2));
30+
});
31+
32+
it('should add new rules', async () => {
33+
const config = {
34+
extends: 'tslint:recommended',
35+
rules: {
36+
'no-use-before-declare': true,
37+
'arrow-return-shorthand': false,
38+
'label-position': true,
39+
},
40+
};
41+
tree.create(TSLINT_PATH, JSON.stringify(config, null, 2));
42+
43+
const newTree = await schematicRunner.runSchematicAsync('tslint-add-deprecation-rule', {}, tree).toPromise();
44+
const { rules } = JSON.parse(newTree.readContent(TSLINT_PATH));
45+
expect(rules['deprecation'].severity).toBe('warning');
46+
});
47+
48+
it('should not update already present rules', async () => {
49+
const config = {
50+
extends: 'tslint:recommended',
51+
rules: {
52+
'no-use-before-declare': true,
53+
'arrow-return-shorthand': false,
54+
'label-position': true,
55+
deprecation: false,
56+
},
57+
};
58+
tree.create(TSLINT_PATH, JSON.stringify(config, null, 2));
59+
60+
const newTree = await schematicRunner.runSchematicAsync('tslint-add-deprecation-rule', {}, tree).toPromise();
61+
const { rules } = JSON.parse(newTree.readContent(TSLINT_PATH));
62+
expect(rules['deprecation']).toBe(false);
63+
});
64+
65+
it('should not update already present rules with different severity', async () => {
66+
const config = {
67+
extends: 'tslint:recommended',
68+
rules: {
69+
'no-use-before-declare': true,
70+
'arrow-return-shorthand': false,
71+
'label-position': true,
72+
deprecation: {
73+
severity: 'error',
74+
},
75+
},
76+
};
77+
tree.create(TSLINT_PATH, JSON.stringify(config, null, 2));
78+
79+
const newTree = await schematicRunner.runSchematicAsync('tslint-add-deprecation-rule', {}, tree).toPromise();
80+
const { rules } = JSON.parse(newTree.readContent(TSLINT_PATH));
81+
expect(rules['deprecation'].severity).toBe('error');
82+
});
83+
});

0 commit comments

Comments
 (0)
Please sign in to comment.