eslint 4.18.0 → 4.19.1
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/CHANGELOG.md +40 -0
- package/README.md +2 -2
- package/conf/environments.js +3 -1
- package/conf/eslint-recommended.js +0 -0
- package/lib/ast-utils.js +25 -29
- package/lib/cli-engine.js +29 -28
- package/lib/code-path-analysis/code-path-state.js +5 -5
- package/lib/code-path-analysis/code-path.js +11 -6
- package/lib/code-path-analysis/fork-context.js +10 -12
- package/lib/config/config-file.js +20 -11
- package/lib/config/config-ops.js +8 -10
- package/lib/config/config-rule.js +2 -3
- package/lib/config/plugins.js +20 -0
- package/lib/config.js +7 -8
- package/lib/file-finder.js +9 -10
- package/lib/ignored-paths.js +4 -4
- package/lib/linter.js +397 -406
- package/lib/load-rules.js +6 -7
- package/lib/rules/accessor-pairs.js +4 -4
- package/lib/rules/array-callback-return.js +8 -6
- package/lib/rules/array-element-newline.js +4 -4
- package/lib/rules/curly.js +11 -10
- package/lib/rules/generator-star-spacing.js +1 -2
- package/lib/rules/indent-legacy.js +7 -10
- package/lib/rules/indent.js +51 -29
- package/lib/rules/keyword-spacing.js +6 -18
- package/lib/rules/max-len.js +12 -5
- package/lib/rules/no-await-in-loop.js +1 -1
- package/lib/rules/no-buffer-constructor.js +1 -1
- package/lib/rules/no-control-regex.js +51 -72
- package/lib/rules/no-else-return.js +7 -6
- package/lib/rules/no-empty-character-class.js +1 -1
- package/lib/rules/no-eval.js +7 -8
- package/lib/rules/no-extra-parens.js +5 -4
- package/lib/rules/no-implicit-coercion.js +6 -9
- package/lib/rules/no-invalid-regexp.js +53 -36
- package/lib/rules/no-irregular-whitespace.js +1 -1
- package/lib/rules/no-loop-func.js +9 -11
- package/lib/rules/no-magic-numbers.js +17 -10
- package/lib/rules/no-return-assign.js +4 -3
- package/lib/rules/no-unexpected-multiline.js +1 -1
- package/lib/rules/no-unsafe-finally.js +7 -4
- package/lib/rules/no-useless-escape.js +2 -2
- package/lib/rules/no-useless-return.js +10 -9
- package/lib/rules/no-var.js +8 -8
- package/lib/rules/object-curly-newline.js +2 -1
- package/lib/rules/one-var.js +140 -97
- package/lib/rules/padding-line-between-statements.js +6 -4
- package/lib/rules/prefer-arrow-callback.js +5 -4
- package/lib/rules/prefer-template.js +5 -3
- package/lib/rules/space-unary-ops.js +1 -3
- package/lib/rules/spaced-comment.js +3 -7
- package/lib/rules/template-tag-spacing.js +0 -0
- package/lib/rules/valid-jsdoc.js +6 -6
- package/lib/rules/vars-on-top.js +7 -17
- package/lib/timing.js +3 -5
- package/lib/util/glob-util.js +11 -11
- package/lib/util/interpolate.js +5 -1
- package/lib/util/naming.js +11 -10
- package/lib/util/npm-util.js +4 -6
- package/lib/util/path-util.js +6 -8
- package/lib/util/source-code-util.js +23 -26
- package/lib/util/source-code.js +4 -3
- package/package.json +4 -3
- package/conf/default-config-options.js +0 -29
package/CHANGELOG.md
CHANGED
@@ -1,3 +1,43 @@
|
|
1
|
+
v4.19.1 - March 21, 2018
|
2
|
+
|
3
|
+
* 3ff5d11 Fix: no-invalid-regexp not understand variable for flags (fixes #10112) (#10113) (薛定谔的猫)
|
4
|
+
* abc765c Fix: object-curly-newline minProperties w/default export (fixes #10101) (#10103) (Kevin Partington)
|
5
|
+
* 6f9e155 Docs: Update ambiguous for...in example for guard-for-in (#10114) (CJ R)
|
6
|
+
* 0360cc2 Chore: Adding debug logs on successful plugin loads (#10100) (Kevin Partington)
|
7
|
+
* a717c5d Chore: Adding log at beginning of unit tests in Makefile.js (#10102) (Kevin Partington)
|
8
|
+
|
9
|
+
v4.19.0 - March 16, 2018
|
10
|
+
|
11
|
+
* 55a1593 Update: consecutive option for one-var (fixes #4680) (#9994) (薛定谔的猫)
|
12
|
+
* 8d3814e Fix: false positive about ES2018 RegExp enhancements (fixes #9893) (#10062) (Toru Nagashima)
|
13
|
+
* 935f4e4 Docs: Clarify default ignoring of node_modules (#10092) (Matijs Brinkhuis)
|
14
|
+
* 72ed3db Docs: Wrap `Buffer()` in backticks in `no-buffer-constructor` rule description (#10084) (Stephen Edgar)
|
15
|
+
* 3aded2f Docs: Fix lodash typos, make spacing consistent (#10073) (Josh Smith)
|
16
|
+
* e33bb64 Chore: enable no-param-reassign on ESLint codebase (#10065) (Teddy Katz)
|
17
|
+
* 66a1e9a Docs: fix possible typo (#10060) (Vse Mozhet Byt)
|
18
|
+
* 2e68be6 Update: give a node at least the indentation of its parent (fixes #9995) (#10054) (Teddy Katz)
|
19
|
+
* 72ca5b3 Update: Correctly indent JSXText with trailing linebreaks (fixes #9878) (#10055) (Teddy Katz)
|
20
|
+
* 2a4c838 Docs: Update ECMAScript versions in FAQ (#10047) (alberto)
|
21
|
+
|
22
|
+
v4.18.2 - March 2, 2018
|
23
|
+
|
24
|
+
* 6b71fd0 Fix: table@4.0.2, because 4.0.3 needs "ajv": "^6.0.1" (#10022) (Mathieu Seiler)
|
25
|
+
* 3c697de Chore: fix incorrect comment about linter.verify return value (#10030) (Teddy Katz)
|
26
|
+
* 9df8653 Chore: refactor parser-loading out of linter.verify (#10028) (Teddy Katz)
|
27
|
+
* f6901d0 Fix: remove catastrophic backtracking vulnerability (fixes #10002) (#10019) (Jamie Davis)
|
28
|
+
* e4f52ce Chore: Simplify dataflow in linter.verify (#10020) (Teddy Katz)
|
29
|
+
* 33177cd Chore: make library files non-executable (#10021) (Teddy Katz)
|
30
|
+
* 558ccba Chore: refactor directive comment processing (#10007) (Teddy Katz)
|
31
|
+
* 18e15d9 Chore: avoid useless catch clauses that just rethrow errors (#10010) (Teddy Katz)
|
32
|
+
* a1c3759 Chore: refactor populating configs with defaults in linter (#10006) (Teddy Katz)
|
33
|
+
* aea07dc Fix: Make max-len ignoreStrings ignore JSXText (fixes #9954) (#9985) (Rachael Sim)
|
34
|
+
|
35
|
+
v4.18.1 - February 20, 2018
|
36
|
+
|
37
|
+
* f417506 Fix: ensure no-await-in-loop reports the correct node (fixes #9992) (#9993) (Teddy Katz)
|
38
|
+
* 3e99363 Docs: Fixed typo in key-spacing rule doc (#9987) (Jaid)
|
39
|
+
* 7c2cd70 Docs: deprecate experimentalObjectRestSpread (#9986) (Toru Nagashima)
|
40
|
+
|
1
41
|
v4.18.0 - February 16, 2018
|
2
42
|
|
3
43
|
* 70f22f3 Chore: Apply memoization to config creation within glob utils (#9944) (Kenton Jacobsen)
|
package/README.md
CHANGED
@@ -227,9 +227,9 @@ In all cases, make sure your plugins' peerDependencies have been installed as we
|
|
227
227
|
|
228
228
|
Yes, ESLint natively supports parsing JSX syntax (this must be enabled in [configuration](https://eslint.org/docs/user-guide/configuring)). Please note that supporting JSX syntax *is not* the same as supporting React. React applies specific semantics to JSX syntax that ESLint doesn't recognize. We recommend using [eslint-plugin-react](https://www.npmjs.com/package/eslint-plugin-react) if you are using React and want React semantics.
|
229
229
|
|
230
|
-
### What
|
230
|
+
### What ECMAScript versions does ESLint support?
|
231
231
|
|
232
|
-
ESLint has full support for ECMAScript
|
232
|
+
ESLint has full support for ECMAScript 3, 5 (default), 2015, 2016, 2017, and 2018. You can set your desired ECMAScript syntax (and other settings, like global variables or your target environments) through [configuration](https://eslint.org/docs/user-guide/configuring).
|
233
233
|
|
234
234
|
### What about experimental features?
|
235
235
|
|
package/conf/environments.js
CHANGED
File without changes
|
package/lib/ast-utils.js
CHANGED
@@ -84,11 +84,10 @@ function isES5Constructor(node) {
|
|
84
84
|
* @returns {Node|null} A found function node.
|
85
85
|
*/
|
86
86
|
function getUpperFunction(node) {
|
87
|
-
|
88
|
-
if (anyFunctionPattern.test(
|
89
|
-
return
|
87
|
+
for (let currentNode = node; currentNode; currentNode = currentNode.parent) {
|
88
|
+
if (anyFunctionPattern.test(currentNode.type)) {
|
89
|
+
return currentNode;
|
90
90
|
}
|
91
|
-
node = node.parent;
|
92
91
|
}
|
93
92
|
return null;
|
94
93
|
}
|
@@ -132,12 +131,10 @@ function isLoop(node) {
|
|
132
131
|
* @returns {boolean} `true` if the node is in a loop.
|
133
132
|
*/
|
134
133
|
function isInLoop(node) {
|
135
|
-
|
136
|
-
if (isLoop(
|
134
|
+
for (let currentNode = node; currentNode && !isFunction(currentNode); currentNode = currentNode.parent) {
|
135
|
+
if (isLoop(currentNode)) {
|
137
136
|
return true;
|
138
137
|
}
|
139
|
-
|
140
|
-
node = node.parent;
|
141
138
|
}
|
142
139
|
|
143
140
|
return false;
|
@@ -204,16 +201,14 @@ function isArrayFromMethod(node) {
|
|
204
201
|
* @returns {boolean} Whether or not the node is a method which has `thisArg`.
|
205
202
|
*/
|
206
203
|
function isMethodWhichHasThisArg(node) {
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
204
|
+
for (
|
205
|
+
let currentNode = node;
|
206
|
+
currentNode.type === "MemberExpression" && !currentNode.computed;
|
207
|
+
currentNode = currentNode.property
|
208
|
+
) {
|
209
|
+
if (currentNode.property.type === "Identifier") {
|
210
|
+
return arrayMethodPattern.test(currentNode.property.name);
|
214
211
|
}
|
215
|
-
|
216
|
-
break;
|
217
212
|
}
|
218
213
|
|
219
214
|
return false;
|
@@ -631,9 +626,10 @@ module.exports = {
|
|
631
626
|
return false;
|
632
627
|
}
|
633
628
|
const isAnonymous = node.id === null;
|
629
|
+
let currentNode = node;
|
634
630
|
|
635
|
-
while (
|
636
|
-
const parent =
|
631
|
+
while (currentNode) {
|
632
|
+
const parent = currentNode.parent;
|
637
633
|
|
638
634
|
switch (parent.type) {
|
639
635
|
|
@@ -643,7 +639,7 @@ module.exports = {
|
|
643
639
|
*/
|
644
640
|
case "LogicalExpression":
|
645
641
|
case "ConditionalExpression":
|
646
|
-
|
642
|
+
currentNode = parent;
|
647
643
|
break;
|
648
644
|
|
649
645
|
/*
|
@@ -663,14 +659,14 @@ module.exports = {
|
|
663
659
|
if (func === null || !isCallee(func)) {
|
664
660
|
return true;
|
665
661
|
}
|
666
|
-
|
662
|
+
currentNode = func.parent;
|
667
663
|
break;
|
668
664
|
}
|
669
665
|
case "ArrowFunctionExpression":
|
670
|
-
if (
|
666
|
+
if (currentNode !== parent.body || !isCallee(parent)) {
|
671
667
|
return true;
|
672
668
|
}
|
673
|
-
|
669
|
+
currentNode = parent.parent;
|
674
670
|
break;
|
675
671
|
|
676
672
|
/*
|
@@ -685,7 +681,7 @@ module.exports = {
|
|
685
681
|
*/
|
686
682
|
case "Property":
|
687
683
|
case "MethodDefinition":
|
688
|
-
return parent.value !==
|
684
|
+
return parent.value !== currentNode;
|
689
685
|
|
690
686
|
/*
|
691
687
|
* e.g.
|
@@ -715,7 +711,7 @@ module.exports = {
|
|
715
711
|
case "VariableDeclarator":
|
716
712
|
return !(
|
717
713
|
isAnonymous &&
|
718
|
-
parent.init ===
|
714
|
+
parent.init === currentNode &&
|
719
715
|
parent.id.type === "Identifier" &&
|
720
716
|
startsWithUpperCase(parent.id.name)
|
721
717
|
);
|
@@ -728,7 +724,7 @@ module.exports = {
|
|
728
724
|
*/
|
729
725
|
case "MemberExpression":
|
730
726
|
return (
|
731
|
-
parent.object !==
|
727
|
+
parent.object !== currentNode ||
|
732
728
|
parent.property.type !== "Identifier" ||
|
733
729
|
!bindOrCallOrApplyPattern.test(parent.property.name) ||
|
734
730
|
!isCallee(parent) ||
|
@@ -746,21 +742,21 @@ module.exports = {
|
|
746
742
|
if (isReflectApply(parent.callee)) {
|
747
743
|
return (
|
748
744
|
parent.arguments.length !== 3 ||
|
749
|
-
parent.arguments[0] !==
|
745
|
+
parent.arguments[0] !== currentNode ||
|
750
746
|
isNullOrUndefined(parent.arguments[1])
|
751
747
|
);
|
752
748
|
}
|
753
749
|
if (isArrayFromMethod(parent.callee)) {
|
754
750
|
return (
|
755
751
|
parent.arguments.length !== 3 ||
|
756
|
-
parent.arguments[1] !==
|
752
|
+
parent.arguments[1] !== currentNode ||
|
757
753
|
isNullOrUndefined(parent.arguments[2])
|
758
754
|
);
|
759
755
|
}
|
760
756
|
if (isMethodWhichHasThisArg(parent.callee)) {
|
761
757
|
return (
|
762
758
|
parent.arguments.length !== 2 ||
|
763
|
-
parent.arguments[0] !==
|
759
|
+
parent.arguments[0] !== currentNode ||
|
764
760
|
isNullOrUndefined(parent.arguments[1])
|
765
761
|
);
|
766
762
|
}
|
package/lib/cli-engine.js
CHANGED
@@ -157,8 +157,9 @@ function processText(text, configHelper, filename, fix, allowInlineConfig, repor
|
|
157
157
|
fileExtension = path.extname(filename);
|
158
158
|
}
|
159
159
|
|
160
|
-
|
161
|
-
|
160
|
+
const effectiveFilename = filename || "<text>";
|
161
|
+
|
162
|
+
debug(`Linting ${effectiveFilename}`);
|
162
163
|
const config = configHelper.getConfig(filePath);
|
163
164
|
|
164
165
|
if (config.plugins) {
|
@@ -177,18 +178,18 @@ function processText(text, configHelper, filename, fix, allowInlineConfig, repor
|
|
177
178
|
const autofixingEnabled = typeof fix !== "undefined" && (!processor || processor.supportsAutofix);
|
178
179
|
|
179
180
|
const fixedResult = linter.verifyAndFix(text, config, {
|
180
|
-
filename,
|
181
|
+
filename: effectiveFilename,
|
181
182
|
allowInlineConfig,
|
182
183
|
reportUnusedDisableDirectives,
|
183
184
|
fix: !!autofixingEnabled && fix,
|
184
|
-
preprocess: processor && (rawText => processor.preprocess(rawText,
|
185
|
-
postprocess: processor && (problemLists => processor.postprocess(problemLists,
|
185
|
+
preprocess: processor && (rawText => processor.preprocess(rawText, effectiveFilename)),
|
186
|
+
postprocess: processor && (problemLists => processor.postprocess(problemLists, effectiveFilename))
|
186
187
|
});
|
187
188
|
|
188
189
|
const stats = calculateStatsPerFile(fixedResult.messages);
|
189
190
|
|
190
191
|
const result = {
|
191
|
-
filePath:
|
192
|
+
filePath: effectiveFilename,
|
192
193
|
messages: fixedResult.messages,
|
193
194
|
errorCount: stats.errorCount,
|
194
195
|
warningCount: stats.warningCount,
|
@@ -302,10 +303,10 @@ function getCacheFile(cacheFile, cwd) {
|
|
302
303
|
* make sure the path separators are normalized for the environment/os
|
303
304
|
* keeping the trailing path separator if present
|
304
305
|
*/
|
305
|
-
|
306
|
+
const normalizedCacheFile = path.normalize(cacheFile);
|
306
307
|
|
307
|
-
const resolvedCacheFile = path.resolve(cwd,
|
308
|
-
const looksLikeADirectory =
|
308
|
+
const resolvedCacheFile = path.resolve(cwd, normalizedCacheFile);
|
309
|
+
const looksLikeADirectory = normalizedCacheFile.slice(-1) === path.sep;
|
309
310
|
|
310
311
|
/**
|
311
312
|
* return the name for the cache file in case the provided parameter is a directory
|
@@ -368,16 +369,16 @@ class CLIEngine {
|
|
368
369
|
|
369
370
|
/**
|
370
371
|
* Creates a new instance of the core CLI engine.
|
371
|
-
* @param {CLIEngineOptions}
|
372
|
+
* @param {CLIEngineOptions} providedOptions The options for this instance.
|
372
373
|
* @constructor
|
373
374
|
*/
|
374
|
-
constructor(
|
375
|
+
constructor(providedOptions) {
|
375
376
|
|
376
|
-
options = Object.assign(
|
377
|
+
const options = Object.assign(
|
377
378
|
Object.create(null),
|
378
379
|
defaultOptions,
|
379
380
|
{ cwd: process.cwd() },
|
380
|
-
|
381
|
+
providedOptions
|
381
382
|
);
|
382
383
|
|
383
384
|
/**
|
@@ -605,20 +606,21 @@ class CLIEngine {
|
|
605
606
|
ignoredPaths = new IgnoredPaths(options);
|
606
607
|
|
607
608
|
// resolve filename based on options.cwd (for reporting, ignoredPaths also resolves)
|
608
|
-
if (filename && !path.isAbsolute(filename)) {
|
609
|
-
filename = path.resolve(options.cwd, filename);
|
610
|
-
}
|
611
609
|
|
612
|
-
|
610
|
+
const resolvedFilename = filename && !path.isAbsolute(filename)
|
611
|
+
? path.resolve(options.cwd, filename)
|
612
|
+
: filename;
|
613
|
+
|
614
|
+
if (resolvedFilename && ignoredPaths.contains(resolvedFilename)) {
|
613
615
|
if (warnIgnored) {
|
614
|
-
results.push(createIgnoreResult(
|
616
|
+
results.push(createIgnoreResult(resolvedFilename, options.cwd));
|
615
617
|
}
|
616
618
|
} else {
|
617
619
|
results.push(
|
618
620
|
processText(
|
619
621
|
text,
|
620
622
|
configHelper,
|
621
|
-
|
623
|
+
resolvedFilename,
|
622
624
|
options.fix,
|
623
625
|
options.allowInlineConfig,
|
624
626
|
options.reportUnusedDisableDirectives,
|
@@ -672,31 +674,30 @@ class CLIEngine {
|
|
672
674
|
*/
|
673
675
|
getFormatter(format) {
|
674
676
|
|
675
|
-
|
676
677
|
// default is stylish
|
677
|
-
|
678
|
+
const resolvedFormatName = format || "stylish";
|
678
679
|
|
679
680
|
// only strings are valid formatters
|
680
|
-
if (typeof
|
681
|
+
if (typeof resolvedFormatName === "string") {
|
681
682
|
|
682
683
|
// replace \ with / for Windows compatibility
|
683
|
-
|
684
|
+
const normalizedFormatName = resolvedFormatName.replace(/\\/g, "/");
|
684
685
|
|
685
686
|
const cwd = this.options ? this.options.cwd : process.cwd();
|
686
|
-
const namespace = naming.getNamespaceFromTerm(
|
687
|
+
const namespace = naming.getNamespaceFromTerm(normalizedFormatName);
|
687
688
|
|
688
689
|
let formatterPath;
|
689
690
|
|
690
691
|
// if there's a slash, then it's a file
|
691
|
-
if (!namespace &&
|
692
|
-
formatterPath = path.resolve(cwd,
|
692
|
+
if (!namespace && normalizedFormatName.indexOf("/") > -1) {
|
693
|
+
formatterPath = path.resolve(cwd, normalizedFormatName);
|
693
694
|
} else {
|
694
695
|
try {
|
695
|
-
const npmFormat = naming.normalizePackageName(
|
696
|
+
const npmFormat = naming.normalizePackageName(normalizedFormatName, "eslint-formatter");
|
696
697
|
|
697
698
|
formatterPath = resolver.resolve(npmFormat, `${cwd}/node_modules`);
|
698
699
|
} catch (e) {
|
699
|
-
formatterPath = `./formatters/${
|
700
|
+
formatterPath = `./formatters/${normalizedFormatName}`;
|
700
701
|
}
|
701
702
|
}
|
702
703
|
|
@@ -164,13 +164,13 @@ function removeConnection(prevSegments, nextSegments) {
|
|
164
164
|
* Creates looping path.
|
165
165
|
*
|
166
166
|
* @param {CodePathState} state - The instance.
|
167
|
-
* @param {CodePathSegment[]}
|
168
|
-
* @param {CodePathSegment[]}
|
167
|
+
* @param {CodePathSegment[]} unflattenedFromSegments - Segments which are source.
|
168
|
+
* @param {CodePathSegment[]} unflattenedToSegments - Segments which are destination.
|
169
169
|
* @returns {void}
|
170
170
|
*/
|
171
|
-
function makeLooped(state,
|
172
|
-
fromSegments = CodePathSegment.flattenUnusedSegments(
|
173
|
-
toSegments = CodePathSegment.flattenUnusedSegments(
|
171
|
+
function makeLooped(state, unflattenedFromSegments, unflattenedToSegments) {
|
172
|
+
const fromSegments = CodePathSegment.flattenUnusedSegments(unflattenedFromSegments);
|
173
|
+
const toSegments = CodePathSegment.flattenUnusedSegments(unflattenedToSegments);
|
174
174
|
|
175
175
|
const end = Math.min(fromSegments.length, toSegments.length);
|
176
176
|
|
@@ -134,14 +134,19 @@ class CodePath {
|
|
134
134
|
* @returns {void}
|
135
135
|
*/
|
136
136
|
traverseSegments(options, callback) {
|
137
|
+
let resolvedOptions;
|
138
|
+
let resolvedCallback;
|
139
|
+
|
137
140
|
if (typeof options === "function") {
|
138
|
-
|
139
|
-
|
141
|
+
resolvedCallback = options;
|
142
|
+
resolvedOptions = {};
|
143
|
+
} else {
|
144
|
+
resolvedOptions = options || {};
|
145
|
+
resolvedCallback = callback;
|
140
146
|
}
|
141
147
|
|
142
|
-
|
143
|
-
const
|
144
|
-
const lastSegment = options.last;
|
148
|
+
const startSegment = resolvedOptions.first || this.internal.initialSegment;
|
149
|
+
const lastSegment = resolvedOptions.last;
|
145
150
|
|
146
151
|
let item = null;
|
147
152
|
let index = 0;
|
@@ -206,7 +211,7 @@ class CodePath {
|
|
206
211
|
|
207
212
|
// Call the callback when the first time.
|
208
213
|
if (!skippedSegment) {
|
209
|
-
|
214
|
+
resolvedCallback.call(this, segment, controller);
|
210
215
|
if (segment === lastSegment) {
|
211
216
|
controller.skip();
|
212
217
|
}
|
@@ -46,19 +46,15 @@ function isReachable(segment) {
|
|
46
46
|
function makeSegments(context, begin, end, create) {
|
47
47
|
const list = context.segmentsList;
|
48
48
|
|
49
|
-
|
50
|
-
|
51
|
-
}
|
52
|
-
if (end < 0) {
|
53
|
-
end = list.length + end;
|
54
|
-
}
|
49
|
+
const normalizedBegin = begin >= 0 ? begin : list.length + begin;
|
50
|
+
const normalizedEnd = end >= 0 ? end : list.length + end;
|
55
51
|
|
56
52
|
const segments = [];
|
57
53
|
|
58
54
|
for (let i = 0; i < context.count; ++i) {
|
59
55
|
const allPrevSegments = [];
|
60
56
|
|
61
|
-
for (let j =
|
57
|
+
for (let j = normalizedBegin; j <= normalizedEnd; ++j) {
|
62
58
|
allPrevSegments.push(list[j][i]);
|
63
59
|
}
|
64
60
|
|
@@ -79,18 +75,20 @@ function makeSegments(context, begin, end, create) {
|
|
79
75
|
* @returns {CodePathSegment[]} The merged segments.
|
80
76
|
*/
|
81
77
|
function mergeExtraSegments(context, segments) {
|
82
|
-
|
78
|
+
let currentSegments = segments;
|
79
|
+
|
80
|
+
while (currentSegments.length > context.count) {
|
83
81
|
const merged = [];
|
84
82
|
|
85
|
-
for (let i = 0, length =
|
83
|
+
for (let i = 0, length = currentSegments.length / 2 | 0; i < length; ++i) {
|
86
84
|
merged.push(CodePathSegment.newNext(
|
87
85
|
context.idGenerator.next(),
|
88
|
-
[
|
86
|
+
[currentSegments[i], currentSegments[i + length]]
|
89
87
|
));
|
90
88
|
}
|
91
|
-
|
89
|
+
currentSegments = merged;
|
92
90
|
}
|
93
|
-
return
|
91
|
+
return currentSegments;
|
94
92
|
}
|
95
93
|
|
96
94
|
//------------------------------------------------------------------------------
|
@@ -400,25 +400,29 @@ function applyExtends(config, configContext, filePath, relativeTo) {
|
|
400
400
|
}
|
401
401
|
|
402
402
|
// Make the last element in an array take the highest precedence
|
403
|
-
|
403
|
+
return configExtends.reduceRight((previousValue, parentPath) => {
|
404
404
|
try {
|
405
|
+
let extensionPath;
|
406
|
+
|
405
407
|
if (parentPath.startsWith("eslint:")) {
|
406
|
-
|
408
|
+
extensionPath = getEslintCoreConfigPath(parentPath);
|
407
409
|
} else if (isFilePath(parentPath)) {
|
408
410
|
|
409
411
|
/*
|
410
412
|
* If the `extends` path is relative, use the directory of the current configuration
|
411
413
|
* file as the reference point. Otherwise, use as-is.
|
412
414
|
*/
|
413
|
-
|
415
|
+
extensionPath = (path.isAbsolute(parentPath)
|
414
416
|
? parentPath
|
415
417
|
: path.join(relativeTo || path.dirname(filePath), parentPath)
|
416
418
|
);
|
419
|
+
} else {
|
420
|
+
extensionPath = parentPath;
|
417
421
|
}
|
418
|
-
debug(`Loading ${
|
422
|
+
debug(`Loading ${extensionPath}`);
|
419
423
|
|
420
424
|
// eslint-disable-next-line no-use-before-define
|
421
|
-
return ConfigOps.merge(load(
|
425
|
+
return ConfigOps.merge(load(extensionPath, configContext, relativeTo), previousValue);
|
422
426
|
} catch (e) {
|
423
427
|
|
424
428
|
/*
|
@@ -432,8 +436,6 @@ function applyExtends(config, configContext, filePath, relativeTo) {
|
|
432
436
|
}
|
433
437
|
|
434
438
|
}, config);
|
435
|
-
|
436
|
-
return config;
|
437
439
|
}
|
438
440
|
|
439
441
|
/**
|
@@ -463,13 +465,20 @@ function resolve(filePath, relativeTo) {
|
|
463
465
|
|
464
466
|
normalizedPackageName = naming.normalizePackageName(pluginName, "eslint-plugin");
|
465
467
|
debug(`Attempting to resolve ${normalizedPackageName}`);
|
466
|
-
|
467
|
-
return {
|
468
|
+
|
469
|
+
return {
|
470
|
+
filePath: resolver.resolve(normalizedPackageName, getLookupPath(relativeTo)),
|
471
|
+
configName,
|
472
|
+
configFullName
|
473
|
+
};
|
468
474
|
}
|
469
475
|
normalizedPackageName = naming.normalizePackageName(filePath, "eslint-config");
|
470
476
|
debug(`Attempting to resolve ${normalizedPackageName}`);
|
471
|
-
|
472
|
-
return {
|
477
|
+
|
478
|
+
return {
|
479
|
+
filePath: resolver.resolve(normalizedPackageName, getLookupPath(relativeTo)),
|
480
|
+
configFullName: filePath
|
481
|
+
};
|
473
482
|
|
474
483
|
|
475
484
|
}
|
package/lib/config/config-ops.js
CHANGED
@@ -136,29 +136,27 @@ module.exports = {
|
|
136
136
|
const array = Array.isArray(src) || Array.isArray(target);
|
137
137
|
let dst = array && [] || {};
|
138
138
|
|
139
|
-
combine = !!combine;
|
140
|
-
isRule = !!isRule;
|
141
139
|
if (array) {
|
142
|
-
|
140
|
+
const resolvedTarget = target || [];
|
143
141
|
|
144
142
|
// src could be a string, so check for array
|
145
143
|
if (isRule && Array.isArray(src) && src.length > 1) {
|
146
144
|
dst = dst.concat(src);
|
147
145
|
} else {
|
148
|
-
dst = dst.concat(
|
146
|
+
dst = dst.concat(resolvedTarget);
|
149
147
|
}
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
148
|
+
const resolvedSrc = typeof src === "object" ? src : [src];
|
149
|
+
|
150
|
+
Object.keys(resolvedSrc).forEach((_, i) => {
|
151
|
+
const e = resolvedSrc[i];
|
152
|
+
|
155
153
|
if (typeof dst[i] === "undefined") {
|
156
154
|
dst[i] = e;
|
157
155
|
} else if (typeof e === "object") {
|
158
156
|
if (isRule) {
|
159
157
|
dst[i] = e;
|
160
158
|
} else {
|
161
|
-
dst[i] = deepmerge(
|
159
|
+
dst[i] = deepmerge(resolvedTarget[i], e, combine, isRule);
|
162
160
|
}
|
163
161
|
} else {
|
164
162
|
if (!combine) {
|
@@ -197,11 +197,10 @@ class RuleConfigSet {
|
|
197
197
|
* Add a severity level to the front of all configs in the instance.
|
198
198
|
* This should only be called after all configs have been added to the instance.
|
199
199
|
*
|
200
|
-
* @param {number} [severity=2] The level of severity for the rule (0, 1, 2)
|
201
200
|
* @returns {void}
|
202
201
|
*/
|
203
|
-
addErrorSeverity(
|
204
|
-
severity =
|
202
|
+
addErrorSeverity() {
|
203
|
+
const severity = 2;
|
205
204
|
|
206
205
|
this.ruleConfigs = this.ruleConfigs.map(config => {
|
207
206
|
config.unshift(severity);
|
package/lib/config/plugins.js
CHANGED
@@ -120,6 +120,26 @@ class Plugins {
|
|
120
120
|
throw pluginLoadErr;
|
121
121
|
}
|
122
122
|
|
123
|
+
// This step is costly, so skip if debug is disabled
|
124
|
+
if (debug.enabled) {
|
125
|
+
const resolvedPath = require.resolve(longName);
|
126
|
+
|
127
|
+
let version = null;
|
128
|
+
|
129
|
+
try {
|
130
|
+
version = require(`${longName}/package.json`).version;
|
131
|
+
} catch (e) {
|
132
|
+
|
133
|
+
// Do nothing
|
134
|
+
}
|
135
|
+
|
136
|
+
const loadedPluginAndVersion = version
|
137
|
+
? `${longName}@${version}`
|
138
|
+
: `${longName}, version unknown`;
|
139
|
+
|
140
|
+
debug(`Loaded plugin ${pluginName} (${loadedPluginAndVersion}) (from ${resolvedPath})`);
|
141
|
+
}
|
142
|
+
|
123
143
|
this.define(pluginName, plugin);
|
124
144
|
}
|
125
145
|
}
|
package/lib/config.js
CHANGED
@@ -51,11 +51,11 @@ function hasRules(options) {
|
|
51
51
|
class Config {
|
52
52
|
|
53
53
|
/**
|
54
|
-
* @param {Object}
|
54
|
+
* @param {Object} providedOptions Options to be passed in
|
55
55
|
* @param {Linter} linterContext Linter instance object
|
56
56
|
*/
|
57
|
-
constructor(
|
58
|
-
options =
|
57
|
+
constructor(providedOptions, linterContext) {
|
58
|
+
const options = providedOptions || {};
|
59
59
|
|
60
60
|
this.linterContext = linterContext;
|
61
61
|
this.plugins = new Plugins(linterContext.environments, linterContext.rules);
|
@@ -132,11 +132,10 @@ class Config {
|
|
132
132
|
isResolvable(`eslint-config-${config}`) ||
|
133
133
|
config.charAt(0) === "@";
|
134
134
|
|
135
|
-
|
136
|
-
config
|
137
|
-
|
138
|
-
|
139
|
-
this.specificConfig = ConfigFile.load(config, this);
|
135
|
+
this.specificConfig = ConfigFile.load(
|
136
|
+
isNamedConfig ? config : path.resolve(this.options.cwd, config),
|
137
|
+
this
|
138
|
+
);
|
140
139
|
}
|
141
140
|
}
|
142
141
|
|