Skip to content

Commit

Permalink
fix(@schematics/angular): add migration to ensure tslint deprecation …
Browse files Browse the repository at this point in the history
…rule

This ensures that projects will be warned when deprecated APIs are used when linted.
  • Loading branch information
clydin authored and filipesilva committed May 20, 2020
1 parent 4ea0efd commit 8cc566d
Show file tree
Hide file tree
Showing 3 changed files with 152 additions and 0 deletions.
Expand Up @@ -94,6 +94,11 @@
"version": "10.0.0-beta.6",
"factory": "./update-10/update-angular-config",
"description": "Remove various deprecated builders options from 'angular.json'."
},
"tslint-add-deprecation-rule": {
"version": "10.0.0-beta.7",
"factory": "./update-10/add-deprecation-rule-tslint",
"description": "Adds the tslint deprecation rule to tslint JSON configuration files."
}
}
}
@@ -0,0 +1,64 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import { JsonAstObject, JsonValue } from '@angular-devkit/core';
import { Rule } from '@angular-devkit/schematics';
import { getPackageJsonDependency } from '../../utility/dependencies';
import { findPropertyInAstObject, insertPropertyInAstObjectInOrder, removePropertyInAstObject } from '../../utility/json-utils';
import { readJsonFileAsAstObject } from '../update-9/utils';

const TSLINT_CONFIG_PATH = '/tslint.json';
const RULES_TO_ADD: Record<string, JsonValue> = {
deprecation: {
severity: 'warning',
},
};

export default function (): Rule {
return (tree, context) => {
const logger = context.logger;

// Update tslint dependency
const current = getPackageJsonDependency(tree, 'tslint');

if (!current) {
logger.info('Skipping: "tslint" in not a dependency of this workspace.');

return;
}

// Update tslint config.
const tslintJsonAst = readJsonFileAsAstObject(tree, TSLINT_CONFIG_PATH);
if (!tslintJsonAst) {
const config = ['tslint.js', 'tslint.yaml'].find(c => tree.exists(c));
if (config) {
logger.warn(`Skipping: Expected a JSON configuration file but found "${config}".`);
} else {
logger.warn('Skipping: Cannot find "tslint.json" configuration file.');
}

return;
}

for (const [name, value] of Object.entries(RULES_TO_ADD)) {
const tslintJsonAst = readJsonFileAsAstObject(tree, TSLINT_CONFIG_PATH) as JsonAstObject;
const rulesAst = findPropertyInAstObject(tslintJsonAst, 'rules');
if (rulesAst?.kind !== 'object') {
break;
}

if (findPropertyInAstObject(rulesAst, name)) {
// Skip as rule already exists.
continue;
}

const recorder = tree.beginUpdate(TSLINT_CONFIG_PATH);
insertPropertyInAstObjectInOrder(recorder, rulesAst, name, value, 4);
tree.commitUpdate(recorder);
}
};
}
@@ -0,0 +1,83 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import { EmptyTree } from '@angular-devkit/schematics';
import { SchematicTestRunner, UnitTestTree } from '@angular-devkit/schematics/testing';

describe('Migration of tslint to version 6', () => {
const schematicRunner = new SchematicTestRunner(
'migrations',
require.resolve('../migration-collection.json'),
);

let tree: UnitTestTree;
const TSLINT_PATH = '/tslint.json';
const PACKAGE_JSON_PATH = '/package.json';

const PACKAGE_JSON = {
devDependencies: {
tslint: '~6.1.0',
},
};

beforeEach(() => {
tree = new UnitTestTree(new EmptyTree());
tree.create(PACKAGE_JSON_PATH, JSON.stringify(PACKAGE_JSON, null, 2));
});

it('should add new rules', async () => {
const config = {
extends: 'tslint:recommended',
rules: {
'no-use-before-declare': true,
'arrow-return-shorthand': false,
'label-position': true,
},
};
tree.create(TSLINT_PATH, JSON.stringify(config, null, 2));

const newTree = await schematicRunner.runSchematicAsync('tslint-add-deprecation-rule', {}, tree).toPromise();
const { rules } = JSON.parse(newTree.readContent(TSLINT_PATH));
expect(rules['deprecation'].severity).toBe('warning');
});

it('should not update already present rules', async () => {
const config = {
extends: 'tslint:recommended',
rules: {
'no-use-before-declare': true,
'arrow-return-shorthand': false,
'label-position': true,
deprecation: false,
},
};
tree.create(TSLINT_PATH, JSON.stringify(config, null, 2));

const newTree = await schematicRunner.runSchematicAsync('tslint-add-deprecation-rule', {}, tree).toPromise();
const { rules } = JSON.parse(newTree.readContent(TSLINT_PATH));
expect(rules['deprecation']).toBe(false);
});

it('should not update already present rules with different severity', async () => {
const config = {
extends: 'tslint:recommended',
rules: {
'no-use-before-declare': true,
'arrow-return-shorthand': false,
'label-position': true,
deprecation: {
severity: 'error',
},
},
};
tree.create(TSLINT_PATH, JSON.stringify(config, null, 2));

const newTree = await schematicRunner.runSchematicAsync('tslint-add-deprecation-rule', {}, tree).toPromise();
const { rules } = JSON.parse(newTree.readContent(TSLINT_PATH));
expect(rules['deprecation'].severity).toBe('error');
});
});

0 comments on commit 8cc566d

Please sign in to comment.