Skip to content

Commit

Permalink
Add TypeScript support
Browse files Browse the repository at this point in the history
* Adds support for linting TypeScript files
* Re-implements lintText(), lintTextSync() and lintFiles() methods
* Inline the fancy result output logic and update relevant tests
  • Loading branch information
novemberborn committed Nov 8, 2017
1 parent 6f2b8b5 commit 6d9d181
Show file tree
Hide file tree
Showing 18 changed files with 315 additions and 141 deletions.
24 changes: 24 additions & 0 deletions .typescript.eslintrc.js
@@ -0,0 +1,24 @@
module.exports = {
plugins: ['typescript'],
rules: {
'no-undef': 'off',
'no-use-before-define': 'off',
'import/imports-first': 'off',
'import/first': 'off',
'typescript/adjacent-overload-signatures': 'error',
'typescript/class-name-casing': 'error',
'typescript/explicit-member-accessibility': 'error',
'typescript/interface-name-prefix': 'error',
'typescript/member-delimiter-style': ['error', {delimiter: 'none', requireLast: true, ignoreSingleLine: true}],
'typescript/member-ordering': 'error',
'typescript/no-angle-bracket-type-assertion': 'error',
'typescript/no-empty-interface': 'error',
'typescript/no-namespace': ['error', {allowDefinitionFiles: true}],
'typescript/no-parameter-properties': 'error',
'typescript/no-triple-slash-reference': 'error',
'typescript/no-unused-vars': 'error',
'typescript/no-use-before-define': ['error', {functions: false, classes: false, variables: false, typedefs: false}],
'typescript/prefer-namespace-keyword': 'error',
'typescript/type-annotation-spacing': 'error'
}
}
4 changes: 3 additions & 1 deletion README.md
Expand Up @@ -16,8 +16,10 @@ issues](https://github.com/nodesecurity/eslint-plugin-security)
* Rules for [JSX / React](https://github.com/yannickcr/eslint-plugin-react)
* Various [awesome](https://github.com/sindresorhus/eslint-plugin-unicorn)
ESLint rules
* [TypeScript](http://typescriptlang.org/) support!

See [`.eslintrc.js`](.eslintrc.js) for details.
See [`.eslintrc.js`](.eslintrc.js) and
[`.typescript.eslintrc.js`](.typescript.eslintrc.js) for details.

It's what [I](https://novemberborn.net/) use.

Expand Down
6 changes: 1 addition & 5 deletions cli.js
@@ -1,7 +1,3 @@
#!/usr/bin/env node

'use strict'

require('./lib/patch-file-result-output')(
require('standard-engine'), console
).cli(require('./options'))
require('./lib/patched-standard-engine').cli(require('./options'))
4 changes: 2 additions & 2 deletions index.js
@@ -1,3 +1,3 @@
'use strict'

module.exports = require('standard-engine').linter(require('./options'))
const Linter = require('./lib/Linter')
module.exports = new Linter(require('./options'))
105 changes: 105 additions & 0 deletions lib/Linter.js
@@ -0,0 +1,105 @@
'use strict'

const deglob = require('deglob')
const formatter = require('eslint-formatter-pretty')
const hasFlag = require('has-flag')
const engine = require('standard-engine')

const DEFAULT_PATTERNS = [
'**/*.js',
'**/*.jsx',
'**/*.d.ts',
'**/*.ts',
'**/*.tsx'
]

class Linter extends engine.linter {
parseTypescriptOpts (opts, usePackageJson) {
return this.parseOpts(Object.assign({}, opts, {parser: 'typescript-eslint-parser'}), usePackageJson)
}

lintTextSync (text, opts) {
if (opts.filename && opts.filename.endsWith('.ts')) {
opts = this.parseTypescriptOpts(opts, false)
} else {
opts = this.parseOpts(opts, false)
}
return new this.eslint.CLIEngine(opts.eslintConfig).executeOnText(text, opts.filename)
}

lintText (text, opts, cb) {
try {
const report = this.lintTextSync(text, opts)
process.nextTick(cb, null, report)
} catch (err) {
process.nextTick(cb, err)
}
}

lintFiles (patterns, opts, cb) {
if (typeof opts === 'function') return this.lintFiles(patterns, null, opts)

const regularOpts = this.parseOpts(opts, true)

if (typeof patterns === 'string') patterns = [patterns]
if (patterns.length === 0) patterns = DEFAULT_PATTERNS

deglob(patterns, {
ignore: regularOpts.ignore,
cwd: regularOpts.cwd,
useGitIgnore: true,
usePackageJson: false
}, (globErr, allFiles) => {
if (globErr) return cb(globErr)

const files = allFiles.filter(file => !file.endsWith('.ts'))
const tsFiles = allFiles.filter(file => file.endsWith('.ts'))

let report
try {
report = new this.eslint.CLIEngine(regularOpts.eslintConfig).executeOnFiles(files)
} catch (err) {
return cb(err)
}

let tsReport
if (tsFiles.length > 0) {
try {
const tsOpts = this.parseTypescriptOpts(opts, true)
tsReport = new this.eslint.CLIEngine(tsOpts.eslintConfig).executeOnFiles(tsFiles)
} catch (err) {
return cb(err)
}
}

const combined = tsReport
? {
results: report.results.concat(tsReport.results),
errorCount: report.errorCount + tsReport.errorCount,
warningCount: report.warningCount + tsReport.warningCount,
fixableErrorCount: report.fixableErrorCount + tsReport.fixableErrorCount,
fixableWarningCount: report.fixableWarningCount + tsReport.fixableWarningCount
}
: report

if (regularOpts.fix) {
this.eslint.CLIEngine.outputFixes(combined)
}

Object.defineProperty(combined.results, 'forEach', {
enumerable: false,
value () {
const output = formatter(this.slice())
if (hasFlag('stdin') && regularOpts.fix) {
console.error(output)
} else {
console.log(output)
}
}
})

cb(null, combined)
})
}
}
module.exports = Linter
28 changes: 0 additions & 28 deletions lib/patch-file-result-output.js

This file was deleted.

7 changes: 7 additions & 0 deletions lib/patched-standard-engine.js
@@ -0,0 +1,7 @@
'use strict'

const engine = require('standard-engine')
const Linter = require('./Linter')

engine.linter = opts => new Linter(opts)
module.exports = engine
11 changes: 9 additions & 2 deletions lib/settings.js
Expand Up @@ -5,11 +5,14 @@ const arrify = require('arrify')
const resolveFrom = require('resolve-from')
const baseRules = require('../.eslintrc').rules
const patchImportRule = require('./patch-import-rule')
const mergeTypescriptConfig = require('./typescript')

const ALLOW_DEV_DEPENDENCIES = [
'scripts/**/*.js',
'scripts/**/{*.js,*.ts}',
'test.js',
'test/**/*.js'
'test.ts',
'test/**/{*.js,*.ts}',
'typings/**/*.d.ts'
]

function applySettings (eslintConfig, settings, rootDir) {
Expand Down Expand Up @@ -64,6 +67,10 @@ function applySettings (eslintConfig, settings, rootDir) {
}
}
}

if (eslintConfig.parser === 'typescript-eslint-parser') {
mergeTypescriptConfig(eslintConfig)
}
}

module.exports = applySettings
19 changes: 19 additions & 0 deletions lib/typescript.js
@@ -0,0 +1,19 @@
'use strict'

const config = require('../.typescript.eslintrc')

function mergeTypescriptConfig (eslintConfig) {
for (const plugin of config.plugins) {
eslintConfig.plugins.push(plugin)
}
Object.assign(eslintConfig.rules, config.rules)

if (!eslintConfig.baseConfig) eslintConfig.baseConfig = {}
const baseConfig = eslintConfig.baseConfig
if (!baseConfig.settings) baseConfig.settings = {}
const settings = baseConfig.settings
if (!settings['import/resolver']) settings['import/resolver'] = {}
const resolver = settings['import/resolver']
resolver['eslint-import-resolver-typescript'] = true
}
module.exports = mergeTypescriptConfig
41 changes: 41 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 8 additions & 2 deletions package.json
Expand Up @@ -8,6 +8,7 @@
},
"files": [
".eslintrc.js",
".typescript.eslintrc.js",
"cli.js",
"index.js",
"options.js",
Expand All @@ -32,9 +33,11 @@
"dependencies": {
"arrify": "^1.0.1",
"babel-eslint": "8.0.1",
"deglob": "^2.1.0",
"eslint": "4.10.0",
"eslint-config-standard": "10.2.1",
"eslint-formatter-pretty": "^1.1.0",
"eslint-import-resolver-typescript": "1.0.2",
"eslint-plugin-ava": "4.2.2",
"eslint-plugin-import": "2.8.0",
"eslint-plugin-node": "5.2.1",
Expand All @@ -43,16 +46,19 @@
"eslint-plugin-react": "7.4.0",
"eslint-plugin-security": "1.4.0",
"eslint-plugin-standard": "3.0.1",
"eslint-plugin-typescript": "0.8.0",
"eslint-plugin-unicorn": "github:sindresorhus/eslint-plugin-unicorn#cba8dd9f31f2ff5646376b137a85f95ab2567e98",
"has-flag": "^2.0.0",
"resolve-from": "^4.0.0",
"standard-engine": "7.1.0"
"standard-engine": "7.1.0",
"typescript-eslint-parser": "8.0.1"
},
"devDependencies": {
"ava": "^0.23.0",
"codecov": "^3.0.0",
"get-stream": "^3.0.0",
"nyc": "^11.2.1"
"nyc": "^11.2.1",
"typescript": "^2.5.3"
},
"engines": {
"node": ">=4"
Expand Down

0 comments on commit 6d9d181

Please sign in to comment.