eslint 4.5.0 → 4.7.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 +98 -0
- package/bin/eslint.js +2 -1
- package/conf/eslint-recommended.js +1 -0
- package/lib/ast-utils.js +20 -17
- package/lib/cli-engine.js +51 -124
- package/lib/code-path-analysis/code-path-analyzer.js +8 -4
- package/lib/code-path-analysis/code-path-segment.js +2 -1
- package/lib/code-path-analysis/code-path-state.js +21 -14
- package/lib/code-path-analysis/code-path.js +3 -2
- package/lib/code-path-analysis/fork-context.js +2 -1
- package/lib/config/autoconfig.js +2 -4
- package/lib/config/config-initializer.js +9 -5
- package/lib/config/config-ops.js +15 -15
- package/lib/config.js +8 -12
- package/lib/formatters/codeframe.js +1 -1
- package/lib/formatters/stylish.js +1 -1
- package/lib/ignored-paths.js +0 -2
- package/lib/linter.js +468 -638
- package/lib/report-translator.js +274 -0
- package/lib/rules/function-paren-newline.js +221 -0
- package/lib/rules/generator-star-spacing.js +70 -19
- package/lib/rules/indent-legacy.js +3 -2
- package/lib/rules/indent.js +15 -6
- package/lib/rules/key-spacing.js +2 -1
- package/lib/rules/newline-per-chained-call.js +20 -3
- package/lib/rules/no-extra-parens.js +75 -33
- package/lib/rules/no-invalid-this.js +2 -1
- package/lib/rules/no-tabs.js +1 -1
- package/lib/rules/no-undef-init.js +4 -0
- package/lib/rules/no-unmodified-loop-condition.js +1 -1
- package/lib/rules/no-unused-vars.js +47 -4
- package/lib/rules/padded-blocks.js +2 -2
- package/lib/rules/prefer-arrow-callback.js +1 -2
- package/lib/rules/quote-props.js +4 -2
- package/lib/rules/quotes.js +1 -2
- package/lib/rules/space-before-blocks.js +1 -1
- package/lib/rules/valid-jsdoc.js +2 -2
- package/lib/rules.js +48 -3
- package/lib/testers/rule-tester.js +27 -51
- package/lib/timing.js +2 -2
- package/lib/util/apply-disable-directives.js +131 -0
- package/lib/util/fix-tracker.js +1 -2
- package/lib/util/npm-util.js +21 -4
- package/lib/util/source-code-fixer.js +5 -14
- package/lib/util/source-code.js +3 -5
- package/package.json +8 -8
- package/lib/rule-context.js +0 -241
- package/lib/testers/event-generator-tester.js +0 -62
- package/lib/testers/test-parser.js +0 -48
package/lib/rules/indent.js
CHANGED
@@ -802,10 +802,19 @@ module.exports = {
|
|
802
802
|
return;
|
803
803
|
}
|
804
804
|
elements.forEach((element, index) => {
|
805
|
+
if (!element) {
|
806
|
+
|
807
|
+
// Skip holes in arrays
|
808
|
+
return;
|
809
|
+
}
|
805
810
|
if (offset === "off") {
|
811
|
+
|
812
|
+
// Ignore the first token of every element if the "off" option is used
|
806
813
|
offsets.ignoreToken(getFirstToken(element));
|
807
814
|
}
|
808
|
-
|
815
|
+
|
816
|
+
// Offset the following elements correctly relative to the first element
|
817
|
+
if (index === 0) {
|
809
818
|
return;
|
810
819
|
}
|
811
820
|
if (offset === "first" && tokenInfo.isFirstTokenOfLine(getFirstToken(element))) {
|
@@ -941,12 +950,12 @@ module.exports = {
|
|
941
950
|
}
|
942
951
|
|
943
952
|
/**
|
944
|
-
* Check whether the given token is the first
|
953
|
+
* Check whether the given token is on the first line of a statement.
|
945
954
|
* @param {Token} token The token to check.
|
946
955
|
* @param {ASTNode} leafNode The expression node that the token belongs directly.
|
947
|
-
* @returns {boolean} `true` if the token is the first
|
956
|
+
* @returns {boolean} `true` if the token is on the first line of a statement.
|
948
957
|
*/
|
949
|
-
function
|
958
|
+
function isOnFirstLineOfStatement(token, leafNode) {
|
950
959
|
let node = leafNode;
|
951
960
|
|
952
961
|
while (node.parent && !node.parent.type.endsWith("Statement") && !node.parent.type.endsWith("Declaration")) {
|
@@ -954,7 +963,7 @@ module.exports = {
|
|
954
963
|
}
|
955
964
|
node = node.parent;
|
956
965
|
|
957
|
-
return !node || node.
|
966
|
+
return !node || node.loc.start.line === token.loc.start.line;
|
958
967
|
}
|
959
968
|
|
960
969
|
const baseOffsetListeners = {
|
@@ -1067,7 +1076,7 @@ module.exports = {
|
|
1067
1076
|
// /*else*/ qiz ;
|
1068
1077
|
if (!options.flatTernaryExpressions ||
|
1069
1078
|
!astUtils.isTokenOnSameLine(node.test, node.consequent) ||
|
1070
|
-
|
1079
|
+
isOnFirstLineOfStatement(firstToken, node)
|
1071
1080
|
) {
|
1072
1081
|
const questionMarkToken = sourceCode.getFirstTokenBetween(node.test, node.consequent, token => token.type === "Punctuator" && token.value === "?");
|
1073
1082
|
const colonToken = sourceCode.getFirstTokenBetween(node.consequent, node.alternate, token => token.type === "Punctuator" && token.value === ":");
|
package/lib/rules/key-spacing.js
CHANGED
@@ -420,7 +420,6 @@ module.exports = {
|
|
420
420
|
isExtra = diff > 0,
|
421
421
|
diffAbs = Math.abs(diff),
|
422
422
|
spaces = Array(diffAbs + 1).join(" ");
|
423
|
-
let fix;
|
424
423
|
|
425
424
|
if ((
|
426
425
|
diff && mode === "strict" ||
|
@@ -428,6 +427,8 @@ module.exports = {
|
|
428
427
|
diff > 0 && !expected && mode === "minimum") &&
|
429
428
|
!(expected && containsLineTerminator(whitespace))
|
430
429
|
) {
|
430
|
+
let fix;
|
431
|
+
|
431
432
|
if (isExtra) {
|
432
433
|
let range;
|
433
434
|
|
@@ -19,7 +19,7 @@ module.exports = {
|
|
19
19
|
category: "Stylistic Issues",
|
20
20
|
recommended: false
|
21
21
|
},
|
22
|
-
|
22
|
+
fixable: "whitespace",
|
23
23
|
schema: [{
|
24
24
|
type: "object",
|
25
25
|
properties: {
|
@@ -40,6 +40,18 @@ module.exports = {
|
|
40
40
|
|
41
41
|
const sourceCode = context.getSourceCode();
|
42
42
|
|
43
|
+
/**
|
44
|
+
* Get the prefix of a given MemberExpression node.
|
45
|
+
* If the MemberExpression node is a computed value it returns a
|
46
|
+
* left bracket. If not it returns a period.
|
47
|
+
*
|
48
|
+
* @param {ASTNode} node - A MemberExpression node to get
|
49
|
+
* @returns {string} The prefix of the node.
|
50
|
+
*/
|
51
|
+
function getPrefix(node) {
|
52
|
+
return node.computed ? "[" : ".";
|
53
|
+
}
|
54
|
+
|
43
55
|
/**
|
44
56
|
* Gets the property text of a given MemberExpression node.
|
45
57
|
* If the text is multiline, this returns only the first line.
|
@@ -48,7 +60,7 @@ module.exports = {
|
|
48
60
|
* @returns {string} The property text of the node.
|
49
61
|
*/
|
50
62
|
function getPropertyText(node) {
|
51
|
-
const prefix = node
|
63
|
+
const prefix = getPrefix(node);
|
52
64
|
const lines = sourceCode.getText(node.property).split(astUtils.LINEBREAK_MATCHER);
|
53
65
|
const suffix = node.computed && lines.length === 1 ? "]" : "";
|
54
66
|
|
@@ -70,13 +82,18 @@ module.exports = {
|
|
70
82
|
parent = parent.callee.object;
|
71
83
|
}
|
72
84
|
|
73
|
-
if (depth > ignoreChainWithDepth && callee.
|
85
|
+
if (depth > ignoreChainWithDepth && astUtils.isTokenOnSameLine(callee.object, callee.property)) {
|
74
86
|
context.report({
|
75
87
|
node: callee.property,
|
76
88
|
loc: callee.property.loc.start,
|
77
89
|
message: "Expected line break before `{{callee}}`.",
|
78
90
|
data: {
|
79
91
|
callee: getPropertyText(callee)
|
92
|
+
},
|
93
|
+
fix(fixer) {
|
94
|
+
const firstTokenAfterObject = sourceCode.getTokenAfter(callee.object, astUtils.isNotClosingParenToken);
|
95
|
+
|
96
|
+
return fixer.insertTextBefore(firstTokenAfterObject, "\n");
|
80
97
|
}
|
81
98
|
});
|
82
99
|
}
|
@@ -276,6 +276,15 @@ module.exports = {
|
|
276
276
|
!astUtils.canTokensBeAdjacent(tokenBeforeRightParen, tokenAfterRightParen);
|
277
277
|
}
|
278
278
|
|
279
|
+
/**
|
280
|
+
* Determines if a given expression node is an IIFE
|
281
|
+
* @param {ASTNode} node The node to check
|
282
|
+
* @returns {boolean} `true` if the given node is an IIFE
|
283
|
+
*/
|
284
|
+
function isIIFE(node) {
|
285
|
+
return node.type === "CallExpression" && node.callee.type === "FunctionExpression";
|
286
|
+
}
|
287
|
+
|
279
288
|
/**
|
280
289
|
* Report the node
|
281
290
|
* @param {ASTNode} node node to evaluate
|
@@ -286,8 +295,14 @@ module.exports = {
|
|
286
295
|
const leftParenToken = sourceCode.getTokenBefore(node);
|
287
296
|
const rightParenToken = sourceCode.getTokenAfter(node);
|
288
297
|
|
289
|
-
if (
|
290
|
-
|
298
|
+
if (!isParenthesisedTwice(node)) {
|
299
|
+
if (tokensToIgnore.has(sourceCode.getFirstToken(node))) {
|
300
|
+
return;
|
301
|
+
}
|
302
|
+
|
303
|
+
if (isIIFE(node) && !isParenthesised(node.callee)) {
|
304
|
+
return;
|
305
|
+
}
|
291
306
|
}
|
292
307
|
|
293
308
|
context.report({
|
@@ -321,6 +336,23 @@ module.exports = {
|
|
321
336
|
}
|
322
337
|
}
|
323
338
|
|
339
|
+
/**
|
340
|
+
* Check if a member expression contains a call expression
|
341
|
+
* @param {ASTNode} node MemberExpression node to evaluate
|
342
|
+
* @returns {boolean} true if found, false if not
|
343
|
+
*/
|
344
|
+
function doesMemberExpressionContainCallExpression(node) {
|
345
|
+
let currentNode = node.object;
|
346
|
+
let currentNodeType = node.object.type;
|
347
|
+
|
348
|
+
while (currentNodeType === "MemberExpression") {
|
349
|
+
currentNode = currentNode.object;
|
350
|
+
currentNodeType = currentNode.type;
|
351
|
+
}
|
352
|
+
|
353
|
+
return currentNodeType === "CallExpression";
|
354
|
+
}
|
355
|
+
|
324
356
|
/**
|
325
357
|
* Evaluate a new call
|
326
358
|
* @param {ASTNode} node node to evaluate
|
@@ -328,26 +360,32 @@ module.exports = {
|
|
328
360
|
* @private
|
329
361
|
*/
|
330
362
|
function checkCallNew(node) {
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
363
|
+
const callee = node.callee;
|
364
|
+
|
365
|
+
if (hasExcessParens(callee) && precedence(callee) >= precedence(node)) {
|
366
|
+
const hasNewParensException = callee.type === "NewExpression" && !isNewExpressionWithParens(callee);
|
367
|
+
|
368
|
+
if (
|
369
|
+
hasDoubleExcessParens(callee) ||
|
370
|
+
!isIIFE(node) && !hasNewParensException && !(
|
371
|
+
|
372
|
+
// Allow extra parens around a new expression if
|
373
|
+
// there are intervening parentheses.
|
374
|
+
callee.type === "MemberExpression" &&
|
375
|
+
doesMemberExpressionContainCallExpression(callee)
|
376
|
+
)
|
377
|
+
) {
|
378
|
+
report(node.callee);
|
379
|
+
}
|
340
380
|
}
|
341
381
|
if (node.arguments.length === 1) {
|
342
382
|
if (hasDoubleExcessParens(node.arguments[0]) && precedence(node.arguments[0]) >= PRECEDENCE_OF_ASSIGNMENT_EXPR) {
|
343
383
|
report(node.arguments[0]);
|
344
384
|
}
|
345
385
|
} else {
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
}
|
350
|
-
});
|
386
|
+
node.arguments
|
387
|
+
.filter(arg => hasExcessParens(arg) && precedence(arg) >= PRECEDENCE_OF_ASSIGNMENT_EXPR)
|
388
|
+
.forEach(report);
|
351
389
|
}
|
352
390
|
}
|
353
391
|
|
@@ -442,11 +480,9 @@ module.exports = {
|
|
442
480
|
|
443
481
|
return {
|
444
482
|
ArrayExpression(node) {
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
}
|
449
|
-
});
|
483
|
+
node.elements
|
484
|
+
.filter(e => e && hasExcessParens(e) && precedence(e) >= PRECEDENCE_OF_ASSIGNMENT_EXPR)
|
485
|
+
.forEach(report);
|
450
486
|
},
|
451
487
|
|
452
488
|
ArrowFunctionExpression(node) {
|
@@ -566,8 +602,10 @@ module.exports = {
|
|
566
602
|
LogicalExpression: checkBinaryLogical,
|
567
603
|
|
568
604
|
MemberExpression(node) {
|
605
|
+
const nodeObjHasExcessParens = hasExcessParens(node.object);
|
606
|
+
|
569
607
|
if (
|
570
|
-
|
608
|
+
nodeObjHasExcessParens &&
|
571
609
|
precedence(node.object) >= precedence(node) &&
|
572
610
|
(
|
573
611
|
node.computed ||
|
@@ -581,6 +619,13 @@ module.exports = {
|
|
581
619
|
) {
|
582
620
|
report(node.object);
|
583
621
|
}
|
622
|
+
|
623
|
+
if (nodeObjHasExcessParens &&
|
624
|
+
node.object.type === "CallExpression" &&
|
625
|
+
node.parent.type !== "NewExpression") {
|
626
|
+
report(node.object);
|
627
|
+
}
|
628
|
+
|
584
629
|
if (node.computed && hasExcessParens(node.property)) {
|
585
630
|
report(node.property);
|
586
631
|
}
|
@@ -589,13 +634,12 @@ module.exports = {
|
|
589
634
|
NewExpression: checkCallNew,
|
590
635
|
|
591
636
|
ObjectExpression(node) {
|
592
|
-
|
593
|
-
|
637
|
+
node.properties
|
638
|
+
.filter(property => {
|
639
|
+
const value = property.value;
|
594
640
|
|
595
|
-
|
596
|
-
|
597
|
-
}
|
598
|
-
});
|
641
|
+
return value && hasExcessParens(value) && precedence(value) >= PRECEDENCE_OF_ASSIGNMENT_EXPR;
|
642
|
+
}).forEach(property => report(property.value));
|
599
643
|
},
|
600
644
|
|
601
645
|
ReturnStatement(node) {
|
@@ -615,11 +659,9 @@ module.exports = {
|
|
615
659
|
},
|
616
660
|
|
617
661
|
SequenceExpression(node) {
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
}
|
622
|
-
});
|
662
|
+
node.expressions
|
663
|
+
.filter(e => hasExcessParens(e) && precedence(e) >= precedence(node))
|
664
|
+
.forEach(report);
|
623
665
|
},
|
624
666
|
|
625
667
|
SwitchCase(node) {
|
package/lib/rules/no-tabs.js
CHANGED
@@ -43,6 +43,10 @@ module.exports = {
|
|
43
43
|
message: "It's not necessary to initialize '{{name}}' to undefined.",
|
44
44
|
data: { name },
|
45
45
|
fix(fixer) {
|
46
|
+
if (node.parent.kind === "var") {
|
47
|
+
return null;
|
48
|
+
}
|
49
|
+
|
46
50
|
if (node.id.type === "ArrayPattern" || node.id.type === "ObjectPattern") {
|
47
51
|
|
48
52
|
// Don't fix destructuring assignment to `undefined`.
|
@@ -213,13 +213,13 @@ function getEncloseFunctionDeclaration(reference) {
|
|
213
213
|
* @returns {void}
|
214
214
|
*/
|
215
215
|
function updateModifiedFlag(conditions, modifiers) {
|
216
|
-
let funcNode, funcVar;
|
217
216
|
|
218
217
|
for (let i = 0; i < conditions.length; ++i) {
|
219
218
|
const condition = conditions[i];
|
220
219
|
|
221
220
|
for (let j = 0; !condition.modified && j < modifiers.length; ++j) {
|
222
221
|
const modifier = modifiers[j];
|
222
|
+
let funcNode, funcVar;
|
223
223
|
|
224
224
|
/*
|
225
225
|
* Besides checking for the condition being in the loop, we want to
|
@@ -64,8 +64,6 @@ module.exports = {
|
|
64
64
|
create(context) {
|
65
65
|
const sourceCode = context.getSourceCode();
|
66
66
|
|
67
|
-
const DEFINED_MESSAGE = "'{{name}}' is defined but never used.";
|
68
|
-
const ASSIGNED_MESSAGE = "'{{name}}' is assigned a value but never used.";
|
69
67
|
const REST_PROPERTY_TYPE = /^(?:Experimental)?RestProperty$/;
|
70
68
|
|
71
69
|
const config = {
|
@@ -100,6 +98,49 @@ module.exports = {
|
|
100
98
|
}
|
101
99
|
}
|
102
100
|
|
101
|
+
/**
|
102
|
+
* Generate the warning message about the variable being
|
103
|
+
* defined and unused, including the ignore pattern if configured.
|
104
|
+
* @param {Variable} unusedVar - eslint-scope variable object.
|
105
|
+
* @returns {string} The warning message to be used with this unused variable.
|
106
|
+
*/
|
107
|
+
function getDefinedMessage(unusedVar) {
|
108
|
+
let type;
|
109
|
+
let pattern;
|
110
|
+
|
111
|
+
if (config.varsIgnorePattern) {
|
112
|
+
type = "vars";
|
113
|
+
pattern = config.varsIgnorePattern.toString();
|
114
|
+
}
|
115
|
+
|
116
|
+
if (unusedVar.defs && unusedVar.defs[0] && unusedVar.defs[0].type) {
|
117
|
+
const defType = unusedVar.defs[0].type;
|
118
|
+
|
119
|
+
if (defType === "CatchClause" && config.caughtErrorsIgnorePattern) {
|
120
|
+
type = "args";
|
121
|
+
pattern = config.caughtErrorsIgnorePattern.toString();
|
122
|
+
} else if (defType === "Parameter" && config.argsIgnorePattern) {
|
123
|
+
type = "args";
|
124
|
+
pattern = config.argsIgnorePattern.toString();
|
125
|
+
}
|
126
|
+
}
|
127
|
+
|
128
|
+
const additional = type ? ` Allowed unused ${type} must match ${pattern}.` : "";
|
129
|
+
|
130
|
+
return `'{{name}}' is defined but never used.${additional}`;
|
131
|
+
}
|
132
|
+
|
133
|
+
/**
|
134
|
+
* Generate the warning message about the variable being
|
135
|
+
* assigned and unused, including the ignore pattern if configured.
|
136
|
+
* @returns {string} The warning message to be used with this unused variable.
|
137
|
+
*/
|
138
|
+
function getAssignedMessage() {
|
139
|
+
const additional = config.varsIgnorePattern ? ` Allowed unused vars must match ${config.varsIgnorePattern.toString()}.` : "";
|
140
|
+
|
141
|
+
return `'{{name}}' is assigned a value but never used.${additional}`;
|
142
|
+
}
|
143
|
+
|
103
144
|
//--------------------------------------------------------------------------
|
104
145
|
// Helpers
|
105
146
|
//--------------------------------------------------------------------------
|
@@ -586,13 +627,15 @@ module.exports = {
|
|
586
627
|
context.report({
|
587
628
|
node: programNode,
|
588
629
|
loc: getLocation(unusedVar),
|
589
|
-
message:
|
630
|
+
message: getDefinedMessage(unusedVar),
|
590
631
|
data: unusedVar
|
591
632
|
});
|
592
633
|
} else if (unusedVar.defs.length > 0) {
|
593
634
|
context.report({
|
594
635
|
node: unusedVar.identifiers[0],
|
595
|
-
message: unusedVar.references.some(ref => ref.isWrite())
|
636
|
+
message: unusedVar.references.some(ref => ref.isWrite())
|
637
|
+
? getAssignedMessage()
|
638
|
+
: getDefinedMessage(unusedVar),
|
596
639
|
data: unusedVar
|
597
640
|
});
|
598
641
|
}
|
@@ -111,7 +111,7 @@ module.exports = {
|
|
111
111
|
* @returns {boolean} Whether or not the token is followed by a blank line.
|
112
112
|
*/
|
113
113
|
function getFirstBlockToken(token) {
|
114
|
-
let prev
|
114
|
+
let prev,
|
115
115
|
first = token;
|
116
116
|
|
117
117
|
do {
|
@@ -129,7 +129,7 @@ module.exports = {
|
|
129
129
|
*/
|
130
130
|
function getLastBlockToken(token) {
|
131
131
|
let last = token,
|
132
|
-
next
|
132
|
+
next;
|
133
133
|
|
134
134
|
do {
|
135
135
|
next = last;
|
@@ -88,7 +88,6 @@ function getCallbackInfo(node) {
|
|
88
88
|
parent.parent.arguments.length === 1 &&
|
89
89
|
parent.parent.arguments[0].type === "ThisExpression"
|
90
90
|
);
|
91
|
-
node = parent;
|
92
91
|
parent = parent.parent;
|
93
92
|
} else {
|
94
93
|
return retv;
|
@@ -133,7 +132,7 @@ function hasDuplicateParams(paramsList) {
|
|
133
132
|
module.exports = {
|
134
133
|
meta: {
|
135
134
|
docs: {
|
136
|
-
description: "require arrow functions
|
135
|
+
description: "require using arrow functions for callbacks",
|
137
136
|
category: "ECMAScript 6",
|
138
137
|
recommended: false
|
139
138
|
},
|
package/lib/rules/quote-props.js
CHANGED
@@ -135,13 +135,14 @@ module.exports = {
|
|
135
135
|
*/
|
136
136
|
function checkUnnecessaryQuotes(node) {
|
137
137
|
const key = node.key;
|
138
|
-
let tokens;
|
139
138
|
|
140
139
|
if (node.method || node.computed || node.shorthand) {
|
141
140
|
return;
|
142
141
|
}
|
143
142
|
|
144
143
|
if (key.type === "Literal" && typeof key.value === "string") {
|
144
|
+
let tokens;
|
145
|
+
|
145
146
|
try {
|
146
147
|
tokens = espree.tokenize(key.value);
|
147
148
|
} catch (e) {
|
@@ -215,7 +216,6 @@ module.exports = {
|
|
215
216
|
|
216
217
|
node.properties.forEach(property => {
|
217
218
|
const key = property.key;
|
218
|
-
let tokens;
|
219
219
|
|
220
220
|
if (!key || property.method || property.computed || property.shorthand) {
|
221
221
|
return;
|
@@ -226,6 +226,8 @@ module.exports = {
|
|
226
226
|
quotedProps.push(property);
|
227
227
|
|
228
228
|
if (checkQuotesRedundancy) {
|
229
|
+
let tokens;
|
230
|
+
|
229
231
|
try {
|
230
232
|
tokens = espree.tokenize(key.value);
|
231
233
|
} catch (e) {
|
package/lib/rules/quotes.js
CHANGED
@@ -229,10 +229,9 @@ module.exports = {
|
|
229
229
|
Literal(node) {
|
230
230
|
const val = node.value,
|
231
231
|
rawVal = node.raw;
|
232
|
-
let isValid;
|
233
232
|
|
234
233
|
if (settings && typeof val === "string") {
|
235
|
-
isValid = (quoteOption === "backtick" && isAllowedAsNonBacktick(node)) ||
|
234
|
+
let isValid = (quoteOption === "backtick" && isAllowedAsNonBacktick(node)) ||
|
236
235
|
isJSXLiteral(node) ||
|
237
236
|
astUtils.isSurroundedBy(rawVal, settings.quote);
|
238
237
|
|
@@ -82,11 +82,11 @@ module.exports = {
|
|
82
82
|
*/
|
83
83
|
function checkPrecedingSpace(node) {
|
84
84
|
const precedingToken = sourceCode.getTokenBefore(node);
|
85
|
-
let requireSpace;
|
86
85
|
|
87
86
|
if (precedingToken && !isConflicted(precedingToken) && astUtils.isTokenOnSameLine(precedingToken, node)) {
|
88
87
|
const hasSpace = sourceCode.isSpaceBetweenTokens(precedingToken, node);
|
89
88
|
const parent = context.getAncestors().pop();
|
89
|
+
let requireSpace;
|
90
90
|
|
91
91
|
if (parent.type === "FunctionExpression" || parent.type === "FunctionDeclaration") {
|
92
92
|
requireSpace = checkFunctions;
|
package/lib/rules/valid-jsdoc.js
CHANGED
@@ -231,11 +231,11 @@ module.exports = {
|
|
231
231
|
hasConstructor = false,
|
232
232
|
isInterface = false,
|
233
233
|
isOverride = false,
|
234
|
-
isAbstract = false
|
235
|
-
jsdoc;
|
234
|
+
isAbstract = false;
|
236
235
|
|
237
236
|
// make sure only to validate JSDoc comments
|
238
237
|
if (jsdocNode) {
|
238
|
+
let jsdoc;
|
239
239
|
|
240
240
|
try {
|
241
241
|
jsdoc = doctrine.parse(jsdocNode.value, {
|
package/lib/rules.js
CHANGED
@@ -9,7 +9,48 @@
|
|
9
9
|
// Requirements
|
10
10
|
//------------------------------------------------------------------------------
|
11
11
|
|
12
|
+
const lodash = require("lodash");
|
12
13
|
const loadRules = require("./load-rules");
|
14
|
+
const ruleReplacements = require("../conf/replacements").rules;
|
15
|
+
|
16
|
+
//------------------------------------------------------------------------------
|
17
|
+
// Helpers
|
18
|
+
//------------------------------------------------------------------------------
|
19
|
+
|
20
|
+
/**
|
21
|
+
* Creates a stub rule that gets used when a rule with a given ID is not found.
|
22
|
+
* @param {string} ruleId The ID of the missing rule
|
23
|
+
* @returns {{create: function(RuleContext): Object}} A rule that reports an error at the first location
|
24
|
+
* in the program. The report has the message `Definition for rule '${ruleId}' was not found` if the rule is unknown,
|
25
|
+
* or `Rule '${ruleId}' was removed and replaced by: ${replacements.join(", ")}` if the rule is known to have been
|
26
|
+
* replaced.
|
27
|
+
*/
|
28
|
+
const createMissingRule = lodash.memoize(ruleId => {
|
29
|
+
const message = Object.prototype.hasOwnProperty.call(ruleReplacements, ruleId)
|
30
|
+
? `Rule '${ruleId}' was removed and replaced by: ${ruleReplacements[ruleId].join(", ")}`
|
31
|
+
: `Definition for rule '${ruleId}' was not found`;
|
32
|
+
|
33
|
+
return {
|
34
|
+
create: context => ({
|
35
|
+
Program() {
|
36
|
+
context.report({
|
37
|
+
loc: { line: 1, column: 0 },
|
38
|
+
message
|
39
|
+
});
|
40
|
+
}
|
41
|
+
})
|
42
|
+
};
|
43
|
+
});
|
44
|
+
|
45
|
+
/**
|
46
|
+
* Normalizes a rule module to the new-style API
|
47
|
+
* @param {(Function|{create: Function})} rule A rule object, which can either be a function
|
48
|
+
* ("old-style") or an object with a `create` method ("new-style")
|
49
|
+
* @returns {{create: Function}} A new-style rule.
|
50
|
+
*/
|
51
|
+
function normalizeRule(rule) {
|
52
|
+
return typeof rule === "function" ? Object.assign({ create: rule }, rule) : rule;
|
53
|
+
}
|
13
54
|
|
14
55
|
//------------------------------------------------------------------------------
|
15
56
|
// Public Interface
|
@@ -29,7 +70,7 @@ class Rules {
|
|
29
70
|
* @returns {void}
|
30
71
|
*/
|
31
72
|
define(ruleId, ruleModule) {
|
32
|
-
this._rules[ruleId] = ruleModule;
|
73
|
+
this._rules[ruleId] = normalizeRule(ruleModule);
|
33
74
|
}
|
34
75
|
|
35
76
|
/**
|
@@ -66,11 +107,15 @@ class Rules {
|
|
66
107
|
/**
|
67
108
|
* Access rule handler by id (file name).
|
68
109
|
* @param {string} ruleId Rule id (file name).
|
69
|
-
* @returns {Function
|
110
|
+
* @returns {{create: Function, schema: JsonSchema[]}}
|
111
|
+
* A rule. This is normalized to always have the new-style shape with a `create` method.
|
70
112
|
*/
|
71
113
|
get(ruleId) {
|
114
|
+
if (!Object.prototype.hasOwnProperty.call(this._rules, ruleId)) {
|
115
|
+
return createMissingRule(ruleId);
|
116
|
+
}
|
72
117
|
if (typeof this._rules[ruleId] === "string") {
|
73
|
-
return require(this._rules[ruleId]);
|
118
|
+
return normalizeRule(require(this._rules[ruleId]));
|
74
119
|
}
|
75
120
|
return this._rules[ruleId];
|
76
121
|
|