forked from AtomLinter/linter-jscs
-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
181 lines (151 loc) · 5.34 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
'use babel';
import { Range } from 'atom';
import { findFile } from 'atom-linter';
import { readFileSync } from 'fs';
import stripJSONComments from 'strip-json-comments';
export default class LinterJSCS {
static config = {
preset: {
title: 'Preset',
description: 'Preset option is ignored if a config file is found for the linter.',
type: 'string',
default: 'airbnb',
enum: ['airbnb', 'crockford', 'google', 'grunt', 'jquery', 'mdcs', 'node-style-guide', 'wikimedia', 'wordpress', 'yandex']
},
esnext: {
description: 'Attempts to parse your code as ES6+, JSX, and Flow using the babel-jscs package as the parser.',
type: 'boolean',
default: false
},
onlyConfig: {
title: 'Only Config',
description: 'Disable linter if there is no config file found for the linter.',
type: 'boolean',
default: false
},
fixOnSave: {
title: 'Fix on save',
description: 'Fix JavaScript on save',
type: 'boolean',
default: false
},
displayAs: {
title: 'Display errors as',
type: 'string',
default: 'error',
enum: ['error', 'warning']
}
}
static get preset() {
return atom.config.get('linter-jscs.preset');
}
static get esnext() {
return atom.config.get('linter-jscs.esnext');
}
static get onlyConfig() {
return atom.config.get('linter-jscs.onlyConfig');
}
static get fixOnSave() {
return atom.config.get('linter-jscs.fixOnSave');
}
static get displayAs() {
return atom.config.get('linter-jscs.displayAs');
}
static activate() {
// Install dependencies using atom-package-deps
require("atom-package-deps").install("linter-jscs");
this.observer = atom.workspace.observeTextEditors((editor) => {
editor.getBuffer().onWillSave(() => {
if (this.fixOnSave) {
this.fixString();
}
});
});
}
static deactivate() {
this.observer.dispose();
}
static provideLinter() {
return {
grammarScopes: ['source.js', 'source.js.jsx'],
scope: 'file',
lintOnFly: true,
lint: (editor) => {
const JSCS = require('jscs');
// We need re-initialize JSCS before every lint
// or it will looses the errors, didn't trace the error
// must be something with new 2.0.0 JSCS
this.jscs = new JSCS();
this.jscs.registerDefaultRules();
const filePath = editor.getPath();
const configFiles = ['.jscsrc', '.jscs.json', 'package.json'];
// Search for project config file
let config = findFile(filePath, configFiles);
// Reset config if `jscsConfig` is not found in `package.json`
if (config && config.indexOf('package.json') > -1) {
const { jscsConfig } = require(config);
if (!jscsConfig) config = null;
}
// Search for home config file
if (!config) {
const homeDir = require('user-home');
if (homeDir) config = findFile(homeDir, configFiles);
}
// Options passed to `jscs` from package configuration
const options = { esnext: this.esnext, preset: this.preset };
if (config) {
try {
const rawConfig = readFileSync(config, { encoding: 'utf8' });
let parsedConfig = JSON.parse(stripJSONComments(rawConfig));
if (config.indexOf('package.json') > -1) {
if (parsedConfig.jscsConfig) {
parsedConfig = parsedConfig.jscsConfig;
} else {
throw new Error('No `jscsConfig` key in `package.json`');
}
}
this.jscs.configure(parsedConfig);
} catch (error) {
// Warn user only once
if (!this.warnLocalConfig) {
console.warn('[linter-jscs] No config found, or error while loading it.');
console.warn(error.stack);
this.warnLocalConfig = true;
}
// Reset config to null
config = null;
this.jscs.configure(options);
}
} else {
this.jscs.configure(options);
}
// We don't have a config file present in project directory
// let's return an empty array of errors
if (!config && this.onlyConfig) return [];
const text = editor.getText();
const errors = this.jscs
.checkString(text, filePath)
.getErrorList();
return errors.map(({ rule, message, line, column }) => {
// Calculate range to make the error whole line
// without the indentation at begining of line
const indentLevel = editor.indentationForBufferRow(line - 1);
const startCol = editor.getTabLength() * indentLevel;
const endCol = editor.getBuffer().lineLengthForRow(line - 1);
const range = [[line - 1, startCol], [line - 1, endCol]];
const type = this.displayAs;
const html = `<span class='badge badge-flexible'>${rule}</span> ${message}`;
return { type, html, filePath, range };
});
}
};
}
static fixString() {
if (!this.isMissingConfig && !this.onlyConfig) {
const editor = atom.workspace.getActiveTextEditor();
const path = editor.getPath();
const text = editor.getText();
return editor.setText(this.jscs.fixString(text, path).output);
}
}
};