eslint 4.1.1 → 4.4.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 +106 -0
- package/bin/eslint.js +5 -4
- package/conf/category-list.json +2 -2
- package/conf/config-schema.js +3 -1
- package/conf/eslint-recommended.js +12 -14
- package/lib/cli-engine.js +4 -3
- package/lib/cli.js +12 -1
- package/lib/config/config-file.js +5 -5
- package/lib/config/config-initializer.js +123 -14
- package/lib/config/config-validator.js +43 -14
- package/lib/config/plugins.js +13 -1
- package/lib/linter.js +26 -15
- package/lib/rule-context.js +53 -41
- package/lib/rules/arrow-parens.js +5 -2
- package/lib/rules/comma-dangle.js +40 -40
- package/lib/rules/curly.js +1 -1
- package/lib/rules/dot-notation.js +9 -0
- package/lib/rules/getter-return.js +176 -0
- package/lib/rules/id-blacklist.js +7 -3
- package/lib/rules/id-match.js +8 -4
- package/lib/rules/indent-legacy.js +2 -2
- package/lib/rules/indent.js +354 -349
- package/lib/rules/key-spacing.js +2 -2
- package/lib/rules/multiline-ternary.js +8 -2
- package/lib/rules/no-cond-assign.js +7 -3
- package/lib/rules/no-constant-condition.js +62 -6
- package/lib/rules/no-debugger.js +6 -1
- package/lib/rules/no-else-return.js +1 -1
- package/lib/rules/no-extra-parens.js +24 -11
- package/lib/rules/no-inner-declarations.js +8 -4
- package/lib/rules/no-multi-spaces.js +53 -115
- package/lib/rules/no-regex-spaces.js +4 -4
- package/lib/rules/no-restricted-globals.js +50 -9
- package/lib/rules/no-restricted-properties.js +19 -11
- package/lib/rules/no-sync.js +15 -3
- package/lib/rules/no-tabs.js +8 -4
- package/lib/rules/no-underscore-dangle.js +28 -1
- package/lib/rules/object-curly-newline.js +18 -0
- package/lib/rules/object-curly-spacing.js +1 -1
- package/lib/rules/padded-blocks.js +2 -2
- package/lib/rules/padding-line-between-statements.js +1 -1
- package/lib/rules/prefer-destructuring.js +70 -32
- package/lib/rules/prefer-numeric-literals.js +36 -7
- package/lib/rules/prefer-reflect.js +8 -4
- package/lib/rules/prefer-template.js +2 -2
- package/lib/rules/space-infix-ops.js +1 -1
- package/lib/rules/spaced-comment.js +2 -2
- package/lib/rules/valid-jsdoc.js +15 -7
- package/lib/testers/rule-tester.js +23 -30
- package/lib/testers/test-parser.js +48 -0
- package/lib/util/ajv.js +29 -0
- package/lib/util/npm-util.js +9 -8
- package/lib/util/source-code-fixer.js +47 -19
- package/package.json +11 -7
- package/conf/json-schema-schema.json +0 -150
package/lib/rules/indent.js
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
/**
|
2
2
|
* @fileoverview This option sets a specific tab width for your code
|
3
3
|
*
|
4
|
-
*
|
4
|
+
* @author Teddy Katz
|
5
5
|
* @author Vitaly Puzrin
|
6
6
|
* @author Gyandeep Singh
|
7
7
|
*/
|
@@ -14,6 +14,7 @@
|
|
14
14
|
|
15
15
|
const lodash = require("lodash");
|
16
16
|
const astUtils = require("../ast-utils");
|
17
|
+
const createTree = require("functional-red-black-tree");
|
17
18
|
|
18
19
|
//------------------------------------------------------------------------------
|
19
20
|
// Rule Definition
|
@@ -114,6 +115,69 @@ const KNOWN_NODES = new Set([
|
|
114
115
|
* and report the token if the two values are not equal.
|
115
116
|
*/
|
116
117
|
|
118
|
+
|
119
|
+
/**
|
120
|
+
* A mutable balanced binary search tree that stores (key, value) pairs. The keys are numeric, and must be unique.
|
121
|
+
* This is intended to be a generic wrapper around a balanced binary search tree library, so that the underlying implementation
|
122
|
+
* can easily be swapped out.
|
123
|
+
*/
|
124
|
+
class BinarySearchTree {
|
125
|
+
|
126
|
+
/**
|
127
|
+
* Creates an empty tree
|
128
|
+
*/
|
129
|
+
constructor() {
|
130
|
+
this._rbTree = createTree();
|
131
|
+
}
|
132
|
+
|
133
|
+
/**
|
134
|
+
* Inserts an entry into the tree.
|
135
|
+
* @param {number} key The entry's key
|
136
|
+
* @param {*} value The entry's value
|
137
|
+
* @returns {void}
|
138
|
+
*/
|
139
|
+
insert(key, value) {
|
140
|
+
const iterator = this._rbTree.find(key);
|
141
|
+
|
142
|
+
if (iterator.valid) {
|
143
|
+
this._rbTree = iterator.update(value);
|
144
|
+
} else {
|
145
|
+
this._rbTree = this._rbTree.insert(key, value);
|
146
|
+
}
|
147
|
+
}
|
148
|
+
|
149
|
+
/**
|
150
|
+
* Finds the entry with the largest key less than or equal to the provided key
|
151
|
+
* @param {number} key The provided key
|
152
|
+
* @returns {{key: number, value: *}|null} The found entry, or null if no such entry exists.
|
153
|
+
*/
|
154
|
+
findLe(key) {
|
155
|
+
const iterator = this._rbTree.le(key);
|
156
|
+
|
157
|
+
return iterator && { key: iterator.key, value: iterator.value };
|
158
|
+
}
|
159
|
+
|
160
|
+
/**
|
161
|
+
* Deletes all of the keys in the interval [start, end)
|
162
|
+
* @param {number} start The start of the range
|
163
|
+
* @param {number} end The end of the range
|
164
|
+
* @returns {void}
|
165
|
+
*/
|
166
|
+
deleteRange(start, end) {
|
167
|
+
|
168
|
+
// Exit without traversing the tree if the range has zero size.
|
169
|
+
if (start === end) {
|
170
|
+
return;
|
171
|
+
}
|
172
|
+
const iterator = this._rbTree.ge(start);
|
173
|
+
|
174
|
+
while (iterator.valid && iterator.key < end) {
|
175
|
+
this._rbTree = this._rbTree.remove(iterator.key);
|
176
|
+
iterator.next();
|
177
|
+
}
|
178
|
+
}
|
179
|
+
}
|
180
|
+
|
117
181
|
/**
|
118
182
|
* A helper class to get token-based info related to indentation
|
119
183
|
*/
|
@@ -135,14 +199,6 @@ class TokenInfo {
|
|
135
199
|
}, new Map());
|
136
200
|
}
|
137
201
|
|
138
|
-
/**
|
139
|
-
* Gets all tokens and comments
|
140
|
-
* @returns {Token[]} A list of all tokens and comments
|
141
|
-
*/
|
142
|
-
getAllTokens() {
|
143
|
-
return this.sourceCode.tokensAndComments;
|
144
|
-
}
|
145
|
-
|
146
202
|
/**
|
147
203
|
* Gets the first token on a given token's line
|
148
204
|
* @param {Token|ASTNode} token a node or token
|
@@ -178,50 +234,28 @@ class OffsetStorage {
|
|
178
234
|
|
179
235
|
/**
|
180
236
|
* @param {TokenInfo} tokenInfo a TokenInfo instance
|
181
|
-
* @param {string} indentType The desired type of indentation (either "space" or "tab")
|
182
237
|
* @param {number} indentSize The desired size of each indentation level
|
183
238
|
*/
|
184
|
-
constructor(tokenInfo,
|
185
|
-
this.
|
186
|
-
this.
|
187
|
-
this.indentSize = indentSize;
|
239
|
+
constructor(tokenInfo, indentSize) {
|
240
|
+
this._tokenInfo = tokenInfo;
|
241
|
+
this._indentSize = indentSize;
|
188
242
|
|
189
|
-
|
190
|
-
|
191
|
-
* However, they're implemented as objects with range indices as keys because this improves performance as of Node 7.
|
192
|
-
* This uses the assumption that no two tokens start at the same index in the program.
|
193
|
-
*
|
194
|
-
* The values of the desiredOffsets map are objects with the schema { offset: number, from: Token|null }.
|
195
|
-
* These objects should not be mutated or exposed outside of OffsetStorage.
|
196
|
-
*/
|
197
|
-
const NO_OFFSET = { offset: 0, from: null };
|
198
|
-
|
199
|
-
this.desiredOffsets = tokenInfo.getAllTokens().reduce((desiredOffsets, token) => {
|
200
|
-
desiredOffsets[token.range[0]] = NO_OFFSET;
|
243
|
+
this._tree = new BinarySearchTree();
|
244
|
+
this._tree.insert(0, { offset: 0, from: null, force: false });
|
201
245
|
|
202
|
-
|
203
|
-
|
204
|
-
this.
|
205
|
-
this.desiredIndentCache = Object.create(null);
|
206
|
-
this.ignoredTokens = new WeakSet();
|
246
|
+
this._lockedFirstTokens = new WeakMap();
|
247
|
+
this._desiredIndentCache = new WeakMap();
|
248
|
+
this._ignoredTokens = new WeakSet();
|
207
249
|
}
|
208
250
|
|
209
|
-
|
210
|
-
|
211
|
-
* @param {Token} baseToken The first token
|
212
|
-
* @param {Token} offsetToken The second token, whose indent should be matched to the first token
|
213
|
-
* @returns {void}
|
214
|
-
*/
|
215
|
-
matchIndentOf(baseToken, offsetToken) {
|
216
|
-
if (baseToken !== offsetToken) {
|
217
|
-
this.desiredOffsets[offsetToken.range[0]] = { offset: 0, from: baseToken };
|
218
|
-
}
|
251
|
+
_getOffsetDescriptor(token) {
|
252
|
+
return this._tree.findLe(token.range[0]).value;
|
219
253
|
}
|
220
254
|
|
221
255
|
/**
|
222
256
|
* Sets the offset column of token B to match the offset column of token A.
|
223
|
-
* **WARNING**: This
|
224
|
-
*
|
257
|
+
* **WARNING**: This matches a *column*, even if baseToken is not the first token on its line. In
|
258
|
+
* most cases, `setDesiredOffset` should be used instead.
|
225
259
|
* @param {Token} baseToken The first token
|
226
260
|
* @param {Token} offsetToken The second token, whose offset should be matched to the first token
|
227
261
|
* @returns {void}
|
@@ -235,7 +269,7 @@ class OffsetStorage {
|
|
235
269
|
* element. The desired indentation of each of these tokens is computed based on the desired indentation
|
236
270
|
* of the "first" element, rather than through the normal offset mechanism.
|
237
271
|
*/
|
238
|
-
this.
|
272
|
+
this._lockedFirstTokens.set(offsetToken, baseToken);
|
239
273
|
}
|
240
274
|
|
241
275
|
/**
|
@@ -291,36 +325,84 @@ class OffsetStorage {
|
|
291
325
|
* in the second case.
|
292
326
|
*
|
293
327
|
* @param {Token} token The token
|
294
|
-
* @param {Token}
|
328
|
+
* @param {Token} fromToken The token that `token` should be offset from
|
295
329
|
* @param {number} offset The desired indent level
|
296
330
|
* @returns {void}
|
297
331
|
*/
|
298
|
-
setDesiredOffset(token,
|
299
|
-
|
300
|
-
this.matchIndentOf(offsetFrom, token);
|
301
|
-
} else {
|
302
|
-
this.desiredOffsets[token.range[0]] = { offset, from: offsetFrom };
|
303
|
-
}
|
332
|
+
setDesiredOffset(token, fromToken, offset) {
|
333
|
+
return this.setDesiredOffsets(token.range, fromToken, offset);
|
304
334
|
}
|
305
335
|
|
306
336
|
/**
|
307
|
-
* Sets the desired offset of
|
308
|
-
*
|
309
|
-
*
|
337
|
+
* Sets the desired offset of all tokens in a range
|
338
|
+
* It's common for node listeners in this file to need to apply the same offset to a large, contiguous range of tokens.
|
339
|
+
* Moreover, the offset of any given token is usually updated multiple times (roughly once for each node that contains
|
340
|
+
* it). This means that the offset of each token is updated O(AST depth) times.
|
341
|
+
* It would not be performant to store and update the offsets for each token independently, because the rule would end
|
342
|
+
* up having a time complexity of O(number of tokens * AST depth), which is quite slow for large files.
|
343
|
+
*
|
344
|
+
* Instead, the offset tree is represented as a collection of contiguous offset ranges in a file. For example, the following
|
345
|
+
* list could represent the state of the offset tree at a given point:
|
346
|
+
*
|
347
|
+
* * Tokens starting in the interval [0, 15) are aligned with the beginning of the file
|
348
|
+
* * Tokens starting in the interval [15, 30) are offset by 1 indent level from the `bar` token
|
349
|
+
* * Tokens starting in the interval [30, 43) are offset by 1 indent level from the `foo` token
|
350
|
+
* * Tokens starting in the interval [43, 820) are offset by 2 indent levels from the `bar` token
|
351
|
+
* * Tokens starting in the interval [820, ∞) are offset by 1 indent level from the `baz` token
|
352
|
+
*
|
353
|
+
* The `setDesiredOffsets` methods inserts ranges like the ones above. The third line above would be inserted by using:
|
354
|
+
* `setDesiredOffsets([30, 43], fooToken, 1);`
|
355
|
+
*
|
356
|
+
* @param {[number, number]} range A [start, end] pair. All tokens with range[0] <= token.start < range[1] will have the offset applied.
|
357
|
+
* @param {Token} fromToken The token that this is offset from
|
310
358
|
* @param {number} offset The desired indent level
|
359
|
+
* @param {boolean} force `true` if this offset should not use the normal collapsing behavior. This should almost always be false.
|
311
360
|
* @returns {void}
|
312
361
|
*/
|
313
|
-
setDesiredOffsets(
|
362
|
+
setDesiredOffsets(range, fromToken, offset, force) {
|
314
363
|
|
315
364
|
/*
|
316
|
-
*
|
317
|
-
*
|
318
|
-
*
|
319
|
-
*
|
320
|
-
*
|
321
|
-
*
|
365
|
+
* Offset ranges are stored as a collection of nodes, where each node maps a numeric key to an offset
|
366
|
+
* descriptor. The tree for the example above would have the following nodes:
|
367
|
+
*
|
368
|
+
* * key: 0, value: { offset: 0, from: null }
|
369
|
+
* * key: 15, value: { offset: 1, from: barToken }
|
370
|
+
* * key: 30, value: { offset: 1, from: fooToken }
|
371
|
+
* * key: 43, value: { offset: 2, from: barToken }
|
372
|
+
* * key: 820, value: { offset: 1, from: bazToken }
|
373
|
+
*
|
374
|
+
* To find the offset descriptor for any given token, one needs to find the node with the largest key
|
375
|
+
* which is <= token.start. To make this operation fast, the nodes are stored in a balanced binary
|
376
|
+
* search tree indexed by key.
|
322
377
|
*/
|
323
|
-
|
378
|
+
|
379
|
+
const descriptorToInsert = { offset, from: fromToken, force };
|
380
|
+
|
381
|
+
const descriptorAfterRange = this._tree.findLe(range[1]).value;
|
382
|
+
|
383
|
+
const fromTokenIsInRange = fromToken && fromToken.range[0] >= range[0] && fromToken.range[1] <= range[1];
|
384
|
+
const fromTokenDescriptor = fromTokenIsInRange && this._getOffsetDescriptor(fromToken);
|
385
|
+
|
386
|
+
// First, remove any existing nodes in the range from the tree.
|
387
|
+
this._tree.deleteRange(range[0] + 1, range[1]);
|
388
|
+
|
389
|
+
// Insert a new node into the tree for this range
|
390
|
+
this._tree.insert(range[0], descriptorToInsert);
|
391
|
+
|
392
|
+
/*
|
393
|
+
* To avoid circular offset dependencies, keep the `fromToken` token mapped to whatever it was mapped to previously,
|
394
|
+
* even if it's in the current range.
|
395
|
+
*/
|
396
|
+
if (fromTokenIsInRange) {
|
397
|
+
this._tree.insert(fromToken.range[0], fromTokenDescriptor);
|
398
|
+
this._tree.insert(fromToken.range[1], descriptorToInsert);
|
399
|
+
}
|
400
|
+
|
401
|
+
/*
|
402
|
+
* To avoid modifying the offset of tokens after the range, insert another node to keep the offset of the following
|
403
|
+
* tokens the same as it was before.
|
404
|
+
*/
|
405
|
+
this._tree.insert(range[1], descriptorAfterRange);
|
324
406
|
}
|
325
407
|
|
326
408
|
/**
|
@@ -329,30 +411,37 @@ class OffsetStorage {
|
|
329
411
|
* @returns {number} The desired indent of the token
|
330
412
|
*/
|
331
413
|
getDesiredIndent(token) {
|
332
|
-
if (!(token
|
414
|
+
if (!this._desiredIndentCache.has(token)) {
|
333
415
|
|
334
|
-
if (this.
|
416
|
+
if (this._ignoredTokens.has(token)) {
|
335
417
|
|
336
418
|
// If the token is ignored, use the actual indent of the token as the desired indent.
|
337
419
|
// This ensures that no errors are reported for this token.
|
338
|
-
this.
|
339
|
-
} else if (
|
340
|
-
const firstToken = this.
|
420
|
+
this._desiredIndentCache.set(token, this._tokenInfo.getTokenIndent(token).length / this._indentSize);
|
421
|
+
} else if (this._lockedFirstTokens.has(token)) {
|
422
|
+
const firstToken = this._lockedFirstTokens.get(token);
|
341
423
|
|
342
|
-
this.
|
424
|
+
this._desiredIndentCache.set(
|
425
|
+
token,
|
343
426
|
|
344
427
|
// (indentation for the first element's line)
|
345
|
-
this.getDesiredIndent(this.
|
428
|
+
this.getDesiredIndent(this._tokenInfo.getFirstTokenOfLine(firstToken)) +
|
346
429
|
|
347
430
|
// (space between the start of the first element's line and the first element)
|
348
|
-
(firstToken.loc.start.column - this.
|
431
|
+
(firstToken.loc.start.column - this._tokenInfo.getFirstTokenOfLine(firstToken).loc.start.column) / this._indentSize
|
432
|
+
);
|
349
433
|
} else {
|
350
|
-
const offsetInfo = this.
|
351
|
-
|
352
|
-
|
434
|
+
const offsetInfo = this._getOffsetDescriptor(token);
|
435
|
+
const offset = (
|
436
|
+
offsetInfo.from &&
|
437
|
+
offsetInfo.from.loc.start.line === token.loc.start.line &&
|
438
|
+
!offsetInfo.force
|
439
|
+
) ? 0 : offsetInfo.offset;
|
440
|
+
|
441
|
+
this._desiredIndentCache.set(token, offset + (offsetInfo.from ? this.getDesiredIndent(offsetInfo.from) : 0));
|
353
442
|
}
|
354
443
|
}
|
355
|
-
return this.
|
444
|
+
return this._desiredIndentCache.get(token);
|
356
445
|
}
|
357
446
|
|
358
447
|
/**
|
@@ -361,8 +450,8 @@ class OffsetStorage {
|
|
361
450
|
* @returns {void}
|
362
451
|
*/
|
363
452
|
ignoreToken(token) {
|
364
|
-
if (this.
|
365
|
-
this.
|
453
|
+
if (this._tokenInfo.isFirstTokenOfLine(token)) {
|
454
|
+
this._ignoredTokens.add(token);
|
366
455
|
}
|
367
456
|
}
|
368
457
|
|
@@ -372,19 +461,7 @@ class OffsetStorage {
|
|
372
461
|
* @returns {Token} The token that the given token depends on, or `null` if the given token is at the top level
|
373
462
|
*/
|
374
463
|
getFirstDependency(token) {
|
375
|
-
return this.
|
376
|
-
}
|
377
|
-
|
378
|
-
/**
|
379
|
-
* Increases the offset for a token from its parent by the given amount
|
380
|
-
* @param {Token} token The token whose offset should be increased
|
381
|
-
* @param {number} amount The number of indent levels that the offset should increase by
|
382
|
-
* @returns {void}
|
383
|
-
*/
|
384
|
-
increaseOffset(token, amount) {
|
385
|
-
const currentOffsetInfo = this.desiredOffsets[token.range[0]];
|
386
|
-
|
387
|
-
this.desiredOffsets[token.range[0]] = { offset: currentOffsetInfo.offset + amount, from: currentOffsetInfo.from };
|
464
|
+
return this._getOffsetDescriptor(token).from;
|
388
465
|
}
|
389
466
|
}
|
390
467
|
|
@@ -501,6 +578,7 @@ module.exports = {
|
|
501
578
|
},
|
502
579
|
ArrayExpression: ELEMENT_LIST_SCHEMA,
|
503
580
|
ObjectExpression: ELEMENT_LIST_SCHEMA,
|
581
|
+
ImportDeclaration: ELEMENT_LIST_SCHEMA,
|
504
582
|
flatTernaryExpressions: {
|
505
583
|
type: "boolean"
|
506
584
|
}
|
@@ -539,8 +617,7 @@ module.exports = {
|
|
539
617
|
MemberExpression: 1,
|
540
618
|
ArrayExpression: 1,
|
541
619
|
ObjectExpression: 1,
|
542
|
-
|
543
|
-
ObjectPattern: 1,
|
620
|
+
ImportDeclaration: 1,
|
544
621
|
flatTernaryExpressions: false
|
545
622
|
};
|
546
623
|
|
@@ -548,7 +625,7 @@ module.exports = {
|
|
548
625
|
if (context.options[0] === "tab") {
|
549
626
|
indentSize = 1;
|
550
627
|
indentType = "tab";
|
551
|
-
} else
|
628
|
+
} else {
|
552
629
|
indentSize = context.options[0];
|
553
630
|
indentType = "space";
|
554
631
|
}
|
@@ -568,7 +645,7 @@ module.exports = {
|
|
568
645
|
|
569
646
|
const sourceCode = context.getSourceCode();
|
570
647
|
const tokenInfo = new TokenInfo(sourceCode);
|
571
|
-
const offsets = new OffsetStorage(tokenInfo,
|
648
|
+
const offsets = new OffsetStorage(tokenInfo, indentSize);
|
572
649
|
const parameterParens = new WeakSet();
|
573
650
|
|
574
651
|
/**
|
@@ -600,10 +677,10 @@ module.exports = {
|
|
600
677
|
|
601
678
|
/**
|
602
679
|
* Reports a given indent violation
|
603
|
-
* @param {Token} token
|
680
|
+
* @param {Token} token Token violating the indent rule
|
604
681
|
* @param {int} neededIndentLevel Expected indentation level
|
605
|
-
* @param {int} gottenSpaces
|
606
|
-
* @param {int} gottenTabs
|
682
|
+
* @param {int} gottenSpaces Actual number of indentation spaces for the token
|
683
|
+
* @param {int} gottenTabs Actual number of indentation tabs for the token
|
607
684
|
* @returns {void}
|
608
685
|
*/
|
609
686
|
function report(token, neededIndentLevel) {
|
@@ -678,15 +755,6 @@ module.exports = {
|
|
678
755
|
return (statement.type === "ExpressionStatement" || statement.type === "VariableDeclaration") && statement.parent.type === "Program";
|
679
756
|
}
|
680
757
|
|
681
|
-
/**
|
682
|
-
* Gets all tokens and comments for a node
|
683
|
-
* @param {ASTNode} node The node
|
684
|
-
* @returns {Token[]} A list of tokens and comments
|
685
|
-
*/
|
686
|
-
function getTokensAndComments(node) {
|
687
|
-
return sourceCode.getTokens(node, { includeComments: true });
|
688
|
-
}
|
689
|
-
|
690
758
|
/**
|
691
759
|
* Check indentation for lists of elements (arrays, objects, function params)
|
692
760
|
* @param {ASTNode[]} elements List of elements that should be offset
|
@@ -712,13 +780,12 @@ module.exports = {
|
|
712
780
|
}
|
713
781
|
|
714
782
|
// Run through all the tokens in the list, and offset them by one indent level (mainly for comments, other things will end up overridden)
|
715
|
-
// FIXME: (not-an-aardvark) This isn't performant at all.
|
716
783
|
offsets.setDesiredOffsets(
|
717
|
-
|
784
|
+
[startToken.range[1], endToken.range[0]],
|
718
785
|
startToken,
|
719
786
|
offset === "first" ? 1 : offset
|
720
787
|
);
|
721
|
-
offsets.
|
788
|
+
offsets.setDesiredOffset(endToken, startToken, 0);
|
722
789
|
|
723
790
|
// If the preference is "first" but there is no first element (e.g. sparse arrays w/ empty first slot), fall back to 1 level.
|
724
791
|
if (offset === "first" && elements.length && !elements[0]) {
|
@@ -738,52 +805,12 @@ module.exports = {
|
|
738
805
|
const firstTokenOfPreviousElement = previousElement && getFirstToken(previousElement);
|
739
806
|
|
740
807
|
if (previousElement && sourceCode.getLastToken(previousElement).loc.start.line > startToken.loc.end.line) {
|
741
|
-
offsets.
|
808
|
+
offsets.setDesiredOffsets(element.range, firstTokenOfPreviousElement, 0);
|
742
809
|
}
|
743
810
|
}
|
744
811
|
});
|
745
812
|
}
|
746
813
|
|
747
|
-
/**
|
748
|
-
* Check indentation for blocks and class bodies
|
749
|
-
* @param {ASTNode} node The BlockStatement or ClassBody node to indent
|
750
|
-
* @returns {void}
|
751
|
-
*/
|
752
|
-
function addBlockIndent(node) {
|
753
|
-
|
754
|
-
let blockIndentLevel;
|
755
|
-
|
756
|
-
if (node.parent && isOuterIIFE(node.parent)) {
|
757
|
-
blockIndentLevel = options.outerIIFEBody;
|
758
|
-
} else if (node.parent && (node.parent.type === "FunctionExpression" || node.parent.type === "ArrowFunctionExpression")) {
|
759
|
-
blockIndentLevel = options.FunctionExpression.body;
|
760
|
-
} else if (node.parent && node.parent.type === "FunctionDeclaration") {
|
761
|
-
blockIndentLevel = options.FunctionDeclaration.body;
|
762
|
-
} else {
|
763
|
-
blockIndentLevel = 1;
|
764
|
-
}
|
765
|
-
|
766
|
-
/*
|
767
|
-
* For blocks that aren't lone statements, ensure that the opening curly brace
|
768
|
-
* is aligned with the parent.
|
769
|
-
*/
|
770
|
-
if (!astUtils.STATEMENT_LIST_PARENTS.has(node.parent.type)) {
|
771
|
-
offsets.matchIndentOf(sourceCode.getFirstToken(node.parent), sourceCode.getFirstToken(node));
|
772
|
-
}
|
773
|
-
addElementListIndent(node.body, sourceCode.getFirstToken(node), sourceCode.getLastToken(node), blockIndentLevel);
|
774
|
-
}
|
775
|
-
|
776
|
-
/**
|
777
|
-
* Check indent for array block content or object block content
|
778
|
-
* @param {ASTNode} node node to examine
|
779
|
-
* @returns {void}
|
780
|
-
*/
|
781
|
-
function addArrayOrObjectIndent(node) {
|
782
|
-
const tokens = getTokensAndComments(node);
|
783
|
-
|
784
|
-
addElementListIndent(node.elements || node.properties, tokens[0], tokens[tokens.length - 1], options[node.type]);
|
785
|
-
}
|
786
|
-
|
787
814
|
/**
|
788
815
|
* Check and decide whether to check for indentation for blockless nodes
|
789
816
|
* Scenarios are for or while statements without braces around them
|
@@ -794,16 +821,18 @@ module.exports = {
|
|
794
821
|
if (node.type !== "BlockStatement") {
|
795
822
|
const lastParentToken = sourceCode.getTokenBefore(node, astUtils.isNotOpeningParenToken);
|
796
823
|
|
797
|
-
let
|
824
|
+
let firstBodyToken = sourceCode.getFirstToken(node);
|
825
|
+
let lastBodyToken = sourceCode.getLastToken(node);
|
798
826
|
|
799
827
|
while (
|
800
|
-
astUtils.isOpeningParenToken(sourceCode.getTokenBefore(
|
801
|
-
astUtils.isClosingParenToken(sourceCode.getTokenAfter(
|
828
|
+
astUtils.isOpeningParenToken(sourceCode.getTokenBefore(firstBodyToken)) &&
|
829
|
+
astUtils.isClosingParenToken(sourceCode.getTokenAfter(lastBodyToken))
|
802
830
|
) {
|
803
|
-
|
831
|
+
firstBodyToken = sourceCode.getTokenBefore(firstBodyToken);
|
832
|
+
lastBodyToken = sourceCode.getTokenAfter(lastBodyToken);
|
804
833
|
}
|
805
834
|
|
806
|
-
offsets.setDesiredOffsets(
|
835
|
+
offsets.setDesiredOffsets([firstBodyToken.range[0], lastBodyToken.range[1]], lastParentToken, 1);
|
807
836
|
|
808
837
|
/*
|
809
838
|
* For blockless nodes with semicolon-first style, don't indent the semicolon.
|
@@ -813,60 +842,12 @@ module.exports = {
|
|
813
842
|
*/
|
814
843
|
const lastToken = sourceCode.getLastToken(node);
|
815
844
|
|
816
|
-
if (astUtils.isSemicolonToken(lastToken)) {
|
817
|
-
offsets.
|
845
|
+
if (node.type !== "EmptyStatement" && astUtils.isSemicolonToken(lastToken)) {
|
846
|
+
offsets.setDesiredOffset(lastToken, lastParentToken, 0);
|
818
847
|
}
|
819
848
|
}
|
820
849
|
}
|
821
850
|
|
822
|
-
/**
|
823
|
-
* Checks the indentation of a function's parameters
|
824
|
-
* @param {ASTNode} node The node
|
825
|
-
* @param {number} paramsIndent The indentation level option for the parameters
|
826
|
-
* @returns {void}
|
827
|
-
*/
|
828
|
-
function addFunctionParamsIndent(node, paramsIndent) {
|
829
|
-
const openingParen = node.params.length ? sourceCode.getTokenBefore(node.params[0]) : sourceCode.getTokenBefore(node.body, 1);
|
830
|
-
|
831
|
-
if (!openingParen) {
|
832
|
-
|
833
|
-
// If there is no opening paren (e.g. for an arrow function with a single parameter), don't indent anything.
|
834
|
-
return;
|
835
|
-
}
|
836
|
-
|
837
|
-
const closingParen = sourceCode.getTokenBefore(node.body);
|
838
|
-
const nodeTokens = getTokensAndComments(node);
|
839
|
-
const openingParenIndex = lodash.sortedIndexBy(nodeTokens, openingParen, token => token.range[0]);
|
840
|
-
const closingParenIndex = lodash.sortedIndexBy(nodeTokens, closingParen, token => token.range[0]);
|
841
|
-
|
842
|
-
parameterParens.add(nodeTokens[openingParenIndex]);
|
843
|
-
parameterParens.add(nodeTokens[closingParenIndex]);
|
844
|
-
|
845
|
-
addElementListIndent(node.params, nodeTokens[openingParenIndex], nodeTokens[closingParenIndex], paramsIndent);
|
846
|
-
}
|
847
|
-
|
848
|
-
/**
|
849
|
-
* Adds indentation for the right-hand side of binary/logical expressions.
|
850
|
-
* @param {ASTNode} node A BinaryExpression or LogicalExpression node
|
851
|
-
* @returns {void}
|
852
|
-
*/
|
853
|
-
function addBinaryOrLogicalExpressionIndent(node) {
|
854
|
-
const tokens = getTokensAndComments(node);
|
855
|
-
const operator = sourceCode.getFirstTokenBetween(node.left, node.right, token => token.value === node.operator);
|
856
|
-
const firstTokenAfterOperator = sourceCode.getTokenAfter(operator);
|
857
|
-
const tokensAfterOperator = tokens.slice(lodash.sortedIndexBy(tokens, firstTokenAfterOperator, token => token.range[0]));
|
858
|
-
|
859
|
-
/*
|
860
|
-
* For backwards compatibility, don't check BinaryExpression indents, e.g.
|
861
|
-
* var foo = bar &&
|
862
|
-
* baz;
|
863
|
-
*/
|
864
|
-
|
865
|
-
offsets.ignoreToken(operator);
|
866
|
-
offsets.ignoreToken(tokensAfterOperator[0]);
|
867
|
-
offsets.setDesiredOffsets(tokensAfterOperator, tokensAfterOperator[0], 1);
|
868
|
-
}
|
869
|
-
|
870
851
|
/**
|
871
852
|
* Checks the indentation for nodes that are like function calls (`CallExpression` and `NewExpression`)
|
872
853
|
* @param {ASTNode} node A CallExpression or NewExpression node
|
@@ -884,26 +865,11 @@ module.exports = {
|
|
884
865
|
|
885
866
|
parameterParens.add(openingParen);
|
886
867
|
parameterParens.add(closingParen);
|
887
|
-
offsets.
|
868
|
+
offsets.setDesiredOffset(openingParen, sourceCode.getTokenBefore(openingParen), 0);
|
888
869
|
|
889
870
|
addElementListIndent(node.arguments, openingParen, closingParen, options.CallExpression.arguments);
|
890
871
|
}
|
891
872
|
|
892
|
-
/**
|
893
|
-
* Checks the indentation of ClassDeclarations and ClassExpressions
|
894
|
-
* @param {ASTNode} node A ClassDeclaration or ClassExpression node
|
895
|
-
* @returns {void}
|
896
|
-
*/
|
897
|
-
function addClassIndent(node) {
|
898
|
-
if (node.superClass) {
|
899
|
-
const classToken = sourceCode.getFirstToken(node);
|
900
|
-
const extendsToken = sourceCode.getTokenBefore(node.superClass, astUtils.isNotOpeningParenToken);
|
901
|
-
|
902
|
-
offsets.setDesiredOffset(extendsToken, classToken, 1);
|
903
|
-
offsets.setDesiredOffsets(sourceCode.getTokensBetween(extendsToken, node.body, { includeComments: true }), classToken, 1);
|
904
|
-
}
|
905
|
-
}
|
906
|
-
|
907
873
|
/**
|
908
874
|
* Checks the indentation of parenthesized values, given a list of tokens in a program
|
909
875
|
* @param {Token[]} tokens A list of tokens
|
@@ -936,10 +902,9 @@ module.exports = {
|
|
936
902
|
offsets.setDesiredOffset(token, leftParen, 1);
|
937
903
|
}
|
938
904
|
});
|
939
|
-
offsets.setDesiredOffset(sourceCode.getTokenAfter(leftParen), leftParen, 1);
|
940
905
|
}
|
941
906
|
|
942
|
-
offsets.
|
907
|
+
offsets.setDesiredOffset(rightParen, leftParen, 0);
|
943
908
|
});
|
944
909
|
}
|
945
910
|
|
@@ -950,7 +915,7 @@ module.exports = {
|
|
950
915
|
* @returns {void}
|
951
916
|
*/
|
952
917
|
function ignoreUnknownNode(node) {
|
953
|
-
const unknownNodeTokens = new Set(
|
918
|
+
const unknownNodeTokens = new Set(sourceCode.getTokens(node, { includeComments: true }));
|
954
919
|
|
955
920
|
unknownNodeTokens.forEach(token => {
|
956
921
|
if (!unknownNodeTokens.has(offsets.getFirstDependency(token))) {
|
@@ -959,7 +924,7 @@ module.exports = {
|
|
959
924
|
if (token === firstTokenOfLine) {
|
960
925
|
offsets.ignoreToken(token);
|
961
926
|
} else {
|
962
|
-
offsets.
|
927
|
+
offsets.setDesiredOffset(token, firstTokenOfLine, 0);
|
963
928
|
}
|
964
929
|
}
|
965
930
|
});
|
@@ -996,11 +961,34 @@ module.exports = {
|
|
996
961
|
}
|
997
962
|
|
998
963
|
return {
|
999
|
-
ArrayExpression
|
1000
|
-
|
964
|
+
"ArrayExpression, ArrayPattern"(node) {
|
965
|
+
const openingBracket = sourceCode.getFirstToken(node);
|
966
|
+
const closingBracket = sourceCode.getTokenAfter(lodash.findLast(node.elements) || openingBracket, astUtils.isClosingBracketToken);
|
967
|
+
|
968
|
+
addElementListIndent(node.elements, openingBracket, closingBracket, options.ArrayExpression);
|
969
|
+
},
|
970
|
+
|
971
|
+
"ObjectExpression, ObjectPattern"(node) {
|
972
|
+
const openingCurly = sourceCode.getFirstToken(node);
|
973
|
+
const closingCurly = sourceCode.getTokenAfter(
|
974
|
+
node.properties.length ? node.properties[node.properties.length - 1] : openingCurly,
|
975
|
+
astUtils.isClosingBraceToken
|
976
|
+
);
|
977
|
+
|
978
|
+
addElementListIndent(node.properties, openingCurly, closingCurly, options.ObjectExpression);
|
979
|
+
},
|
1001
980
|
|
1002
981
|
ArrowFunctionExpression(node) {
|
1003
|
-
|
982
|
+
const firstToken = sourceCode.getFirstToken(node);
|
983
|
+
|
984
|
+
if (astUtils.isOpeningParenToken(firstToken)) {
|
985
|
+
const openingParen = firstToken;
|
986
|
+
const closingParen = sourceCode.getTokenBefore(node.body, astUtils.isClosingParenToken);
|
987
|
+
|
988
|
+
parameterParens.add(openingParen);
|
989
|
+
parameterParens.add(closingParen);
|
990
|
+
addElementListIndent(node.params, openingParen, closingParen, options.FunctionExpression.parameters);
|
991
|
+
}
|
1004
992
|
addBlocklessNodeIndent(node.body);
|
1005
993
|
|
1006
994
|
let arrowToken;
|
@@ -1010,30 +998,67 @@ module.exports = {
|
|
1010
998
|
} else {
|
1011
999
|
arrowToken = sourceCode.getFirstToken(node, astUtils.isArrowToken);
|
1012
1000
|
}
|
1013
|
-
offsets.
|
1001
|
+
offsets.setDesiredOffset(arrowToken, sourceCode.getFirstToken(node), 0);
|
1014
1002
|
},
|
1015
1003
|
|
1016
1004
|
AssignmentExpression(node) {
|
1017
1005
|
const operator = sourceCode.getFirstTokenBetween(node.left, node.right, token => token.value === node.operator);
|
1018
|
-
const nodeTokens = getTokensAndComments(node);
|
1019
|
-
const tokensFromOperator = nodeTokens.slice(lodash.sortedIndexBy(nodeTokens, operator, token => token.range[0]));
|
1020
1006
|
|
1021
|
-
offsets.setDesiredOffsets(
|
1022
|
-
offsets.ignoreToken(
|
1023
|
-
offsets.ignoreToken(
|
1007
|
+
offsets.setDesiredOffsets([operator.range[0], node.range[1]], sourceCode.getLastToken(node.left), 1);
|
1008
|
+
offsets.ignoreToken(operator);
|
1009
|
+
offsets.ignoreToken(sourceCode.getTokenAfter(operator));
|
1024
1010
|
},
|
1025
1011
|
|
1026
|
-
BinaryExpression
|
1012
|
+
"BinaryExpression, LogicalExpression"(node) {
|
1013
|
+
const operator = sourceCode.getFirstTokenBetween(node.left, node.right, token => token.value === node.operator);
|
1014
|
+
|
1015
|
+
/*
|
1016
|
+
* For backwards compatibility, don't check BinaryExpression indents, e.g.
|
1017
|
+
* var foo = bar &&
|
1018
|
+
* baz;
|
1019
|
+
*/
|
1020
|
+
|
1021
|
+
const tokenAfterOperator = sourceCode.getTokenAfter(operator);
|
1022
|
+
|
1023
|
+
offsets.ignoreToken(operator);
|
1024
|
+
offsets.ignoreToken(tokenAfterOperator);
|
1025
|
+
offsets.setDesiredOffset(tokenAfterOperator, operator, 0);
|
1026
|
+
offsets.setDesiredOffsets([tokenAfterOperator.range[1], node.range[1]], tokenAfterOperator, 1);
|
1027
|
+
},
|
1027
1028
|
|
1028
|
-
BlockStatement
|
1029
|
+
"BlockStatement, ClassBody"(node) {
|
1030
|
+
|
1031
|
+
let blockIndentLevel;
|
1032
|
+
|
1033
|
+
if (node.parent && isOuterIIFE(node.parent)) {
|
1034
|
+
blockIndentLevel = options.outerIIFEBody;
|
1035
|
+
} else if (node.parent && (node.parent.type === "FunctionExpression" || node.parent.type === "ArrowFunctionExpression")) {
|
1036
|
+
blockIndentLevel = options.FunctionExpression.body;
|
1037
|
+
} else if (node.parent && node.parent.type === "FunctionDeclaration") {
|
1038
|
+
blockIndentLevel = options.FunctionDeclaration.body;
|
1039
|
+
} else {
|
1040
|
+
blockIndentLevel = 1;
|
1041
|
+
}
|
1042
|
+
|
1043
|
+
/*
|
1044
|
+
* For blocks that aren't lone statements, ensure that the opening curly brace
|
1045
|
+
* is aligned with the parent.
|
1046
|
+
*/
|
1047
|
+
if (!astUtils.STATEMENT_LIST_PARENTS.has(node.parent.type)) {
|
1048
|
+
offsets.setDesiredOffset(sourceCode.getFirstToken(node), sourceCode.getFirstToken(node.parent), 0);
|
1049
|
+
}
|
1050
|
+
addElementListIndent(node.body, sourceCode.getFirstToken(node), sourceCode.getLastToken(node), blockIndentLevel);
|
1051
|
+
},
|
1029
1052
|
|
1030
1053
|
CallExpression: addFunctionCallIndent,
|
1031
1054
|
|
1032
|
-
ClassBody: addBlockIndent,
|
1033
1055
|
|
1034
|
-
ClassDeclaration
|
1056
|
+
"ClassDeclaration[superClass], ClassExpression[superClass]"(node) {
|
1057
|
+
const classToken = sourceCode.getFirstToken(node);
|
1058
|
+
const extendsToken = sourceCode.getTokenBefore(node.superClass, astUtils.isNotOpeningParenToken);
|
1035
1059
|
|
1036
|
-
|
1060
|
+
offsets.setDesiredOffsets([extendsToken.range[0], node.body.range[0]], classToken, 1);
|
1061
|
+
},
|
1037
1062
|
|
1038
1063
|
ConditionalExpression(node) {
|
1039
1064
|
const firstToken = sourceCode.getFirstToken(node);
|
@@ -1050,13 +1075,14 @@ module.exports = {
|
|
1050
1075
|
const questionMarkToken = sourceCode.getFirstTokenBetween(node.test, node.consequent, token => token.type === "Punctuator" && token.value === "?");
|
1051
1076
|
const colonToken = sourceCode.getFirstTokenBetween(node.consequent, node.alternate, token => token.type === "Punctuator" && token.value === ":");
|
1052
1077
|
|
1053
|
-
const
|
1054
|
-
const
|
1078
|
+
const firstConsequentToken = sourceCode.getTokenAfter(questionMarkToken, { includeComments: true });
|
1079
|
+
const lastConsequentToken = sourceCode.getTokenBefore(colonToken, { includeComments: true });
|
1080
|
+
const firstAlternateToken = sourceCode.getTokenAfter(colonToken);
|
1055
1081
|
|
1056
1082
|
offsets.setDesiredOffset(questionMarkToken, firstToken, 1);
|
1057
1083
|
offsets.setDesiredOffset(colonToken, firstToken, 1);
|
1058
1084
|
|
1059
|
-
offsets.setDesiredOffset(
|
1085
|
+
offsets.setDesiredOffset(firstConsequentToken, firstToken, 1);
|
1060
1086
|
|
1061
1087
|
/*
|
1062
1088
|
* The alternate and the consequent should usually have the same indentation.
|
@@ -1068,8 +1094,8 @@ module.exports = {
|
|
1068
1094
|
* baz // as a result, `baz` is offset by 1 rather than 2
|
1069
1095
|
* )
|
1070
1096
|
*/
|
1071
|
-
if (
|
1072
|
-
offsets.
|
1097
|
+
if (lastConsequentToken.loc.end.line === firstAlternateToken.loc.start.line) {
|
1098
|
+
offsets.setDesiredOffset(firstAlternateToken, firstConsequentToken, 0);
|
1073
1099
|
} else {
|
1074
1100
|
|
1075
1101
|
/**
|
@@ -1081,21 +1107,19 @@ module.exports = {
|
|
1081
1107
|
* If `baz` were aligned with `bar` rather than being offset by 1 from `foo`, `baz` would end up
|
1082
1108
|
* having no expected indentation.
|
1083
1109
|
*/
|
1084
|
-
offsets.setDesiredOffset(
|
1110
|
+
offsets.setDesiredOffset(firstAlternateToken, firstToken, 1);
|
1085
1111
|
}
|
1086
1112
|
|
1087
|
-
offsets.setDesiredOffsets(
|
1088
|
-
offsets.setDesiredOffsets(
|
1113
|
+
offsets.setDesiredOffsets([questionMarkToken.range[1], colonToken.range[0]], firstConsequentToken, 0);
|
1114
|
+
offsets.setDesiredOffsets([colonToken.range[1], node.range[1]], firstAlternateToken, 0);
|
1089
1115
|
}
|
1090
1116
|
},
|
1091
1117
|
|
1092
|
-
DoWhileStatement: node => addBlocklessNodeIndent(node.body),
|
1118
|
+
"DoWhileStatement, WhileStatement, ForInStatement, ForOfStatement": node => addBlocklessNodeIndent(node.body),
|
1093
1119
|
|
1094
1120
|
ExportNamedDeclaration(node) {
|
1095
1121
|
if (node.declaration === null) {
|
1096
|
-
const tokensInNode = getTokensAndComments(node);
|
1097
1122
|
const closingCurly = sourceCode.getLastToken(node, astUtils.isClosingBraceToken);
|
1098
|
-
const closingCurlyIndex = lodash.sortedIndexBy(tokensInNode, closingCurly, token => token.range[0]);
|
1099
1123
|
|
1100
1124
|
// Indent the specifiers in `export {foo, bar, baz}`
|
1101
1125
|
addElementListIndent(node.specifiers, sourceCode.getFirstToken(node, { skip: 1 }), closingCurly, 1);
|
@@ -1103,36 +1127,33 @@ module.exports = {
|
|
1103
1127
|
if (node.source) {
|
1104
1128
|
|
1105
1129
|
// Indent everything after and including the `from` token in `export {foo, bar, baz} from 'qux'`
|
1106
|
-
offsets.setDesiredOffsets(
|
1130
|
+
offsets.setDesiredOffsets([closingCurly.range[1], node.range[1]], sourceCode.getFirstToken(node), 1);
|
1107
1131
|
}
|
1108
1132
|
}
|
1109
1133
|
},
|
1110
1134
|
|
1111
|
-
ForInStatement: node => addBlocklessNodeIndent(node.body),
|
1112
|
-
|
1113
|
-
ForOfStatement: node => addBlocklessNodeIndent(node.body),
|
1114
|
-
|
1115
1135
|
ForStatement(node) {
|
1116
1136
|
const forOpeningParen = sourceCode.getFirstToken(node, 1);
|
1117
1137
|
|
1118
1138
|
if (node.init) {
|
1119
|
-
offsets.setDesiredOffsets(
|
1139
|
+
offsets.setDesiredOffsets(node.init.range, forOpeningParen, 1);
|
1120
1140
|
}
|
1121
1141
|
if (node.test) {
|
1122
|
-
offsets.setDesiredOffsets(
|
1142
|
+
offsets.setDesiredOffsets(node.test.range, forOpeningParen, 1);
|
1123
1143
|
}
|
1124
1144
|
if (node.update) {
|
1125
|
-
offsets.setDesiredOffsets(
|
1145
|
+
offsets.setDesiredOffsets(node.update.range, forOpeningParen, 1);
|
1126
1146
|
}
|
1127
1147
|
addBlocklessNodeIndent(node.body);
|
1128
1148
|
},
|
1129
1149
|
|
1130
|
-
FunctionDeclaration(node) {
|
1131
|
-
|
1132
|
-
|
1150
|
+
"FunctionDeclaration, FunctionExpression"(node) {
|
1151
|
+
const closingParen = sourceCode.getTokenBefore(node.body);
|
1152
|
+
const openingParen = sourceCode.getTokenBefore(node.params.length ? node.params[0] : closingParen);
|
1133
1153
|
|
1134
|
-
|
1135
|
-
|
1154
|
+
parameterParens.add(openingParen);
|
1155
|
+
parameterParens.add(closingParen);
|
1156
|
+
addElementListIndent(node.params, openingParen, closingParen, options[node.type].parameters);
|
1136
1157
|
},
|
1137
1158
|
|
1138
1159
|
IfStatement(node) {
|
@@ -1147,34 +1168,32 @@ module.exports = {
|
|
1147
1168
|
const openingCurly = sourceCode.getFirstToken(node, astUtils.isOpeningBraceToken);
|
1148
1169
|
const closingCurly = sourceCode.getLastToken(node, astUtils.isClosingBraceToken);
|
1149
1170
|
|
1150
|
-
addElementListIndent(node.specifiers.filter(specifier => specifier.type === "ImportSpecifier"), openingCurly, closingCurly,
|
1171
|
+
addElementListIndent(node.specifiers.filter(specifier => specifier.type === "ImportSpecifier"), openingCurly, closingCurly, options.ImportDeclaration);
|
1151
1172
|
}
|
1152
1173
|
|
1153
1174
|
const fromToken = sourceCode.getLastToken(node, token => token.type === "Identifier" && token.value === "from");
|
1154
1175
|
|
1155
1176
|
if (fromToken) {
|
1156
|
-
|
1157
|
-
|
1158
|
-
offsets.setDesiredOffsets(tokensToOffset, sourceCode.getFirstToken(node), 1);
|
1177
|
+
offsets.setDesiredOffsets([fromToken.range[0], node.range[1]], sourceCode.getFirstToken(node), 1);
|
1159
1178
|
}
|
1160
1179
|
},
|
1161
1180
|
|
1162
|
-
LogicalExpression: addBinaryOrLogicalExpressionIndent,
|
1163
|
-
|
1164
1181
|
"MemberExpression, JSXMemberExpression"(node) {
|
1165
1182
|
const firstNonObjectToken = sourceCode.getFirstTokenBetween(node.object, node.property, astUtils.isNotClosingParenToken);
|
1166
1183
|
const secondNonObjectToken = sourceCode.getTokenAfter(firstNonObjectToken);
|
1167
1184
|
|
1168
|
-
const
|
1169
|
-
const firstObjectToken =
|
1185
|
+
const objectParenCount = sourceCode.getTokensBetween(node.object, node.property, { filter: astUtils.isClosingParenToken }).length;
|
1186
|
+
const firstObjectToken = objectParenCount
|
1187
|
+
? sourceCode.getTokenBefore(node.object, { skip: objectParenCount - 1 })
|
1188
|
+
: sourceCode.getFirstToken(node.object);
|
1170
1189
|
const lastObjectToken = sourceCode.getTokenBefore(firstNonObjectToken);
|
1171
1190
|
const firstPropertyToken = node.computed ? firstNonObjectToken : secondNonObjectToken;
|
1172
1191
|
|
1173
1192
|
if (node.computed) {
|
1174
1193
|
|
1175
1194
|
// For computed MemberExpressions, match the closing bracket with the opening bracket.
|
1176
|
-
offsets.
|
1177
|
-
offsets.setDesiredOffsets(
|
1195
|
+
offsets.setDesiredOffset(sourceCode.getLastToken(node), firstNonObjectToken, 0);
|
1196
|
+
offsets.setDesiredOffsets(node.property.range, firstNonObjectToken, 1);
|
1178
1197
|
}
|
1179
1198
|
|
1180
1199
|
/*
|
@@ -1207,8 +1226,8 @@ module.exports = {
|
|
1207
1226
|
offsets.ignoreToken(secondNonObjectToken);
|
1208
1227
|
|
1209
1228
|
// To ignore the property indentation, ensure that the property tokens depend on the ignored tokens.
|
1210
|
-
offsets.
|
1211
|
-
offsets.
|
1229
|
+
offsets.setDesiredOffset(firstNonObjectToken, offsetBase, 0);
|
1230
|
+
offsets.setDesiredOffset(secondNonObjectToken, firstNonObjectToken, 0);
|
1212
1231
|
}
|
1213
1232
|
},
|
1214
1233
|
|
@@ -1220,11 +1239,8 @@ module.exports = {
|
|
1220
1239
|
}
|
1221
1240
|
},
|
1222
1241
|
|
1223
|
-
ObjectExpression: addArrayOrObjectIndent,
|
1224
|
-
ObjectPattern: addArrayOrObjectIndent,
|
1225
|
-
|
1226
1242
|
Property(node) {
|
1227
|
-
if (!node.
|
1243
|
+
if (!node.shorthand && !node.method && node.kind === "init") {
|
1228
1244
|
const colon = sourceCode.getFirstTokenBetween(node.key, node.value, astUtils.isColonToken);
|
1229
1245
|
|
1230
1246
|
offsets.ignoreToken(sourceCode.getTokenAfter(colon));
|
@@ -1232,41 +1248,38 @@ module.exports = {
|
|
1232
1248
|
},
|
1233
1249
|
|
1234
1250
|
SwitchStatement(node) {
|
1235
|
-
const
|
1236
|
-
const
|
1251
|
+
const openingCurly = sourceCode.getTokenAfter(node.discriminant, astUtils.isOpeningBraceToken);
|
1252
|
+
const closingCurly = sourceCode.getLastToken(node);
|
1253
|
+
const caseKeywords = node.cases.map(switchCase => sourceCode.getFirstToken(switchCase));
|
1237
1254
|
|
1238
|
-
offsets.setDesiredOffsets(
|
1255
|
+
offsets.setDesiredOffsets([openingCurly.range[1], closingCurly.range[0]], openingCurly, options.SwitchCase);
|
1239
1256
|
|
1240
|
-
|
1241
|
-
|
1242
|
-
const casesWithBlocks = new WeakSet(
|
1243
|
-
node.cases
|
1244
|
-
.filter(switchCase => switchCase.consequent.length === 1 && switchCase.consequent[0].type === "BlockStatement")
|
1245
|
-
.map(switchCase => sourceCode.getFirstToken(switchCase))
|
1246
|
-
);
|
1247
|
-
let lastAnchor = tokens[openingCurlyIndex];
|
1257
|
+
node.cases.forEach((switchCase, index) => {
|
1258
|
+
const caseKeyword = caseKeywords[index];
|
1248
1259
|
|
1249
|
-
|
1250
|
-
|
1251
|
-
|
1252
|
-
|
1253
|
-
offsets.ignoreToken(token);
|
1254
|
-
} else if (!casesWithBlocks.has(lastAnchor)) {
|
1255
|
-
offsets.setDesiredOffset(token, lastAnchor, 1);
|
1260
|
+
if (!(switchCase.consequent.length === 1 && switchCase.consequent[0].type === "BlockStatement")) {
|
1261
|
+
const tokenAfterCurrentCase = index === node.cases.length - 1 ? closingCurly : caseKeywords[index + 1];
|
1262
|
+
|
1263
|
+
offsets.setDesiredOffsets([caseKeyword.range[1], tokenAfterCurrentCase.range[0]], caseKeyword, 1);
|
1256
1264
|
}
|
1257
1265
|
});
|
1266
|
+
|
1267
|
+
if (node.cases.length) {
|
1268
|
+
sourceCode.getTokensBetween(
|
1269
|
+
node.cases[node.cases.length - 1],
|
1270
|
+
closingCurly,
|
1271
|
+
{ includeComments: true, filter: astUtils.isCommentToken }
|
1272
|
+
).forEach(token => offsets.ignoreToken(token));
|
1273
|
+
}
|
1258
1274
|
},
|
1259
1275
|
|
1260
1276
|
TemplateLiteral(node) {
|
1261
|
-
const tokens = getTokensAndComments(node);
|
1262
|
-
|
1263
|
-
offsets.setDesiredOffsets(getTokensAndComments(node.quasis[0]), tokens[0], 0);
|
1264
1277
|
node.expressions.forEach((expression, index) => {
|
1265
1278
|
const previousQuasi = node.quasis[index];
|
1266
1279
|
const nextQuasi = node.quasis[index + 1];
|
1267
1280
|
const tokenToAlignFrom = previousQuasi.loc.start.line === previousQuasi.loc.end.line ? sourceCode.getFirstToken(previousQuasi) : null;
|
1268
1281
|
|
1269
|
-
offsets.setDesiredOffsets(
|
1282
|
+
offsets.setDesiredOffsets([previousQuasi.range[1], nextQuasi.range[0]], tokenToAlignFrom, 1);
|
1270
1283
|
offsets.setDesiredOffset(sourceCode.getFirstToken(nextQuasi), tokenToAlignFrom, 0);
|
1271
1284
|
});
|
1272
1285
|
},
|
@@ -1274,7 +1287,33 @@ module.exports = {
|
|
1274
1287
|
VariableDeclaration(node) {
|
1275
1288
|
const variableIndent = options.VariableDeclarator.hasOwnProperty(node.kind) ? options.VariableDeclarator[node.kind] : DEFAULT_VARIABLE_INDENT;
|
1276
1289
|
|
1277
|
-
|
1290
|
+
if (node.declarations[node.declarations.length - 1].loc.start.line > node.loc.start.line) {
|
1291
|
+
|
1292
|
+
/*
|
1293
|
+
* VariableDeclarator indentation is a bit different from other forms of indentation, in that the
|
1294
|
+
* indentation of an opening bracket sometimes won't match that of a closing bracket. For example,
|
1295
|
+
* the following indentations are correct:
|
1296
|
+
*
|
1297
|
+
* var foo = {
|
1298
|
+
* ok: true
|
1299
|
+
* };
|
1300
|
+
*
|
1301
|
+
* var foo = {
|
1302
|
+
* ok: true,
|
1303
|
+
* },
|
1304
|
+
* bar = 1;
|
1305
|
+
*
|
1306
|
+
* Account for when exiting the AST (after indentations have already been set for the nodes in
|
1307
|
+
* the declaration) by manually increasing the indentation level of the tokens in this declarator
|
1308
|
+
* on the same line as the start of the declaration, provided that there are declarators that
|
1309
|
+
* follow this one.
|
1310
|
+
*/
|
1311
|
+
const firstToken = sourceCode.getFirstToken(node);
|
1312
|
+
|
1313
|
+
offsets.setDesiredOffsets(node.range, firstToken, variableIndent, true);
|
1314
|
+
} else {
|
1315
|
+
offsets.setDesiredOffsets(node.range, sourceCode.getFirstToken(node), variableIndent);
|
1316
|
+
}
|
1278
1317
|
const lastToken = sourceCode.getLastToken(node);
|
1279
1318
|
|
1280
1319
|
if (astUtils.isSemicolonToken(lastToken)) {
|
@@ -1289,52 +1328,17 @@ module.exports = {
|
|
1289
1328
|
|
1290
1329
|
offsets.ignoreToken(equalOperator);
|
1291
1330
|
offsets.ignoreToken(tokenAfterOperator);
|
1292
|
-
offsets.
|
1293
|
-
offsets.
|
1331
|
+
offsets.setDesiredOffsets([tokenAfterOperator.range[0], node.range[1]], equalOperator, 1);
|
1332
|
+
offsets.setDesiredOffset(equalOperator, sourceCode.getLastToken(node.id), 0);
|
1294
1333
|
}
|
1295
1334
|
},
|
1296
1335
|
|
1297
|
-
"VariableDeclarator:exit"(node) {
|
1298
|
-
|
1299
|
-
/*
|
1300
|
-
* VariableDeclarator indentation is a bit different from other forms of indentation, in that the
|
1301
|
-
* indentation of an opening bracket sometimes won't match that of a closing bracket. For example,
|
1302
|
-
* the following indentations are correct:
|
1303
|
-
*
|
1304
|
-
* var foo = {
|
1305
|
-
* ok: true
|
1306
|
-
* };
|
1307
|
-
*
|
1308
|
-
* var foo = {
|
1309
|
-
* ok: true,
|
1310
|
-
* },
|
1311
|
-
* bar = 1;
|
1312
|
-
*
|
1313
|
-
* Account for when exiting the AST (after indentations have already been set for the nodes in
|
1314
|
-
* the declaration) by manually increasing the indentation level of the tokens in the first declarator if the
|
1315
|
-
* parent declaration has more than one declarator.
|
1316
|
-
*/
|
1317
|
-
if (node.parent.declarations.length > 1 && node.parent.declarations[0] === node && node.init) {
|
1318
|
-
const valueTokens = new Set(getTokensAndComments(node.init));
|
1319
|
-
|
1320
|
-
valueTokens.forEach(token => {
|
1321
|
-
if (!valueTokens.has(offsets.getFirstDependency(token))) {
|
1322
|
-
offsets.increaseOffset(token, options.VariableDeclarator[node.parent.kind]);
|
1323
|
-
}
|
1324
|
-
});
|
1325
|
-
}
|
1326
|
-
},
|
1327
|
-
|
1328
|
-
WhileStatement: node => addBlocklessNodeIndent(node.body),
|
1329
|
-
|
1330
1336
|
"*:exit": checkForUnknownNode,
|
1331
1337
|
|
1332
1338
|
"JSXAttribute[value]"(node) {
|
1333
1339
|
const equalsToken = sourceCode.getFirstTokenBetween(node.name, node.value, token => token.type === "Punctuator" && token.value === "=");
|
1334
|
-
const firstNameToken = sourceCode.getFirstToken(node.name);
|
1335
1340
|
|
1336
|
-
offsets.
|
1337
|
-
offsets.setDesiredOffset(sourceCode.getFirstToken(node.value), firstNameToken, 1);
|
1341
|
+
offsets.setDesiredOffsets([equalsToken.range[0], node.value.range[1]], sourceCode.getFirstToken(node.name), 1);
|
1338
1342
|
},
|
1339
1343
|
|
1340
1344
|
JSXElement(node) {
|
@@ -1349,30 +1353,31 @@ module.exports = {
|
|
1349
1353
|
|
1350
1354
|
if (node.selfClosing) {
|
1351
1355
|
closingToken = sourceCode.getLastToken(node, { skip: 1 });
|
1352
|
-
offsets.
|
1356
|
+
offsets.setDesiredOffset(sourceCode.getLastToken(node), closingToken, 0);
|
1353
1357
|
} else {
|
1354
1358
|
closingToken = sourceCode.getLastToken(node);
|
1355
1359
|
}
|
1356
|
-
offsets.setDesiredOffsets(
|
1360
|
+
offsets.setDesiredOffsets(node.name.range, sourceCode.getFirstToken(node));
|
1357
1361
|
addElementListIndent(node.attributes, firstToken, closingToken, 1);
|
1358
1362
|
},
|
1359
1363
|
|
1360
1364
|
JSXClosingElement(node) {
|
1361
1365
|
const firstToken = sourceCode.getFirstToken(node);
|
1362
1366
|
|
1363
|
-
offsets.setDesiredOffsets(
|
1364
|
-
offsets.
|
1367
|
+
offsets.setDesiredOffsets(node.name.range, firstToken, 1);
|
1368
|
+
offsets.setDesiredOffset(sourceCode.getLastToken(node), firstToken, 0);
|
1365
1369
|
},
|
1366
1370
|
|
1367
1371
|
JSXExpressionContainer(node) {
|
1368
1372
|
const openingCurly = sourceCode.getFirstToken(node);
|
1369
|
-
const
|
1373
|
+
const closingCurly = sourceCode.getLastToken(node);
|
1370
1374
|
|
1371
|
-
|
1372
|
-
|
1373
|
-
|
1374
|
-
|
1375
|
-
|
1375
|
+
offsets.setDesiredOffsets(
|
1376
|
+
[openingCurly.range[1], closingCurly.range[0]],
|
1377
|
+
openingCurly,
|
1378
|
+
1
|
1379
|
+
);
|
1380
|
+
offsets.setDesiredOffset(closingCurly, openingCurly, 0);
|
1376
1381
|
},
|
1377
1382
|
|
1378
1383
|
"Program:exit"() {
|