eslint 1.9.0 → 1.10.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/bin/eslint.js +1 -2
- package/lib/ast-utils.js +22 -1
- package/lib/cli-engine.js +15 -7
- package/lib/cli.js +2 -1
- package/lib/config/config-file.js +440 -0
- package/lib/config/config-initializer.js +241 -0
- package/lib/config/config-ops.js +186 -0
- package/lib/{config-validator.js → config/config-validator.js} +10 -2
- package/lib/config.js +39 -183
- package/lib/eslint.js +49 -41
- package/lib/file-finder.js +34 -15
- package/lib/ignored-paths.js +1 -1
- package/lib/options.js +7 -1
- package/lib/rules/block-spacing.js +7 -2
- package/lib/rules/brace-style.js +3 -1
- package/lib/rules/comma-spacing.js +25 -66
- package/lib/rules/consistent-this.js +25 -29
- package/lib/rules/curly.js +37 -7
- package/lib/rules/eqeqeq.js +17 -2
- package/lib/rules/id-length.js +2 -2
- package/lib/rules/indent.js +7 -10
- package/lib/rules/lines-around-comment.js +32 -12
- package/lib/rules/new-cap.js +11 -1
- package/lib/rules/no-alert.js +2 -3
- package/lib/rules/no-catch-shadow.js +7 -13
- package/lib/rules/no-extend-native.js +1 -2
- package/lib/rules/no-fallthrough.js +1 -2
- package/lib/rules/no-implicit-coercion.js +19 -0
- package/lib/rules/no-label-var.js +9 -23
- package/lib/rules/no-multiple-empty-lines.js +1 -1
- package/lib/rules/no-sequences.js +2 -1
- package/lib/rules/no-shadow.js +31 -58
- package/lib/rules/no-spaced-func.js +16 -12
- package/lib/rules/no-undef-init.js +5 -3
- package/lib/rules/no-undef.js +10 -13
- package/lib/rules/no-use-before-define.js +7 -21
- package/lib/rules/operator-linebreak.js +3 -2
- package/lib/rules/quotes.js +34 -15
- package/lib/rules/require-jsdoc.js +61 -2
- package/lib/rules/space-after-keywords.js +2 -0
- package/lib/rules/space-before-function-paren.js +5 -26
- package/lib/rules/space-before-keywords.js +5 -2
- package/lib/rules/spaced-comment.js +1 -3
- package/lib/rules/valid-jsdoc.js +8 -4
- package/lib/rules/vars-on-top.js +2 -2
- package/lib/testers/rule-tester.js +48 -7
- package/lib/util/source-code.js +4 -0
- package/lib/util.js +0 -92
- package/package.json +4 -6
- package/lib/config-initializer.js +0 -146
package/README.md
CHANGED
@@ -122,5 +122,5 @@ Join our [Mailing List](https://groups.google.com/group/eslint) or [Chatroom](ht
|
|
122
122
|
[travis-url]: https://travis-ci.org/eslint/eslint
|
123
123
|
[coveralls-image]: https://img.shields.io/coveralls/eslint/eslint/master.svg?style=flat-square
|
124
124
|
[coveralls-url]: https://coveralls.io/r/eslint/eslint?branch=master
|
125
|
-
[downloads-image]:
|
125
|
+
[downloads-image]: https://img.shields.io/npm/dm/eslint.svg?style=flat-square
|
126
126
|
[downloads-url]: https://www.npmjs.com/package/eslint
|
package/bin/eslint.js
CHANGED
@@ -46,14 +46,13 @@ if (useStdIn) {
|
|
46
46
|
}
|
47
47
|
}));
|
48
48
|
} else if (init) {
|
49
|
-
var configInit = require("../lib/config-initializer");
|
49
|
+
var configInit = require("../lib/config/config-initializer");
|
50
50
|
configInit.initializeConfig(function(err) {
|
51
51
|
if (err) {
|
52
52
|
exitCode = 1;
|
53
53
|
console.error(err.message);
|
54
54
|
console.error(err.stack);
|
55
55
|
} else {
|
56
|
-
console.log("Successfully created .eslintrc file in " + process.cwd());
|
57
56
|
exitCode = 0;
|
58
57
|
}
|
59
58
|
});
|
package/lib/ast-utils.js
CHANGED
@@ -129,5 +129,26 @@ module.exports = {
|
|
129
129
|
* @param {ASTNode} A node to get.
|
130
130
|
* @returns {ASTNode|null} The trailing statement's node.
|
131
131
|
*/
|
132
|
-
getTrailingStatement: esutils.ast.trailingStatement
|
132
|
+
getTrailingStatement: esutils.ast.trailingStatement,
|
133
|
+
|
134
|
+
/**
|
135
|
+
* Finds the variable by a given name in a given scope and its upper scopes.
|
136
|
+
*
|
137
|
+
* @param {escope.Scope} initScope - A scope to start find.
|
138
|
+
* @param {string} name - A variable name to find.
|
139
|
+
* @returns {escope.Variable|null} A found variable or `null`.
|
140
|
+
*/
|
141
|
+
getVariableByName: function(initScope, name) {
|
142
|
+
var scope = initScope;
|
143
|
+
while (scope) {
|
144
|
+
var variable = scope.set.get(name);
|
145
|
+
if (variable) {
|
146
|
+
return variable;
|
147
|
+
}
|
148
|
+
|
149
|
+
scope = scope.upper;
|
150
|
+
}
|
151
|
+
|
152
|
+
return null;
|
153
|
+
}
|
133
154
|
};
|
package/lib/cli-engine.js
CHANGED
@@ -32,7 +32,7 @@ var fs = require("fs"),
|
|
32
32
|
fileEntryCache = require("file-entry-cache"),
|
33
33
|
globUtil = require("./util/glob-util"),
|
34
34
|
SourceCodeFixer = require("./util/source-code-fixer"),
|
35
|
-
validator = require("./config-validator"),
|
35
|
+
validator = require("./config/config-validator"),
|
36
36
|
stringify = require("json-stable-stringify"),
|
37
37
|
|
38
38
|
crypto = require( "crypto" ),
|
@@ -95,7 +95,8 @@ var defaultOptions = {
|
|
95
95
|
// it will always be used
|
96
96
|
cacheLocation: "",
|
97
97
|
cacheFile: ".eslintcache",
|
98
|
-
fix: false
|
98
|
+
fix: false,
|
99
|
+
allowInlineConfig: true
|
99
100
|
},
|
100
101
|
loadedPlugins = Object.create(null);
|
101
102
|
|
@@ -176,10 +177,11 @@ function calculateStatsPerRun(results) {
|
|
176
177
|
* @param {Object} configHelper The configuration options for ESLint.
|
177
178
|
* @param {string} filename An optional string representing the texts filename.
|
178
179
|
* @param {boolean} fix Indicates if fixes should be processed.
|
180
|
+
* @param {boolean} allowInlineConfig Allow/ignore comments that change config.
|
179
181
|
* @returns {Result} The results for linting on this text.
|
180
182
|
* @private
|
181
183
|
*/
|
182
|
-
function processText(text, configHelper, filename, fix) {
|
184
|
+
function processText(text, configHelper, filename, fix, allowInlineConfig) {
|
183
185
|
|
184
186
|
// clear all existing settings for a new file
|
185
187
|
eslint.reset();
|
@@ -213,7 +215,10 @@ function processText(text, configHelper, filename, fix) {
|
|
213
215
|
var parsedBlocks = processor.preprocess(text, filename);
|
214
216
|
var unprocessedMessages = [];
|
215
217
|
parsedBlocks.forEach(function(block) {
|
216
|
-
unprocessedMessages.push(eslint.verify(block, config,
|
218
|
+
unprocessedMessages.push(eslint.verify(block, config, {
|
219
|
+
filename: filename,
|
220
|
+
allowInlineConfig: allowInlineConfig
|
221
|
+
}));
|
217
222
|
});
|
218
223
|
|
219
224
|
// TODO(nzakas): Figure out how fixes might work for processors
|
@@ -222,7 +227,10 @@ function processText(text, configHelper, filename, fix) {
|
|
222
227
|
|
223
228
|
} else {
|
224
229
|
|
225
|
-
messages = eslint.verify(text, config,
|
230
|
+
messages = eslint.verify(text, config, {
|
231
|
+
filename: filename,
|
232
|
+
allowInlineConfig: allowInlineConfig
|
233
|
+
});
|
226
234
|
|
227
235
|
if (fix) {
|
228
236
|
debug("Generating fixed text for " + filename);
|
@@ -259,7 +267,7 @@ function processText(text, configHelper, filename, fix) {
|
|
259
267
|
function processFile(filename, configHelper, options) {
|
260
268
|
|
261
269
|
var text = fs.readFileSync(path.resolve(filename), "utf8"),
|
262
|
-
result = processText(text, configHelper, filename, options.fix);
|
270
|
+
result = processText(text, configHelper, filename, options.fix, options.allowInlineConfig);
|
263
271
|
|
264
272
|
return result;
|
265
273
|
|
@@ -675,7 +683,7 @@ CLIEngine.prototype = {
|
|
675
683
|
if (filename && options.ignore && exclude(filename)) {
|
676
684
|
results.push(createIgnoreResult(filename));
|
677
685
|
} else {
|
678
|
-
results.push(processText(text, configHelper, filename, options.fix));
|
686
|
+
results.push(processText(text, configHelper, filename, options.fix, options.allowInlineConfig));
|
679
687
|
}
|
680
688
|
|
681
689
|
stats = calculateStatsPerRun(results);
|
package/lib/cli.js
CHANGED
@@ -0,0 +1,440 @@
|
|
1
|
+
/**
|
2
|
+
* @fileoverview Helper to locate and load configuration files.
|
3
|
+
* @author Nicholas C. Zakas
|
4
|
+
* @copyright 2015 Nicholas C. Zakas. All rights reserved.
|
5
|
+
* See LICENSE file in root directory for full license.
|
6
|
+
*/
|
7
|
+
/* eslint no-use-before-define: 0 */
|
8
|
+
"use strict";
|
9
|
+
|
10
|
+
//------------------------------------------------------------------------------
|
11
|
+
// Requirements
|
12
|
+
//------------------------------------------------------------------------------
|
13
|
+
|
14
|
+
var debug = require("debug"),
|
15
|
+
fs = require("fs"),
|
16
|
+
path = require("path"),
|
17
|
+
ConfigOps = require("./config-ops"),
|
18
|
+
validator = require("./config-validator"),
|
19
|
+
stripComments = require("strip-json-comments"),
|
20
|
+
isAbsolutePath = require("path-is-absolute");
|
21
|
+
|
22
|
+
//------------------------------------------------------------------------------
|
23
|
+
// Private
|
24
|
+
//------------------------------------------------------------------------------
|
25
|
+
|
26
|
+
var CONFIG_FILES = [
|
27
|
+
".eslintrc.js",
|
28
|
+
".eslintrc.yaml",
|
29
|
+
".eslintrc.yml",
|
30
|
+
".eslintrc.json",
|
31
|
+
".eslintrc"
|
32
|
+
];
|
33
|
+
|
34
|
+
debug = debug("eslint:config-file");
|
35
|
+
|
36
|
+
/**
|
37
|
+
* Convenience wrapper for synchronously reading file contents.
|
38
|
+
* @param {string} filePath The filename to read.
|
39
|
+
* @returns {string} The file contents.
|
40
|
+
* @private
|
41
|
+
*/
|
42
|
+
function readFile(filePath) {
|
43
|
+
return fs.readFileSync(filePath, "utf8");
|
44
|
+
}
|
45
|
+
|
46
|
+
/**
|
47
|
+
* Determines if a given string represents a filepath or not using the same
|
48
|
+
* conventions as require(), meaning that the first character must be nonalphanumeric
|
49
|
+
* and not the @ sign which is used for scoped packages to be considered a file path.
|
50
|
+
* @param {string} filePath The string to check.
|
51
|
+
* @returns {boolean} True if it's a filepath, false if not.
|
52
|
+
* @private
|
53
|
+
*/
|
54
|
+
function isFilePath(filePath) {
|
55
|
+
return isAbsolutePath(filePath) || !/\w|@/.test(filePath.charAt(0));
|
56
|
+
}
|
57
|
+
|
58
|
+
/**
|
59
|
+
* Loads a YAML configuration from a file.
|
60
|
+
* @param {string} filePath The filename to load.
|
61
|
+
* @returns {Object} The configuration object from the file.
|
62
|
+
* @throws {Error} If the file cannot be read.
|
63
|
+
* @private
|
64
|
+
*/
|
65
|
+
function loadYAMLConfigFile(filePath) {
|
66
|
+
debug("Loading YAML config file: " + filePath);
|
67
|
+
|
68
|
+
// lazy load YAML to improve performance when not used
|
69
|
+
var yaml = require("js-yaml");
|
70
|
+
|
71
|
+
try {
|
72
|
+
// empty YAML file can be null, so always use
|
73
|
+
return yaml.safeLoad(readFile(filePath)) || {};
|
74
|
+
} catch (e) {
|
75
|
+
debug("Error reading YAML file: " + filePath);
|
76
|
+
e.message = "Cannot read config file: " + filePath + "\nError: " + e.message;
|
77
|
+
throw e;
|
78
|
+
}
|
79
|
+
}
|
80
|
+
|
81
|
+
/**
|
82
|
+
* Loads a JSON configuration from a file.
|
83
|
+
* @param {string} filePath The filename to load.
|
84
|
+
* @returns {Object} The configuration object from the file.
|
85
|
+
* @throws {Error} If the file cannot be read.
|
86
|
+
* @private
|
87
|
+
*/
|
88
|
+
function loadJSONConfigFile(filePath) {
|
89
|
+
debug("Loading JSON config file: " + filePath);
|
90
|
+
|
91
|
+
try {
|
92
|
+
return JSON.parse(stripComments(readFile(filePath)));
|
93
|
+
} catch (e) {
|
94
|
+
debug("Error reading JSON file: " + filePath);
|
95
|
+
e.message = "Cannot read config file: " + filePath + "\nError: " + e.message;
|
96
|
+
throw e;
|
97
|
+
}
|
98
|
+
}
|
99
|
+
|
100
|
+
/**
|
101
|
+
* Loads a legacy (.eslintrc) configuration from a file.
|
102
|
+
* @param {string} filePath The filename to load.
|
103
|
+
* @returns {Object} The configuration object from the file.
|
104
|
+
* @throws {Error} If the file cannot be read.
|
105
|
+
* @private
|
106
|
+
*/
|
107
|
+
function loadLegacyConfigFile(filePath) {
|
108
|
+
debug("Loading config file: " + filePath);
|
109
|
+
|
110
|
+
// lazy load YAML to improve performance when not used
|
111
|
+
var yaml = require("js-yaml");
|
112
|
+
|
113
|
+
try {
|
114
|
+
return yaml.safeLoad(stripComments(readFile(filePath))) || {};
|
115
|
+
} catch (e) {
|
116
|
+
debug("Error reading YAML file: " + filePath);
|
117
|
+
e.message = "Cannot read config file: " + filePath + "\nError: " + e.message;
|
118
|
+
throw e;
|
119
|
+
}
|
120
|
+
}
|
121
|
+
|
122
|
+
/**
|
123
|
+
* Loads a JavaScript configuration from a file.
|
124
|
+
* @param {string} filePath The filename to load.
|
125
|
+
* @returns {Object} The configuration object from the file.
|
126
|
+
* @throws {Error} If the file cannot be read.
|
127
|
+
* @private
|
128
|
+
*/
|
129
|
+
function loadJSConfigFile(filePath) {
|
130
|
+
debug("Loading JS config file: " + filePath);
|
131
|
+
try {
|
132
|
+
return require(filePath);
|
133
|
+
} catch (e) {
|
134
|
+
debug("Error reading JavaScript file: " + filePath);
|
135
|
+
e.message = "Cannot read config file: " + filePath + "\nError: " + e.message;
|
136
|
+
throw e;
|
137
|
+
}
|
138
|
+
}
|
139
|
+
|
140
|
+
/**
|
141
|
+
* Loads a configuration from a package.json file.
|
142
|
+
* @param {string} filePath The filename to load.
|
143
|
+
* @returns {Object} The configuration object from the file.
|
144
|
+
* @throws {Error} If the file cannot be read.
|
145
|
+
* @private
|
146
|
+
*/
|
147
|
+
function loadPackageJSONConfigFile(filePath) {
|
148
|
+
debug("Loading package.json config file: " + filePath);
|
149
|
+
try {
|
150
|
+
return require(filePath).eslintConfig || null;
|
151
|
+
} catch (e) {
|
152
|
+
debug("Error reading package.json file: " + filePath);
|
153
|
+
e.message = "Cannot read config file: " + filePath + "\nError: " + e.message;
|
154
|
+
throw e;
|
155
|
+
}
|
156
|
+
}
|
157
|
+
|
158
|
+
/**
|
159
|
+
* Loads a JavaScript configuration from a package.
|
160
|
+
* @param {string} filePath The package name to load.
|
161
|
+
* @returns {Object} The configuration object from the package.
|
162
|
+
* @throws {Error} If the package cannot be read.
|
163
|
+
* @private
|
164
|
+
*/
|
165
|
+
function loadPackage(filePath) {
|
166
|
+
debug("Loading config package: " + filePath);
|
167
|
+
try {
|
168
|
+
return require(filePath);
|
169
|
+
} catch (e) {
|
170
|
+
debug("Error reading package: " + filePath);
|
171
|
+
e.message = "Cannot read config package: " + filePath + "\nError: " + e.message;
|
172
|
+
throw e;
|
173
|
+
}
|
174
|
+
}
|
175
|
+
|
176
|
+
/**
|
177
|
+
* Loads a configuration file regardless of the source. Inspects the file path
|
178
|
+
* to determine the correctly way to load the config file.
|
179
|
+
* @param {string} filePath The path to the configuration.
|
180
|
+
* @returns {Object} The configuration information.
|
181
|
+
* @private
|
182
|
+
*/
|
183
|
+
function loadConfigFile(filePath) {
|
184
|
+
var config;
|
185
|
+
|
186
|
+
if (isFilePath(filePath)) {
|
187
|
+
switch (path.extname(filePath)) {
|
188
|
+
case ".js":
|
189
|
+
config = loadJSConfigFile(filePath);
|
190
|
+
break;
|
191
|
+
|
192
|
+
case ".json":
|
193
|
+
if (path.basename(filePath) === "package.json") {
|
194
|
+
config = loadPackageJSONConfigFile(filePath);
|
195
|
+
if (config === null) {
|
196
|
+
return null;
|
197
|
+
}
|
198
|
+
} else {
|
199
|
+
config = loadJSONConfigFile(filePath);
|
200
|
+
}
|
201
|
+
break;
|
202
|
+
|
203
|
+
case ".yaml":
|
204
|
+
case ".yml":
|
205
|
+
config = loadYAMLConfigFile(filePath);
|
206
|
+
break;
|
207
|
+
|
208
|
+
default:
|
209
|
+
config = loadLegacyConfigFile(filePath);
|
210
|
+
}
|
211
|
+
} else {
|
212
|
+
config = loadPackage(filePath);
|
213
|
+
}
|
214
|
+
|
215
|
+
return ConfigOps.merge(ConfigOps.createEmptyConfig(), config);
|
216
|
+
}
|
217
|
+
|
218
|
+
/**
|
219
|
+
* Writes a configuration file in JSON format.
|
220
|
+
* @param {Object} config The configuration object to write.
|
221
|
+
* @param {string} filePath The filename to write to.
|
222
|
+
* @returns {void}
|
223
|
+
* @private
|
224
|
+
*/
|
225
|
+
function writeJSONConfigFile(config, filePath) {
|
226
|
+
debug("Writing JSON config file: " + filePath);
|
227
|
+
|
228
|
+
var content = JSON.stringify(config, null, 4);
|
229
|
+
fs.writeFileSync(filePath, content, "utf8");
|
230
|
+
}
|
231
|
+
|
232
|
+
/**
|
233
|
+
* Writes a configuration file in YAML format.
|
234
|
+
* @param {Object} config The configuration object to write.
|
235
|
+
* @param {string} filePath The filename to write to.
|
236
|
+
* @returns {void}
|
237
|
+
* @private
|
238
|
+
*/
|
239
|
+
function writeYAMLConfigFile(config, filePath) {
|
240
|
+
debug("Writing YAML config file: " + filePath);
|
241
|
+
|
242
|
+
// lazy load YAML to improve performance when not used
|
243
|
+
var yaml = require("js-yaml");
|
244
|
+
|
245
|
+
var content = yaml.safeDump(config);
|
246
|
+
fs.writeFileSync(filePath, content, "utf8");
|
247
|
+
}
|
248
|
+
|
249
|
+
/**
|
250
|
+
* Writes a configuration file in JavaScript format.
|
251
|
+
* @param {Object} config The configuration object to write.
|
252
|
+
* @param {string} filePath The filename to write to.
|
253
|
+
* @returns {void}
|
254
|
+
* @private
|
255
|
+
*/
|
256
|
+
function writeJSConfigFile(config, filePath) {
|
257
|
+
debug("Writing JS config file: " + filePath);
|
258
|
+
|
259
|
+
var content = "module.exports = " + JSON.stringify(config, null, 4) + ";";
|
260
|
+
fs.writeFileSync(filePath, content, "utf8");
|
261
|
+
}
|
262
|
+
|
263
|
+
/**
|
264
|
+
* Writes a configuration file.
|
265
|
+
* @param {Object} config The configuration object to write.
|
266
|
+
* @param {string} filePath The filename to write to.
|
267
|
+
* @returns {void}
|
268
|
+
* @throws {Error} When an unknown file type is specified.
|
269
|
+
* @private
|
270
|
+
*/
|
271
|
+
function write(config, filePath) {
|
272
|
+
switch (path.extname(filePath)) {
|
273
|
+
case ".js":
|
274
|
+
writeJSConfigFile(config, filePath);
|
275
|
+
break;
|
276
|
+
|
277
|
+
case ".json":
|
278
|
+
writeJSONConfigFile(config, filePath);
|
279
|
+
break;
|
280
|
+
|
281
|
+
case ".yaml":
|
282
|
+
case ".yml":
|
283
|
+
writeYAMLConfigFile(config, filePath);
|
284
|
+
break;
|
285
|
+
|
286
|
+
default:
|
287
|
+
throw new Error("Can't write to unknown file type.");
|
288
|
+
}
|
289
|
+
}
|
290
|
+
|
291
|
+
/**
|
292
|
+
* Applies values from the "extends" field in a configuration file.
|
293
|
+
* @param {Object} config The configuration information.
|
294
|
+
* @param {string} filePath The file path from which the configuration information
|
295
|
+
* was loaded.
|
296
|
+
* @returns {Object} A new configuration object with all of the "extends" fields
|
297
|
+
* loaded and merged.
|
298
|
+
* @private
|
299
|
+
*/
|
300
|
+
function applyExtends(config, filePath) {
|
301
|
+
var configExtends = config.extends;
|
302
|
+
|
303
|
+
// normalize into an array for easier handling
|
304
|
+
if (!Array.isArray(config.extends)) {
|
305
|
+
configExtends = [config.extends];
|
306
|
+
}
|
307
|
+
|
308
|
+
// Make the last element in an array take the highest precedence
|
309
|
+
config = configExtends.reduceRight(function(previousValue, parentPath) {
|
310
|
+
|
311
|
+
if (parentPath === "eslint:recommended") {
|
312
|
+
// Add an explicit substitution for eslint:recommended to conf/eslint.json
|
313
|
+
// this lets us use the eslint.json file as the recommended rules
|
314
|
+
parentPath = path.resolve(__dirname, "../../conf/eslint.json");
|
315
|
+
} else if (isFilePath(parentPath)) {
|
316
|
+
// If the `extends` path is relative, use the directory of the current configuration
|
317
|
+
// file as the reference point. Otherwise, use as-is.
|
318
|
+
parentPath = (!isAbsolutePath(parentPath) ?
|
319
|
+
path.join(path.dirname(filePath), parentPath) :
|
320
|
+
parentPath
|
321
|
+
);
|
322
|
+
}
|
323
|
+
|
324
|
+
try {
|
325
|
+
debug("Loading " + parentPath);
|
326
|
+
return ConfigOps.merge(load(parentPath), previousValue);
|
327
|
+
} catch (e) {
|
328
|
+
// If the file referenced by `extends` failed to load, add the path to the
|
329
|
+
// configuration file that referenced it to the error message so the user is
|
330
|
+
// able to see where it was referenced from, then re-throw
|
331
|
+
e.message += "\nReferenced from: " + filePath;
|
332
|
+
throw e;
|
333
|
+
}
|
334
|
+
|
335
|
+
}, config);
|
336
|
+
|
337
|
+
return config;
|
338
|
+
}
|
339
|
+
|
340
|
+
/**
|
341
|
+
* Resolves a configuration file path into the fully-formed path, whether filename
|
342
|
+
* or package name.
|
343
|
+
* @param {string} filePath The filepath to resolve.
|
344
|
+
* @returns {string} A path that can be used directly to load the configuration.
|
345
|
+
* @private
|
346
|
+
*/
|
347
|
+
function resolve(filePath) {
|
348
|
+
|
349
|
+
if (isFilePath(filePath)) {
|
350
|
+
return path.resolve(filePath);
|
351
|
+
} else {
|
352
|
+
|
353
|
+
// it's a package
|
354
|
+
|
355
|
+
if (filePath.charAt(0) === "@") {
|
356
|
+
// it's a scoped package
|
357
|
+
|
358
|
+
// package name is "eslint-config", or just a username
|
359
|
+
var scopedPackageShortcutRegex = /^(@[^\/]+)(?:\/(?:eslint-config)?)?$/;
|
360
|
+
if (scopedPackageShortcutRegex.test(filePath)) {
|
361
|
+
filePath = filePath.replace(scopedPackageShortcutRegex, "$1/eslint-config");
|
362
|
+
} else if (filePath.split("/")[1].indexOf("eslint-config-") !== 0) {
|
363
|
+
// for scoped packages, insert the eslint-config after the first /
|
364
|
+
filePath = filePath.replace(/^@([^\/]+)\/(.*)$/, "@$1/eslint-config-$2");
|
365
|
+
}
|
366
|
+
} else if (filePath.indexOf("eslint-config-") !== 0) {
|
367
|
+
filePath = "eslint-config-" + filePath;
|
368
|
+
}
|
369
|
+
|
370
|
+
return filePath;
|
371
|
+
}
|
372
|
+
|
373
|
+
}
|
374
|
+
|
375
|
+
/**
|
376
|
+
* Loads a configuration file from the given file path.
|
377
|
+
* @param {string} filePath The filename or package name to load the configuration
|
378
|
+
* information from.
|
379
|
+
* @returns {Object} The configuration information.
|
380
|
+
* @private
|
381
|
+
*/
|
382
|
+
function load(filePath) {
|
383
|
+
|
384
|
+
var resolvedPath = resolve(filePath),
|
385
|
+
config = loadConfigFile(resolvedPath);
|
386
|
+
|
387
|
+
if (config) {
|
388
|
+
|
389
|
+
// validate the configuration before continuing
|
390
|
+
validator.validate(config, filePath);
|
391
|
+
|
392
|
+
// If an `extends` property is defined, it represents a configuration file to use as
|
393
|
+
// a "parent". Load the referenced file and merge the configuration recursively.
|
394
|
+
if (config.extends) {
|
395
|
+
config = applyExtends(config, filePath);
|
396
|
+
}
|
397
|
+
|
398
|
+
if (config.env) {
|
399
|
+
// Merge in environment-specific globals and ecmaFeatures.
|
400
|
+
config = ConfigOps.applyEnvironments(config);
|
401
|
+
}
|
402
|
+
|
403
|
+
}
|
404
|
+
|
405
|
+
return config;
|
406
|
+
}
|
407
|
+
|
408
|
+
//------------------------------------------------------------------------------
|
409
|
+
// Public Interface
|
410
|
+
//------------------------------------------------------------------------------
|
411
|
+
|
412
|
+
module.exports = {
|
413
|
+
|
414
|
+
load: load,
|
415
|
+
resolve: resolve,
|
416
|
+
write: write,
|
417
|
+
applyExtends: applyExtends,
|
418
|
+
CONFIG_FILES: CONFIG_FILES,
|
419
|
+
|
420
|
+
/**
|
421
|
+
* Retrieves the configuration filename for a given directory. It loops over all
|
422
|
+
* of the valid configuration filenames in order to find the first one that exists.
|
423
|
+
* @param {string} directory The directory to check for a config file.
|
424
|
+
* @returns {?string} The filename of the configuration file for the directory
|
425
|
+
* or null if there is no configuration file in the directory.
|
426
|
+
*/
|
427
|
+
getFilenameForDirectory: function(directory) {
|
428
|
+
|
429
|
+
var filename;
|
430
|
+
|
431
|
+
for (var i = 0, len = CONFIG_FILES.length; i < len; i++) {
|
432
|
+
filename = path.join(directory, CONFIG_FILES[i]);
|
433
|
+
if (fs.existsSync(filename)) {
|
434
|
+
return filename;
|
435
|
+
}
|
436
|
+
}
|
437
|
+
|
438
|
+
return null;
|
439
|
+
}
|
440
|
+
};
|