diff --git a/.gitignore b/.gitignore index 41847c7fd604..7b81c70ca57a 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ pids *.pid *.seed *.pid.lock +package-lock.json # Directory for instrumented libs generated by jscoverage/JSCover lib-cov diff --git a/.prettierignore b/.prettierignore index 49b3a61e6d8f..d96a940857f3 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,8 +1,7 @@ -**/tests/fixtures/**/* +**/fixtures/**/* **/dist **/coverage **/shared-fixtures -**/tests/integration/fixtures/**/* **/lib/configs/recommended.json **/.vscode -**/.nyc_output \ No newline at end of file +**/.nyc_output diff --git a/packages/benchmark/benchmark.js b/packages/benchmark/benchmark.js new file mode 100644 index 000000000000..f74616be4db4 --- /dev/null +++ b/packages/benchmark/benchmark.js @@ -0,0 +1,95 @@ +const Benchmark = require('benchmark'); + +function createBenchmark(name, directory, files, useServices) { + return new Promise((resolve, reject) => { + const suite = new Benchmark.Suite(name, { + async: true + }); + suite + .add('tslint', function() { + const result = require('./tslint-runner').runTSLint( + directory, + files, + useServices + ); + if (typeof result !== 'string') { + throw new Error('something went wrong'); + } + }) + .add('eslint', function() { + const result = require('./eslint-runner').runESLint( + directory, + files, + useServices + ); + if (typeof result !== 'string') { + throw new Error('something went wrong'); + } + }) + // add listeners + .on('cycle', function(event) { + console.log(String(event.target)); + }) + .on('error', function(e) { + reject(e); + }) + .on('complete', function() { + console.log( + `Fastest is ${this.filter('fastest') + .map(i => i.name) + .join(', ')}` + ); + resolve(); + }) + .run(); + }); +} + +async function runAllBenchmarks(scenarios) { + for (const scenario of scenarios) { + console.log(scenario.name); + await createBenchmark( + scenario.name, + scenario.directory, + scenario.files, + scenario.useServices + ); + } +} + +runAllBenchmarks([ + { + name: 'Single File: restrict-plus-operands', + directory: 'fixtures/restrict-plus-operands/', + useServices: true, + files: ['fixtures/restrict-plus-operands/test1.ts'] + }, + { + name: 'Multi File: restrict-plus-operands', + directory: 'fixtures/restrict-plus-operands/', + useServices: true, + files: [ + 'fixtures/restrict-plus-operands/test1.ts', + 'fixtures/restrict-plus-operands/test2.ts', + 'fixtures/restrict-plus-operands/test3.ts' + ] + }, + { + name: 'Single File: no-empty-interface', + directory: 'fixtures/no-empty-interface/', + useServices: false, + files: ['fixtures/no-empty-interface/test1.ts'] + }, + { + name: 'Multi File: no-empty-interface', + directory: 'fixtures/no-empty-interface/', + useServices: false, + files: [ + 'fixtures/no-empty-interface/test1.ts', + 'fixtures/no-empty-interface/test2.ts', + 'fixtures/no-empty-interface/test3.ts' + ] + } +]).catch(e => { + console.log(e); +}); diff --git a/packages/benchmark/e2e.js b/packages/benchmark/e2e.js new file mode 100644 index 000000000000..c80e5741f48c --- /dev/null +++ b/packages/benchmark/e2e.js @@ -0,0 +1,66 @@ +const Benchmark = require('benchmark'); +const child_process = require('child_process'); +const path = require('path'); + +function normalizeCommand(command) { + return path.normalize(command); +} + +function createBenchmark(name, directory, files, useServices) { + return new Promise((resolve, reject) => { + const suite = new Benchmark.Suite(name, { + async: true + }); + suite + .add('tslint', function() { + let hasError = false; + try { + child_process.execSync( + normalizeCommand('./node_modules/.bin/tslint') + + ' -p fixtures/restrict-plus-operands/tsconfig.json "fixtures/restrict-plus-operands/*.ts"' + ); + } catch (e) { + // console.error(e.output ? e.output.toString() : e); + hasError = true; + } + if (!hasError) { + throw new Error('something went wrong'); + } + }) + .add('eslint', function() { + let hasError = false; + try { + child_process.execSync( + normalizeCommand('./node_modules/.bin/eslint') + + ' --ext .ts "fixtures/restrict-plus-operands/*.ts"' + ); + } catch (e) { + // console.error(e.output ? e.output.toString() : e); + hasError = true; + } + if (!hasError) { + throw new Error('something went wrong'); + } + }) + // add listeners + .on('cycle', function(event) { + console.log(String(event.target)); + }) + .on('error', function(e) { + reject(e); + }) + .on('complete', function() { + console.log( + `Fastest is ${this.filter('fastest') + .map(i => i.name) + .join(', ')}` + ); + resolve(); + }) + .run(); + }); +} + +createBenchmark().catch(e => { + console.log(e); +}); diff --git a/packages/benchmark/eslint-runner.js b/packages/benchmark/eslint-runner.js new file mode 100644 index 000000000000..397d6b56a271 --- /dev/null +++ b/packages/benchmark/eslint-runner.js @@ -0,0 +1,56 @@ +const eslint = require('eslint'); +const path = require('path'); +const fs = require('fs'); + +// exports.runESLint = function(directory, files, useServices) { +// const linter = new eslint.CLIEngine({ +// files: files, +// configFile: `${directory}.eslintrc.js`, +// extensions: ['.js', '.ts'] +// }); +// const results = []; +// for (const file of files) { +// results.push( +// linter.executeOnText( +// fs.readFileSync(path.join(__dirname, file), 'utf8'), +// file, +// true +// ) +// ); +// } +// +// if (results[0].errorCount === 0) { +// throw new Error('something went wrong'); +// } +// if ( +// results[0].results[0].messages[0].message !== +// 'An empty interface is equivalent to `{}`.' +// ) { +// throw new Error('something went wrong'); +// } +// }; + +exports.runESLint = function(directory, files, useServices) { + const linter = new eslint.Linter(); + linter.defineRule( + '@typescript-eslint/no-empty-interface', + require('@typescript-eslint/eslint-plugin/lib/rules/no-empty-interface') + ); + linter.defineRule( + '@typescript-eslint/restrict-plus-operands', + require('@typescript-eslint/eslint-plugin/lib/rules/restrict-plus-operands') + ); + let result; + for (const file of files) { + result = linter.verify( + fs.readFileSync(path.join(__dirname, file), 'utf8'), + require(path.join(__dirname, `./${directory}.eslintrc.js`)), + file + ); + } + if (result.length === 0) { + throw new Error('something went wrong'); + } + + return result[0].message; +}; diff --git a/packages/benchmark/fixtures/complex/test.ts b/packages/benchmark/fixtures/complex/test.ts new file mode 100644 index 000000000000..6dd1d10852a1 --- /dev/null +++ b/packages/benchmark/fixtures/complex/test.ts @@ -0,0 +1,402 @@ +class Red extends Color { + public shade() { + var getHue = () => { + return this.hue(); + }; + return getHue() + ' red'; + } +} + +class Color { + public shade() { + return 'some shade'; + } + public hue() { + return 'some hue'; + } +} + +class Blue extends Color { + public shade() { + var getHue = () => { + return this.hue(); + }; + return getHue() + ' blue'; + } +} + +var r = new Red(); +var b = new Blue(); + +r.shade(); +r.hue(); +b.shade(); +b.hue(); + +// @declaration: true +// @filename: foo.ts +const foo = { + bar: 'hello', + bat: 'world', + bam: { bork: { bar: 'a', baz: 'b' } } +}; +const arr: [0, 1, 2, ['a', 'b', 'c', [{ def: 'def' }, { sec: 'sec' }]]] = [ + 0, + 1, + 2, + ['a', 'b', 'c', [{ def: 'def' }, { sec: 'sec' }]] +]; + +const { + bar: baz, + bat, + bam: { + bork: { bar: ibar, baz: ibaz } + } +} = foo; +{ baz, ibaz }; + +const [, one, , [, bee, , [, { sec }]]] = arr; +{ one, bee, sec }; + +const getFoo = () => ({ + foo: 'foo' +}); + +const { foo: foo2 } = getFoo(); +class TestFile { + name: string; + foo(message: string): () => string { + return (...x: string[]) => + /// Test summary + /// + /// + + message + this.name; + } +} +var simpleExample = class { + static getTags() {} + tags() {} +}; +var circularReference = class C { + static getTags(c: C): C { + return c; + } + tags(c: C): C { + return c; + } +}; + +// repro from #15066 +class FooItem { + foo(): void {} + name?: string; +} + +type Constructor = new (...args: any[]) => T; +function WithTags>(Base: T) { + return class extends Base { + static getTags(): void {} + tags(): void {} + }; +} + +class Test extends WithTags(FooItem) {} + +const test = new Test(); + +Test.getTags(); +test.tags(); +interface Foo { + a: string; + b: number; +}; + +interface Bar { + b: string; +} + +interface Other { + totallyUnrelatedProperty: number; +} + +let x = { a: '', b: '' }; + +declare function f(x: Foo | Other): any; + +f(x); +f({ a: '', b: '' }) + +declare function g(x: Bar | Other): any; + +g(x); +g({ a: '', b: '' }) + +declare function h(x: Foo | Bar | Other): any; + +h(x); +h({ a: '', b: '' }) + +interface CatDog { cat: any, dog: any } +interface ManBearPig { man: any, bear: any, pig: any } +interface Platypus { platypus: any } + +type ExoticAnimal = + | CatDog + | ManBearPig + | Platypus; + +declare function addToZoo(animal: ExoticAnimal): void; + +addToZoo({ dog: "Barky McBarkface" }); +addToZoo({ man: "Manny", bear: "Coffee" }); + +const manBeer = { man: "Manny", beer: "Coffee" }; +addToZoo({ man: "Manny", beer: "Coffee" }); +addToZoo(manBeer); +interface I { +} + +enum E { + Red, Green, Blue +} + +function f() { + var a: any; + var n=3; + var s=""; + var b=false; + var i:I; + var e:E; + + n&&a; + n&&s; + n&&b; + n&&i; + n&&n; + n&&e; + + s&&a; + s&&n; + s&&b; + s&&i; + s&&s; + s&&e; + + a&&n; + a&&s; + a&&b; + a&&i; + a&&a; + a&&e; + + i&&n; + i&&s; + i&&b; + i&&a; + i&&i; + i&&e; + + e&&n; + e&&s; + e&&b; + e&&a; + e&&i; + e&&e; + + n||a; + n||s; + n||b; + n||i; + n||n; + n||e; + + s||a; + s||n; + s||b; + s||i; + s||s; + s||e; + + a||n; + a||s; + a||b; + a||i; + a||a; + a||e; + + i||n; + i||s; + i||b; + i||a; + i||i; + i||e; + + e||n; + e||s; + e||b; + e||a; + e||i; + e||e; + + n==a; + n==s; + n==b; + n==i; + n==n; + n==e; + + s==a; + s==n; + s==b; + s==i; + s==s; + s==e; + + a==n; + a==s; + a==b; + a==i; + a==a; + a==e; + + i==n; + i==s; + i==b; + i==a; + i==i; + i==e; + + e==n; + e==s; + e==b; + e==a; + e==i; + e==e; + + +i; + +s; + +n; + +a; + +b; + + -i; + -s; + -n; + -a; + -b; + + !i; + !s; + !n; + !a; + !b; + + + n+a; + n+s; + n+b; + n+i; + n+n; + n+e; + + s+a; + s+n; + s+b; + s+i; + s+s; + s+e; + + a+n; + a+s; + a+b; + a+i; + a+a; + a+e; + + i+n; + i+s; + i+b; + i+a; + i+i; + i+e; + + e+n; + e+s; + e+b; + e+a; + e+i; + e+e; + + n^a; + n^s; + n^b; + n^i; + n^n; + n^e; + + s^a; + s^n; + s^b; + s^i; + s^s; + s^e; + + a^n; + a^s; + a^b; + a^i; + a^a; + a^e; + + i^n; + i^s; + i^b; + i^a; + i^i; + i^e; + + e^n; + e^s; + e^b; + e^a; + e^i; + e^e; + + n-a; + n-s; + n-b; + n-i; + n-n; + n-e; + + s-a; + s-n; + s-b; + s-i; + s-s; + s-e; + + a-n; + a-s; + a-b; + a-i; + a-a; + a-e; + + i-n; + i-s; + i-b; + i-a; + i-i; + i-e; + + e-n; + e-s; + e-b; + e-a; + e-i; + e-e; + +} diff --git a/packages/benchmark/fixtures/no-empty-interface/.eslintrc.js b/packages/benchmark/fixtures/no-empty-interface/.eslintrc.js new file mode 100644 index 000000000000..4eb332bf900d --- /dev/null +++ b/packages/benchmark/fixtures/no-empty-interface/.eslintrc.js @@ -0,0 +1,14 @@ +module.exports = { + root: true, + plugins: ['@typescript-eslint'], + rules: { + '@typescript-eslint/no-empty-interface': 'error' + }, + parser: '@typescript-eslint/parser', + parserOptions: { + sourceType: 'module', + ecmaFeatures: { + jsx: false + } + } +}; diff --git a/packages/benchmark/fixtures/no-empty-interface/test1.ts b/packages/benchmark/fixtures/no-empty-interface/test1.ts new file mode 100644 index 000000000000..fa0ebf3c5638 --- /dev/null +++ b/packages/benchmark/fixtures/no-empty-interface/test1.ts @@ -0,0 +1 @@ +interface Foo {} diff --git a/packages/benchmark/fixtures/no-empty-interface/test2.ts b/packages/benchmark/fixtures/no-empty-interface/test2.ts new file mode 100644 index 000000000000..fa0ebf3c5638 --- /dev/null +++ b/packages/benchmark/fixtures/no-empty-interface/test2.ts @@ -0,0 +1 @@ +interface Foo {} diff --git a/packages/benchmark/fixtures/no-empty-interface/test3.ts b/packages/benchmark/fixtures/no-empty-interface/test3.ts new file mode 100644 index 000000000000..fa0ebf3c5638 --- /dev/null +++ b/packages/benchmark/fixtures/no-empty-interface/test3.ts @@ -0,0 +1 @@ +interface Foo {} diff --git a/packages/benchmark/fixtures/no-empty-interface/tslint.json b/packages/benchmark/fixtures/no-empty-interface/tslint.json new file mode 100644 index 000000000000..366f38b35e96 --- /dev/null +++ b/packages/benchmark/fixtures/no-empty-interface/tslint.json @@ -0,0 +1,5 @@ +{ + "rules": { + "no-empty-interface": true + } +} diff --git a/packages/benchmark/fixtures/restrict-plus-operands/.eslintrc.js b/packages/benchmark/fixtures/restrict-plus-operands/.eslintrc.js new file mode 100644 index 000000000000..29e8d14c7e9d --- /dev/null +++ b/packages/benchmark/fixtures/restrict-plus-operands/.eslintrc.js @@ -0,0 +1,16 @@ +module.exports = { + root: true, + plugins: ['@typescript-eslint'], + rules: { + '@typescript-eslint/restrict-plus-operands': 'error' + }, + parser: '@typescript-eslint/parser', + parserOptions: { + tsconfigRootDir: __dirname, + project: './tsconfig.json', + sourceType: 'module', + ecmaFeatures: { + jsx: false + } + } +}; diff --git a/packages/benchmark/fixtures/restrict-plus-operands/test1.ts b/packages/benchmark/fixtures/restrict-plus-operands/test1.ts new file mode 100644 index 000000000000..aa88a44282b9 --- /dev/null +++ b/packages/benchmark/fixtures/restrict-plus-operands/test1.ts @@ -0,0 +1 @@ +const test = 'a' + 1 diff --git a/packages/benchmark/fixtures/restrict-plus-operands/test2.ts b/packages/benchmark/fixtures/restrict-plus-operands/test2.ts new file mode 100644 index 000000000000..aa88a44282b9 --- /dev/null +++ b/packages/benchmark/fixtures/restrict-plus-operands/test2.ts @@ -0,0 +1 @@ +const test = 'a' + 1 diff --git a/packages/benchmark/fixtures/restrict-plus-operands/test3.ts b/packages/benchmark/fixtures/restrict-plus-operands/test3.ts new file mode 100644 index 000000000000..aa88a44282b9 --- /dev/null +++ b/packages/benchmark/fixtures/restrict-plus-operands/test3.ts @@ -0,0 +1 @@ +const test = 'a' + 1 diff --git a/packages/benchmark/fixtures/restrict-plus-operands/tsconfig.json b/packages/benchmark/fixtures/restrict-plus-operands/tsconfig.json new file mode 100644 index 000000000000..3792da469e0e --- /dev/null +++ b/packages/benchmark/fixtures/restrict-plus-operands/tsconfig.json @@ -0,0 +1,8 @@ +{ + "compilerOptions": { + "declaration": true + }, + "include": [ + "./*" + ] +} diff --git a/packages/benchmark/fixtures/restrict-plus-operands/tslint.json b/packages/benchmark/fixtures/restrict-plus-operands/tslint.json new file mode 100644 index 000000000000..8389b1de47a8 --- /dev/null +++ b/packages/benchmark/fixtures/restrict-plus-operands/tslint.json @@ -0,0 +1,5 @@ +{ + "rules": { + "restrict-plus-operands": true + } +} diff --git a/packages/benchmark/package.json b/packages/benchmark/package.json new file mode 100644 index 000000000000..58f4d26fcdc5 --- /dev/null +++ b/packages/benchmark/package.json @@ -0,0 +1,22 @@ +{ + "name": "@typescript-eslint/benchmark", + "version": "1.1.0", + "private": true, + "scripts": { + "benchmark:rules": "node --allow-natives-syntax benchmark.js", + "benchmark:parsers": "node --allow-natives-syntax parsers.js", + "benchmark:e2e": "node --allow-natives-syntax e2e.js", + "eslint": "eslint --ext .ts fixtures/restrict-plus-operands", + "tslint": "tslint -p fixtures/restrict-plus-operands/tsconfig.json \"fixtures/restrict-plus-operands/*.ts\"" + }, + "devDependencies": { + "@types/benchmark": "^1.0.31", + "@types/eslint": "^4.16.5", + "@typescript-eslint/eslint-plugin": "1.1.1", + "@typescript-eslint/parser": "1.1.1", + "@typescript-eslint/typescript-estree": "1.1.1", + "benchmark": "^2.1.4", + "eslint": "^5.12.1", + "tslint": "^5.12.1" + } +} diff --git a/packages/benchmark/parsers.js b/packages/benchmark/parsers.js new file mode 100644 index 000000000000..9565c262531f --- /dev/null +++ b/packages/benchmark/parsers.js @@ -0,0 +1,90 @@ +const Benchmark = require('benchmark'); +const fs = require('fs'); +const path = require('path'); +const tsEstree = require('@typescript-eslint/typescript-estree'); +const tsParser = require('@typescript-eslint/parser'); + +function runTSESTree(directory, files) { + for (const file of files) { + const result = tsEstree.parse( + fs.readFileSync(path.join(__dirname, file), 'utf8'), + { + comment: true, + tokens: true + } + ); + if (result.type !== 'Program') { + throw new Error('something went wrong'); + } + } +} + +function runTSParser(directory, files) { + for (const file of files) { + const result = tsParser.parse( + fs.readFileSync(path.join(__dirname, file), 'utf8'), + { + comment: true, + tokens: true + } + ); + if (result.type !== 'Program') { + throw new Error('something went wrong'); + } + } +} + +function createBenchmark(name, directory, files) { + return new Promise((resolve, reject) => { + const suite = new Benchmark.Suite(name); + suite + .add('ts-estree', function() { + runTSESTree(directory, files); + }) + .add('ts-parser', function tsParser() { + runTSParser(directory, files); + }) + // add listeners + .on('cycle', function(event) { + console.log(String(event.target)); + }) + .on('error', function(e) { + reject(e); + }) + .on('complete', function() { + console.log( + `Fastest is ${this.filter('fastest') + .map(i => i.name) + .join(', ')}` + ); + resolve(); + }) + .run({ + async: true, + minSamples: 100000, + initCount: 100000 + }); + }); +} + +async function runAllBenchmarks(scenarios) { + for (const scenario of scenarios) { + console.log(scenario.name); + await createBenchmark(scenario.name, scenario.directory, scenario.files); + } +} + +runAllBenchmarks([ + { + name: 'Complex File', + directory: 'fixtures/complex/', + files: ['fixtures/complex/test.ts'] + }, + { + name: 'Simple File', + directory: 'fixtures/restrict-plus-operands/', + files: ['fixtures/restrict-plus-operands/test1.ts'] + } +]).catch(e => { + console.log(e); +}); diff --git a/packages/benchmark/tsconfig.json b/packages/benchmark/tsconfig.json new file mode 100644 index 000000000000..38e6103e9c6e --- /dev/null +++ b/packages/benchmark/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "declaration": true + }, + "include": ["src"] +} diff --git a/packages/benchmark/tslint-runner.js b/packages/benchmark/tslint-runner.js new file mode 100644 index 000000000000..aff8f3c5fe0d --- /dev/null +++ b/packages/benchmark/tslint-runner.js @@ -0,0 +1,31 @@ +const tslint = require('tslint'); +const path = require('path'); +const fs = require('fs'); + +exports.runTSLint = function(directory, files, useServices) { + const program = useServices + ? tslint.Linter.createProgram(`${directory}tsconfig.json`) + : undefined; + const linter = new tslint.Linter( + { + fix: false, + formatter: 'json' + }, + program + ); + const tslintConfig = tslint.Configuration.loadConfigurationFromPath( + `./${directory}tslint.json` + ); + for (const file of files) { + linter.lint( + file, + fs.readFileSync(path.join(__dirname, file), 'utf8'), + tslintConfig + ); + } + const result = linter.getResult(); + if (result.errorCount === 0) { + throw new Error('something went wrong'); + } + return result.failures[0].failure; +}; diff --git a/yarn.lock b/yarn.lock index b6a6d614dfc0..c91501604006 100644 --- a/yarn.lock +++ b/yarn.lock @@ -803,6 +803,11 @@ resolved "https://registry.yarnpkg.com/@types/babel-code-frame/-/babel-code-frame-6.20.1.tgz#e79a40ea81435034df7b46b5e32e8ed638aea4dd" integrity sha1-55pA6oFDUDTfe0a14y6O1jiupN0= +"@types/benchmark@^1.0.31": + version "1.0.31" + resolved "https://registry.yarnpkg.com/@types/benchmark/-/benchmark-1.0.31.tgz#2dd3514e93396f362ba5551a7c9ff0da405c1d38" + integrity sha512-F6fVNOkGEkSdo/19yWYOwVKGvzbTeWkR/XQYBKtGBQ9oGRjBN9f/L4aJI4sDcVPJO58Y1CJZN8va9V2BhrZapA== + "@types/eslint-visitor-keys@^1.0.0": version "1.0.0" resolved "https://registry.yarnpkg.com/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#1ee30d79544ca84d68d4b3cdb0af4f205663dd2d" @@ -1361,6 +1366,14 @@ bcrypt-pbkdf@^1.0.0: dependencies: tweetnacl "^0.14.3" +benchmark@^2.1.4: + version "2.1.4" + resolved "https://registry.yarnpkg.com/benchmark/-/benchmark-2.1.4.tgz#09f3de31c916425d498cc2ee565a0ebf3c2a5629" + integrity sha1-CfPeMckWQl1JjMLuVloOvzwqVik= + dependencies: + lodash "^4.17.4" + platform "^1.3.3" + bin-links@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/bin-links/-/bin-links-1.1.2.tgz#fb74bd54bae6b7befc6c6221f25322ac830d9757" @@ -5743,6 +5756,11 @@ pkg-dir@^3.0.0: dependencies: find-up "^3.0.0" +platform@^1.3.3: + version "1.3.5" + resolved "https://registry.yarnpkg.com/platform/-/platform-1.3.5.tgz#fb6958c696e07e2918d2eeda0f0bc9448d733444" + integrity sha512-TuvHS8AOIZNAlE77WUDiR4rySV/VMptyMfcfeoMgs4P8apaZM3JrnbzBiixKUv+XR6i+BXrQh8WAnjaSPFO65Q== + please-upgrade-node@^3.0.2, please-upgrade-node@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/please-upgrade-node/-/please-upgrade-node-3.1.1.tgz#ed320051dfcc5024fae696712c8288993595e8ac" @@ -7000,7 +7018,7 @@ tslib@^1.8.0, tslib@^1.8.1, tslib@^1.9.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286" integrity sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ== -tslint@^5.11.0: +tslint@^5.11.0, tslint@^5.12.1: version "5.12.1" resolved "https://registry.yarnpkg.com/tslint/-/tslint-5.12.1.tgz#8cec9d454cf8a1de9b0a26d7bdbad6de362e52c1" integrity sha512-sfodBHOucFg6egff8d1BvuofoOQ/nOeYNfbp7LDlKBcLNrL3lmS5zoiDGyOMdT7YsEXAwWpTdAHwOGOc8eRZAw==