From 2f68b7a73327105e97f9714116e10dfa78b613ed Mon Sep 17 00:00:00 2001 From: Landon Abney Date: Mon, 26 Sep 2016 16:36:58 -0700 Subject: [PATCH] Rewrite in ES2015 No more CoffeeScript! :tada: --- coffeelint.json | 135 ---------------------------------- lib/init.coffee | 119 ------------------------------ lib/main.js | 144 +++++++++++++++++++++++++++++++++++++ package.json | 17 ++++- spec/linter-tslint-spec.js | 2 +- 5 files changed, 159 insertions(+), 258 deletions(-) delete mode 100644 coffeelint.json delete mode 100644 lib/init.coffee create mode 100644 lib/main.js diff --git a/coffeelint.json b/coffeelint.json deleted file mode 100644 index 24ab756f..00000000 --- a/coffeelint.json +++ /dev/null @@ -1,135 +0,0 @@ -{ - "arrow_spacing": { - "level": "error" - }, - "braces_spacing": { - "level": "ignore", - "spaces": 0, - "empty_object_spaces": 0 - }, - "camel_case_classes": { - "level": "error" - }, - "coffeescript_error": { - "level": "error" - }, - "colon_assignment_spacing": { - "level": "error", - "spacing": { - "left": 0, - "right": 1 - } - }, - "cyclomatic_complexity": { - "level": "ignore", - "value": 10 - }, - "duplicate_key": { - "level": "error" - }, - "empty_constructor_needs_parens": { - "level": "ignore" - }, - "ensure_comprehensions": { - "level": "warn" - }, - "eol_last": { - "level": "error" - }, - "indentation": { - "value": 2, - "level": "error" - }, - "line_endings": { - "level": "error", - "value": "unix" - }, - "max_line_length": { - "value": 80, - "level": "error", - "limitComments": true - }, - "missing_fat_arrows": { - "level": "ignore", - "is_strict": false - }, - "newlines_after_classes": { - "value": 2, - "level": "error" - }, - "no_backticks": { - "level": "error" - }, - "no_debugger": { - "level": "error", - "console": false - }, - "no_empty_functions": { - "level": "error" - }, - "no_empty_param_list": { - "level": "error" - }, - "no_implicit_braces": { - "level": "ignore", - "strict": true - }, - "no_implicit_parens": { - "level": "ignore", - "strict": true - }, - "no_interpolation_in_single_quotes": { - "level": "error" - }, - "no_nested_string_interpolation": { - "level": "warn" - }, - "no_plusplus": { - "level": "error" - }, - "no_private_function_fat_arrows": { - "level": "warn" - }, - "no_stand_alone_at": { - "level": "ignore" - }, - "no_tabs": { - "level": "error" - }, - "no_this": { - "level": "error" - }, - "no_throwing_strings": { - "level": "error" - }, - "no_trailing_semicolons": { - "level": "error" - }, - "no_trailing_whitespace": { - "level": "error", - "allowed_in_comments": false, - "allowed_in_empty_lines": true - }, - "no_unnecessary_double_quotes": { - "level": "error" - }, - "no_unnecessary_fat_arrows": { - "level": "warn" - }, - "non_empty_constructor_needs_parens": { - "level": "ignore" - }, - "prefer_english_operator": { - "level": "ignore", - "doubleNotLevel": "ignore" - }, - "space_operators": { - "level": "ignore" - }, - "spacing_after_comma": { - "level": "ignore" - }, - "transform_messes_up_line_numbers": { - "level": "warn" - } -} diff --git a/lib/init.coffee b/lib/init.coffee deleted file mode 100644 index 31325a2e..00000000 --- a/lib/init.coffee +++ /dev/null @@ -1,119 +0,0 @@ -{CompositeDisposable} = require 'atom' -path = require 'path' -fs = require 'fs' -requireResolve = require 'resolve' - -TSLINT_MODULE_NAME = 'tslint' - - -module.exports = - - config: - rulesDirectory: - type: 'string' - title: 'Custom rules directory (absolute path)' - default: '' - useLocalTslint: - type: 'boolean' - title: 'Try using the local tslint package (if exist)' - default: true - - rulesDirectory: '' - tslintCache: new Map - tslintDef: null - useLocalTslint: true - - activate: -> - require('atom-package-deps').install('linter-tslint') - @subscriptions = new CompositeDisposable - @scopes = ['source.ts', 'source.tsx'] - @subscriptions.add atom.config.observe 'linter-tslint.rulesDirectory', - (dir) => - if dir and path.isAbsolute(dir) - fs.stat dir, (err, stats) => - if stats?.isDirectory() - @rulesDirectory = dir - - @subscriptions.add atom.config.observe 'linter-tslint.useLocalTslint', - (use) => - @tslintCache.clear() - @useLocalTslint = use - - deactivate: -> - @subscriptions.dispose() - - getLinter: (filePath) -> - basedir = path.dirname filePath - linter = @tslintCache.get basedir - if linter - return Promise.resolve(linter) - - if @useLocalTslint - return @getLocalLinter(basedir) - - @tslintCache.set basedir, @tslintDef - Promise.resolve(@tslintDef) - - getLocalLinter: (basedir) -> - new Promise (resolve, reject) => - requireResolve TSLINT_MODULE_NAME, { basedir }, - (err, linterPath, pkg) => - if not err and pkg?.version.startsWith '3.' - linter = require('loophole').allowUnsafeNewFunction -> - require linterPath - else - linter = @tslintDef - @tslintCache.set basedir, linter - resolve(linter) - - provideLinter: -> - @tslintDef = require('loophole').allowUnsafeNewFunction -> - require TSLINT_MODULE_NAME - - provider = - grammarScopes: @scopes - scope: 'file' - lintOnFly: true - lint: (textEditor) => - filePath = textEditor.getPath() - text = textEditor.getText() - - @getLinter(filePath).then (Linter) => - configurationPath = Linter.findConfigurationPath null, filePath - configuration = Linter.loadConfigurationFromPath configurationPath - - rulesDirectory = configuration.rulesDirectory - if rulesDirectory - configurationDir = path.dirname configurationPath - if not Array.isArray rulesDirectory - rulesDirectory = [rulesDirectory] - rulesDirectory = rulesDirectory.map (dir) -> - if path.isAbsolute dir - then dir - else path.join configurationDir, dir - - if @rulesDirectory - rulesDirectory.push @rulesDirectory - - linter = new Linter filePath, text, - formatter: 'json' - configuration: configuration - rulesDirectory: rulesDirectory - - lintResult = linter.lint() - - if not lintResult.failureCount - return [] - - lintResult.failures.map (failure) -> - startPosition = failure.getStartPosition().getLineAndCharacter() - endPosition = failure.getEndPosition().getLineAndCharacter() - { - type: 'Warning' - text: "#{failure.getRuleName()} - #{failure.getFailure()}" - filePath: path.normalize failure.getFileName() - range: [ - [ startPosition.line, startPosition.character], - [ endPosition.line, endPosition.character] - ] - } diff --git a/lib/main.js b/lib/main.js new file mode 100644 index 00000000..24fb65b6 --- /dev/null +++ b/lib/main.js @@ -0,0 +1,144 @@ +'use babel'; + +/* eslint-disable import/extensions, import/no-extraneous-dependencies */ +import { CompositeDisposable } from 'atom'; +/* eslint-enable import/extensions, import/no-extraneous-dependencies */ +import path from 'path'; +import fs from 'fs'; +import requireResolve from 'resolve'; + +const TSLINT_MODULE_NAME = 'tslint'; +const tslintCache = new Map(); +let tslintDef = null; + +export default { + activate() { + require('atom-package-deps').install('linter-tslint'); + + this.subscriptions = new CompositeDisposable(); + this.subscriptions.add( + atom.config.observe('linter-tslint.rulesDirectory', (dir) => { + if (dir && path.isAbsolute(dir)) { + fs.stat(dir, (err, stats) => { + if (stats && stats.isDirectory()) { + this.rulesDirectory = dir; + } + }); + } + }) + ); + + this.subscriptions.add( + atom.config.observe('linter-tslint.useLocalTslint', (use) => { + tslintCache.clear(); + this.useLocalTslint = use; + }) + ); + }, + + deactivate() { + this.subscriptions.dispose(); + }, + + getLinter(filePath) { + const basedir = path.dirname(filePath); + const linter = tslintCache.get(basedir); + if (linter) { + return Promise.resolve(linter); + } + + if (this.useLocalTslint) { + return this.getLocalLinter(basedir); + } + + tslintCache.set(basedir, tslintDef); + return Promise.resolve(tslintDef); + }, + + getLocalLinter(basedir) { + return new Promise(resolve => + requireResolve(TSLINT_MODULE_NAME, { basedir }, + (err, linterPath, pkg) => { + let linter; + if (!err && pkg && pkg.version.startsWith('3.')) { + // eslint-disable-next-line import/no-dynamic-require + linter = require('loophole').allowUnsafeNewFunction(() => require(linterPath)); + } else { + linter = tslintDef; + } + tslintCache.set(basedir, linter); + return resolve(linter); + } + ) + ); + }, + + provideLinter() { + // eslint-disable-next-line import/no-dynamic-require + tslintDef = require('loophole').allowUnsafeNewFunction(() => require(TSLINT_MODULE_NAME)); + + return { + grammarScopes: ['source.ts', 'source.tsx'], + scope: 'file', + lintOnFly: true, + lint: (textEditor) => { + const filePath = textEditor.getPath(); + const text = textEditor.getText(); + + return this.getLinter(filePath).then((Linter) => { + const configurationPath = Linter.findConfigurationPath(null, filePath); + const configuration = Linter.loadConfigurationFromPath(configurationPath); + + let { rulesDirectory } = configuration; + if (rulesDirectory) { + const configurationDir = path.dirname(configurationPath); + if (!Array.isArray(rulesDirectory)) { + rulesDirectory = [rulesDirectory]; + } + rulesDirectory = rulesDirectory.map((dir) => { + if (path.isAbsolute(dir)) { + return dir; + } + return path.join(configurationDir, dir); + }); + + if (this.rulesDirectory) { + rulesDirectory.push(this.rulesDirectory); + } + } + + const linter = new Linter(filePath, text, { + formatter: 'json', + configuration, + rulesDirectory, + }); + + const lintResult = linter.lint(); + + if (textEditor.getText() !== text) { + // Text has been modified since the lint was triggered, tell linter not to update + return null; + } + + if (!lintResult.failureCount) { + return []; + } + + return lintResult.failures.map((failure) => { + const startPosition = failure.getStartPosition().getLineAndCharacter(); + const endPosition = failure.getEndPosition().getLineAndCharacter(); + return { + type: 'Warning', + text: `${failure.getRuleName()} - ${failure.getFailure()}`, + filePath: path.normalize(failure.getFileName()), + range: [ + [startPosition.line, startPosition.character], + [endPosition.line, endPosition.character], + ], + }; + }); + }); + }, + }; + }, +}; diff --git a/package.json b/package.json index 06a167bc..767dc210 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "linter-tslint", - "main": "./lib/init.coffee", + "main": "./lib/main.js", "linter-package": true, "version": "0.11.1", "description": "Linter plugin for Typescript, using tslint", @@ -10,12 +10,24 @@ }, "scripts": { "test": "apm test", - "lint": "coffeelint lib && eslint ." + "lint": "eslint ." }, "license": "MIT", "engines": { "atom": ">=1.0.0 <2.0.0" }, + "configSchema": { + "rulesDirectory": { + "type": "string", + "title": "Custom rules directory (absolute path)", + "default": "" + }, + "useLocalTslint": { + "type": "boolean", + "title": "Try using the local tslint package (if exist)", + "default": true + } + }, "dependencies": { "atom-package-deps": "4.3.1", "loophole": "^1.1.0", @@ -42,7 +54,6 @@ } }, "devDependencies": { - "coffeelint": "1.15.7", "eslint": "^3.6.0", "eslint-config-airbnb-base": "^8.0.0", "eslint-plugin-import": "^1.16.0" diff --git a/spec/linter-tslint-spec.js b/spec/linter-tslint-spec.js index ed4d328c..1fa9a1a6 100644 --- a/spec/linter-tslint-spec.js +++ b/spec/linter-tslint-spec.js @@ -6,7 +6,7 @@ const validPath = path.join(__dirname, 'fixtures', 'valid', 'valid.ts'); const invalidPath = path.join(__dirname, 'fixtures', 'invalid', 'invalid.ts'); describe('The TSLint provider for Linter', () => { - const lint = require('../lib/init.coffee').provideLinter().lint; + const lint = require('../lib/main.js').provideLinter().lint; beforeEach(() => { atom.workspace.destroyActivePaneItem();