1
0
Fork 0

feat(build): replace tslint with eslint

This commit is contained in:
ssube 2019-11-09 17:41:55 -06:00 committed by Sean Sube
parent 27bb602ad1
commit 705209620b
16 changed files with 1211 additions and 51 deletions

View File

@ -1,7 +1,19 @@
version: "2" version: "2"
checks:
method-complexity:
config:
threshold: 6 # 5 is *just* too low and flags a number of otherwise readable methods
method-lines:
config:
threshold: 30 # with object literals, lines are not a great measure
exclude_patterns: exclude_patterns:
- CHANGELOG.md - CHANGELOG.md
- config/
- docs/api/
- docs/dev/style.md
- src/migration/
- vendor/ - vendor/
plugins: plugins:
@ -10,7 +22,11 @@ plugins:
config: config:
languages: languages:
typescript: typescript:
mass_threshold: 225 # avoid increasing, increments of 5 mass_threshold: 225
eslint:
enabled: true
config:
config: config/eslint.json
fixme: fixme:
enabled: true enabled: true
markdownlint: markdownlint:

389
config/eslint.json Normal file
View File

@ -0,0 +1,389 @@
{
"env": {
"es6": true
},
"parser": "@typescript-eslint/parser",
"parserOptions": {
"project": "tsconfig.json",
"sourceType": "module"
},
"plugins": [
"eslint-plugin-chai",
"eslint-plugin-chai-expect",
"eslint-plugin-chai-expect-keywords",
"eslint-plugin-import",
"eslint-plugin-mocha",
"eslint-plugin-no-null",
"eslint-plugin-sonarjs",
"@typescript-eslint",
"@typescript-eslint/tslint"
],
"rules": {
"@typescript-eslint/adjacent-overload-signatures": "error",
"@typescript-eslint/array-type": [
"error",
{
"default": "generic"
}
],
"@typescript-eslint/await-thenable": "error",
"@typescript-eslint/ban-types": [
"error",
{
"types": {
"null": "Use 'undefined' instead of 'null'"
}
}
],
"@typescript-eslint/class-name-casing": "error",
"@typescript-eslint/consistent-type-assertions": "error",
"@typescript-eslint/consistent-type-definitions": "error",
"@typescript-eslint/explicit-member-accessibility": [
"error",
{
"accessibility": "explicit",
"overrides": {
"constructors": "no-public"
}
}
],
"@typescript-eslint/indent": [
"error",
2,
{
"ObjectExpression": "first",
"FunctionDeclaration": {
"parameters": "first"
},
"FunctionExpression": {
"parameters": "first"
},
"SwitchCase": 1
}
],
"@typescript-eslint/interface-name-prefix": "error",
"@typescript-eslint/member-delimiter-style": [
"error",
{
"multiline": {
"delimiter": "semi",
"requireLast": true
},
"singleline": {
"delimiter": "semi",
"requireLast": false
}
}
],
"@typescript-eslint/member-ordering": [
"error",
{
"default": [
"public-static-method",
"public-static-field",
"public-instance-field",
"protected-instance-field",
"public-constructor",
"public-instance-method",
"protected-instance-method"
]
}
],
"@typescript-eslint/no-empty-function": "error",
"@typescript-eslint/no-empty-interface": "error",
"@typescript-eslint/no-explicit-any": "error",
"@typescript-eslint/no-floating-promises": "error",
"@typescript-eslint/no-for-in-array": "error",
"@typescript-eslint/no-inferrable-types": "error",
"@typescript-eslint/no-misused-new": "error",
"@typescript-eslint/no-namespace": "error",
"@typescript-eslint/no-non-null-assertion": "error",
"no-param-reassign": "error",
"@typescript-eslint/no-parameter-properties": "error",
"@typescript-eslint/no-this-alias": "error",
"@typescript-eslint/no-unnecessary-type-arguments": "error",
"@typescript-eslint/no-use-before-declare": "off",
"@typescript-eslint/no-var-requires": "error",
"@typescript-eslint/prefer-for-of": "error",
"@typescript-eslint/prefer-function-type": "error",
"@typescript-eslint/prefer-namespace-keyword": "error",
"@typescript-eslint/quotes": [
"error",
"single",
{
"avoidEscape": true
}
],
"@typescript-eslint/restrict-plus-operands": "error",
"@typescript-eslint/semi": [
"error",
"always"
],
"space-in-parens": [
"error",
"never"
],
"@typescript-eslint/strict-boolean-expressions": "error",
"@typescript-eslint/triple-slash-reference": "error",
"@typescript-eslint/type-annotation-spacing": "error",
"@typescript-eslint/unbound-method": "error",
"@typescript-eslint/unified-signatures": "error",
"arrow-body-style": "error",
"arrow-parens": [
"error",
"always"
],
"camelcase": "error",
"complexity": [
"error",
{
"max": 12
}
],
"constructor-super": "error",
"curly": "error",
"default-case": "error",
"dot-notation": "error",
"eol-last": "error",
"eqeqeq": [
"error",
"always"
],
"guard-for-in": "error",
"id-blacklist": [
"error",
"any",
"Number",
"String",
"Boolean",
"Undefined"
],
"id-match": "error",
"import/no-default-export": "error",
"import/no-deprecated": "error",
"import/no-extraneous-dependencies": "off",
"import/no-internal-modules": "off",
"import/order": [
"error",
{
"groups": [
[
"builtin",
"external"
],
[
"index",
"parent",
"sibling",
"unknown"
]
]
}
],
"max-classes-per-file": [
"off",
1
],
"max-len": [
"error",
{
"code": 180
}
],
"max-lines": [
"error",
500
],
"new-parens": "error",
"no-bitwise": "off",
"no-caller": "error",
"no-cond-assign": "error",
"no-console": "error",
"no-debugger": "error",
"no-duplicate-case": "error",
"no-duplicate-imports": "error",
"no-empty": "error",
"no-eval": "error",
"no-extra-bind": "error",
"no-fallthrough": "off",
"no-invalid-this": "error",
"no-irregular-whitespace": "error",
"no-magic-numbers": [
"error",
{
"ignore": [
-3,
-2,
-1,
0,
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
20,
30,
40,
50,
60,
70,
80,
90,
100
]
}
],
"no-multiple-empty-lines": "error",
"no-new-func": "error",
"no-new-wrappers": "error",
"no-null/no-null": "error",
"no-plusplus": [
"error",
{
"allowForLoopAfterthoughts": true
}
],
"no-redeclare": "error",
"no-restricted-syntax": [
"error",
"ForInStatement"
],
"no-return-await": "error",
"no-sequences": "error",
"no-shadow": [
"error",
{
"hoist": "all"
}
],
"no-sparse-arrays": "error",
"no-template-curly-in-string": "error",
"no-throw-literal": "error",
"no-trailing-spaces": "error",
"no-undef-init": "error",
"no-underscore-dangle": "error",
"no-unsafe-finally": "error",
"no-unused-expressions": "error",
"no-unused-labels": "error",
"no-useless-constructor": "error",
"no-var": "error",
"no-void": "error",
"max-params": [
"error",
4
],
"object-shorthand": "error",
"one-var": [
"error",
"never"
],
"prefer-const": "error",
"prefer-object-spread": "error",
"@typescript-eslint/prefer-readonly": "error",
"quote-props": [
"error",
"consistent-as-needed"
],
"radix": "error",
"space-before-function-paren": [
"error",
{
"anonymous": "never",
"asyncArrow": "always",
"named": "never"
}
],
"spaced-comment": "error",
"use-isnan": "error",
"valid-typeof": "off",
"sonarjs/max-switch-cases": "error",
"sonarjs/cognitive-complexity": "error",
"sonarjs/no-all-duplicated-branches": "error",
"sonarjs/no-collapsible-if": "error",
"sonarjs/no-collection-size-mischeck": "error",
"sonarjs/no-duplicate-string": "error",
"sonarjs/no-duplicated-branches": "error",
"sonarjs/no-element-overwrite": "error",
"sonarjs/no-identical-conditions": "error",
"sonarjs/no-identical-expressions": "error",
"sonarjs/no-identical-functions": "error",
"sonarjs/no-inverted-boolean-check": "error",
"sonarjs/no-redundant-boolean": "error",
"sonarjs/no-redundant-jump": "error",
"sonarjs/no-same-line-conditional": "error",
"sonarjs/no-useless-catch": "error",
"sonarjs/prefer-immediate-return": "error",
"@typescript-eslint/tslint/config": [
"error",
{
"rules": {
"ban": [
true,
{
"message": "use lodash isString",
"name": [
"util",
"isString"
]
},
{
"message": "use lodash isNil",
"name": [
"util",
"isNullOrUndefined"
]
}
],
"import-spacing": true,
"jsdoc-format": [
true,
"check-multiline-start"
],
"no-boolean-literal-compare": true,
"no-dynamic-delete": true,
"no-inferred-empty-object-type": true,
"no-reference-import": true,
"object-literal-sort-keys": true,
"one-line": [
true,
"check-catch",
"check-else",
"check-finally",
"check-open-brace",
"check-whitespace"
],
"prefer-switch": true,
"strict-type-predicates": true,
"trailing-comma": [
true,
{
"esSpecCompliant": true,
"multiline": {
"arrays": "always",
"functions": "never",
"object": "always"
},
"singleline": "never"
}
],
"whitespace": [
true,
"check-branch",
"check-decl",
"check-operator",
"check-separator",
"check-type",
"check-typecast",
"check-type-operator",
"check-rest-spread"
]
}
}
]
}
}

View File

@ -1,9 +1,9 @@
import commonjs from 'rollup-plugin-commonjs'; import commonjs from 'rollup-plugin-commonjs';
import { eslint } from 'rollup-plugin-eslint';
import json from 'rollup-plugin-json'; import json from 'rollup-plugin-json';
import multiEntry from 'rollup-plugin-multi-entry'; import multiEntry from 'rollup-plugin-multi-entry';
import resolve from 'rollup-plugin-node-resolve'; import resolve from 'rollup-plugin-node-resolve';
import replace from 'rollup-plugin-replace'; import replace from 'rollup-plugin-replace';
import tslint from 'rollup-plugin-tslint';
import typescript from 'rollup-plugin-typescript2'; import typescript from 'rollup-plugin-typescript2';
const metadata = require('../package.json'); const metadata = require('../package.json');
@ -102,8 +102,8 @@ const bundle = {
], ],
}, },
}), }),
tslint({ eslint({
configuration: './config/tslint.json', configFile: './config/eslint.json',
throwOnError: true, throwOnError: true,
}), }),
typescript({ typescript({

View File

@ -47,11 +47,21 @@
"@types/sinon-chai": "3.2.3", "@types/sinon-chai": "3.2.3",
"@types/source-map-support": "0.5.0", "@types/source-map-support": "0.5.0",
"@types/yargs": "13.0.3", "@types/yargs": "13.0.3",
"@typescript-eslint/eslint-plugin": "^2.6.1",
"@typescript-eslint/eslint-plugin-tslint": "^2.6.1",
"@typescript-eslint/parser": "^2.6.1",
"ajv": "6.10.2", "ajv": "6.10.2",
"bunyan": "1.8.12", "bunyan": "1.8.12",
"chai": "4.2.0", "chai": "4.2.0",
"chai-as-promised": "7.1.1", "chai-as-promised": "7.1.1",
"deep-diff": "1.0.2", "deep-diff": "1.0.2",
"eslint-plugin-chai": "^0.0.1",
"eslint-plugin-chai-expect": "^2.0.1",
"eslint-plugin-chai-expect-keywords": "^1.0.0",
"eslint-plugin-import": "^2.18.2",
"eslint-plugin-mocha": "^6.2.1",
"eslint-plugin-no-null": "^1.0.2",
"eslint-plugin-sonarjs": "^0.5.0",
"js-yaml": "3.13.1", "js-yaml": "3.13.1",
"jsonpath-plus": "1.1.0", "jsonpath-plus": "1.1.0",
"lodash": "4.17.15", "lodash": "4.17.15",
@ -60,6 +70,7 @@
"nyc": "14.1.1", "nyc": "14.1.1",
"rollup": "1.26.4", "rollup": "1.26.4",
"rollup-plugin-commonjs": "10.1.0", "rollup-plugin-commonjs": "10.1.0",
"rollup-plugin-eslint": "^7.0.0",
"rollup-plugin-json": "4.0.0", "rollup-plugin-json": "4.0.0",
"rollup-plugin-multi-entry": "2.1.0", "rollup-plugin-multi-entry": "2.1.0",
"rollup-plugin-node-resolve": "5.2.0", "rollup-plugin-node-resolve": "5.2.0",

View File

@ -12,7 +12,7 @@ export enum MODE {
export const VALID_MODES = new Set([MODE.check, MODE.fix, MODE.list]); export const VALID_MODES = new Set([MODE.check, MODE.fix, MODE.list]);
/* tslint:disable:no-any */ /* eslint-disable @typescript-eslint/no-explicit-any */
export const CONFIG_ARGS_NAME = 'config-name'; export const CONFIG_ARGS_NAME = 'config-name';
export const CONFIG_ARGS_PATH = 'config-path'; export const CONFIG_ARGS_PATH = 'config-path';
@ -50,7 +50,7 @@ export interface ParseResults {
export async function parseArgs(argv: Array<string>): Promise<ParseResults> { export async function parseArgs(argv: Array<string>): Promise<ParseResults> {
let mode: MODE = MODE.check; let mode: MODE = MODE.check;
const parser = usage(`Usage: salty-dog <mode> [options]`) const parser = usage('Usage: salty-dog <mode> [options]')
.command({ .command({
command: ['check', '*'], command: ['check', '*'],
describe: 'validate the source documents', describe: 'validate the source documents',
@ -59,19 +59,16 @@ export async function parseArgs(argv: Array<string>): Promise<ParseResults> {
}, },
}) })
.command({ .command({
builder: (yargs: any) => { builder: (yargs: any) => yargs.options({
return yargs coerce: {
.options({ default: false,
coerce: { type: 'boolean',
default: false, },
type: 'boolean', defaults: {
}, default: true,
defaults: { type: 'boolean',
default: true, },
type: 'boolean', }),
},
});
},
command: ['fix'], command: ['fix'],
describe: 'validate the source document and insert defaults', describe: 'validate the source document and insert defaults',
handler: (argi: any) => { handler: (argi: any) => {

View File

@ -69,7 +69,7 @@ export async function loadConfig(name: string, ...extras: Array<string>): Promis
export async function readConfig(path: string): Promise<string | undefined> { export async function readConfig(path: string): Promise<string | undefined> {
try { try {
// need to await this read to catch the error, need to catch the error to check the code // need to await this read to catch the error, need to catch the error to check the code
// tslint:disable-next-line:prefer-immediate-return /* eslint-disable-next-line sonarjs/prefer-immediate-return */
const data = await readFile(path, { const data = await readFile(path, {
encoding: 'utf-8', encoding: 'utf-8',
}); });

View File

@ -83,7 +83,7 @@ export async function main(argv: Array<string>): Promise<number> {
} }
main(process.argv).then((status) => process.exit(status)).catch((err) => { main(process.argv).then((status) => process.exit(status)).catch((err) => {
/* tslint:disable-next-line:no-console */ /* eslint-disable-next-line no-console */
console.error('uncaught error during main:', err); console.error('uncaught error during main:', err);
process.exit(STATUS_ERROR); process.exit(STATUS_ERROR);
}); });

View File

@ -3,6 +3,8 @@ import { safeDump, safeLoadAll } from 'js-yaml';
import { CONFIG_SCHEMA } from '../config/schema'; import { CONFIG_SCHEMA } from '../config/schema';
import { Parser } from '../parser'; import { Parser } from '../parser';
/* eslint-disable @typescript-eslint/no-explicit-any */
export class YamlParser implements Parser { export class YamlParser implements Parser {
public dump(...data: Array<any>): string { public dump(...data: Array<any>): string {
const docs: Array<any> = []; const docs: Array<any> = [];

View File

@ -10,6 +10,8 @@ import { VisitorContext } from '../visitor/VisitorContext';
import { VisitorError } from '../visitor/VisitorError'; import { VisitorError } from '../visitor/VisitorError';
import { VisitorResult } from '../visitor/VisitorResult'; import { VisitorResult } from '../visitor/VisitorResult';
/* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/strict-boolean-expressions */
export class SchemaRule implements Rule, RuleData, Visitor { export class SchemaRule implements Rule, RuleData, Visitor {
public readonly check: ValidateFunction; public readonly check: ValidateFunction;
public readonly desc: string; public readonly desc: string;

View File

@ -11,7 +11,7 @@ import { VisitorContext } from '../visitor/VisitorContext';
import { VisitorResult } from '../visitor/VisitorResult'; import { VisitorResult } from '../visitor/VisitorResult';
import { SchemaRule } from './SchemaRule'; import { SchemaRule } from './SchemaRule';
/* tslint:disable:no-any */ /* eslint-disable @typescript-eslint/no-explicit-any */
export interface RuleData { export interface RuleData {
// metadata // metadata
desc: string; desc: string;
@ -123,10 +123,10 @@ export async function loadRulePaths(paths: Array<string>, ctx: VisitorContext):
for (const path of paths) { for (const path of paths) {
const allFiles = await readDir(path); const allFiles = await readDir(path);
const files = allFiles.filter((name) => { // skip files that start with `.`, limit to json and yaml/yml
// skip files that start with `.`, limit to json and yaml/yml const files = allFiles
return name.toLowerCase().match(/^[^\.].*\.(json|ya?ml)/); .filter((name) => name.toLowerCase().match(/^[^\.].*\.(json|ya?ml)/))
}).map((name) => join(path, name)); .map((name) => join(path, name));
const pathRules = await loadRuleFiles(files, ctx); const pathRules = await loadRuleFiles(files, ctx);
rules.push(...pathRules); rules.push(...pathRules);
@ -140,6 +140,7 @@ export async function loadRuleModules(modules: Array<string>, ctx: VisitorContex
for (const name of modules) { for (const name of modules) {
try { try {
/* eslint-disable-next-line @typescript-eslint/no-var-requires */
const module: RuleSourceModule = require(name); const module: RuleSourceModule = require(name);
// TODO: ensure module has definitions, name, and rules // TODO: ensure module has definitions, name, and rules

View File

@ -6,6 +6,8 @@ import { doesExist, hasItems } from '../utils';
import { VisitorError } from './VisitorError'; import { VisitorError } from './VisitorError';
import { VisitorResult } from './VisitorResult'; import { VisitorResult } from './VisitorResult';
/* eslint-disable @typescript-eslint/no-explicit-any */
export interface RuleOptions { export interface RuleOptions {
coerce: boolean; coerce: boolean;
defaults: boolean; defaults: boolean;

View File

@ -11,7 +11,7 @@ describeLeaks('load config helper', async () => {
expect(config.data.logger.name).to.equal('salty-dog'); expect(config.data.logger.name).to.equal('salty-dog');
}); });
itLeaks('should throw when config is missing', async () => { itLeaks('should throw when config is missing', async () =>
return expect(loadConfig('missing.yml', join(__dirname, '..', 'docs'))).to.eventually.be.rejectedWith(NotFoundError); expect(loadConfig('missing.yml', join(__dirname, '..', 'docs'))).to.eventually.be.rejectedWith(NotFoundError)
}); );
}); });

View File

@ -13,7 +13,7 @@ sourceMapSupport.install({
* This will break the whole test run if any test leaks an unhandled rejection. * This will break the whole test run if any test leaks an unhandled rejection.
*/ */
process.on('unhandledRejection', (reason, promise) => { process.on('unhandledRejection', (reason, promise) => {
// tslint:disable-next-line:no-console // eslint-disable-next-line no-console
console.error('unhandled error during tests', reason); console.error('unhandled error during tests', reason);
process.exit(1); process.exit(1);
}); });

View File

@ -2,7 +2,7 @@ import { AsyncHook, createHook } from 'async_hooks';
import { isNil } from 'lodash'; import { isNil } from 'lodash';
// this will pull Mocha internals out of the stacks // this will pull Mocha internals out of the stacks
// tslint:disable-next-line:no-var-requires /* eslint-disable-next-line @typescript-eslint/no-var-requires */
const { stackTraceFilter } = require('mocha/lib/utils'); const { stackTraceFilter } = require('mocha/lib/utils');
const filterStack = stackTraceFilter(); const filterStack = stackTraceFilter();
@ -67,8 +67,8 @@ export class Tracker {
this.hook.disable(); this.hook.disable();
} }
/* eslint-disable no-console, no-invalid-this */
public dump() { public dump() {
/* tslint:disable:no-console */
console.error(`tracking ${this.resources.size} async resources`); console.error(`tracking ${this.resources.size} async resources`);
this.resources.forEach((res, id) => { this.resources.forEach((res, id) => {
console.error(`${id}: ${res.type}`); console.error(`${id}: ${res.type}`);
@ -77,7 +77,6 @@ export class Tracker {
console.error('\n'); console.error('\n');
} }
}); });
/* tslint:enable:no-console */
} }
public enable() { public enable() {
@ -111,7 +110,7 @@ export function describeLeaks(description: string, cb: AsyncMochaSuite): Mocha.S
if (debugMode()) { if (debugMode()) {
throw new Error(msg); throw new Error(msg);
} else { } else {
// tslint:disable-next-line:no-console /* eslint-disable-next-line no-console */
console.warn(msg); console.warn(msg);
} }
} }
@ -121,7 +120,7 @@ export function describeLeaks(description: string, cb: AsyncMochaSuite): Mocha.S
const suite: PromiseLike<void> | undefined = cb.call(this); const suite: PromiseLike<void> | undefined = cb.call(this);
if (isNil(suite) || !Reflect.has(suite, 'then')) { if (isNil(suite) || !Reflect.has(suite, 'then')) {
// tslint:disable-next-line:no-console /* eslint-disable-next-line no-console */
console.error(`test suite '${description}' did not return a promise`); console.error(`test suite '${description}' did not return a promise`);
} }

View File

@ -6,6 +6,8 @@ import { SchemaRule } from '../../src/rule/SchemaRule';
import { VisitorContext } from '../../src/visitor/VisitorContext'; import { VisitorContext } from '../../src/visitor/VisitorContext';
import { describeLeaks, itLeaks } from '../helpers/async'; import { describeLeaks, itLeaks } from '../helpers/async';
/* eslint-disable @typescript-eslint/unbound-method */
const TEST_NAME = 'test-rule'; const TEST_NAME = 'test-rule';
describeLeaks('schema rule', async () => { describeLeaks('schema rule', async () => {

771
yarn.lock

File diff suppressed because it is too large Load Diff