diff --git a/lib/rules/indent.js b/lib/rules/indent.js index d1e94c9..4af55ee 100644 --- a/lib/rules/indent.js +++ b/lib/rules/indent.js @@ -363,10 +363,11 @@ class OffsetStorage { * @param {Token} token The token * @param {Token} fromToken The token that `token` should be offset from * @param {number} offset The desired indent level + * @param {number} extraIndent The extra static indent amount to add to desired offset * @returns {void} */ - setDesiredOffset(token, fromToken, offset) { - return this.setDesiredOffsets(token.range, fromToken, offset); + setDesiredOffset(token, fromToken, offset, extraIndent) { + return this.setDesiredOffsets(token.range, fromToken, offset, extraIndent); } /** @@ -404,9 +405,10 @@ class OffsetStorage { * @param {number} offset The desired indent level * @param {boolean} force `true` if this offset should not use the normal collapsing * behavior. This should almost always be false. + * @param {number} extraIndent The extra static indent amount to add to desired offset * @returns {void} */ - setDesiredOffsets(range, fromToken, offset, force) { + setDesiredOffsets(range, fromToken, offset, force, extraIndent) { /* * Offset ranges are stored as a collection of nodes, where each node maps a @@ -423,7 +425,7 @@ class OffsetStorage { * with the largest key which is <= token.start. To make this operation fast, the * nodes are stored in a balanced binary search tree indexed by key. */ - const descriptorToInsert = { offset, from: fromToken, force }; + const descriptorToInsert = { offset, from: fromToken, force, extraIndent }; const descriptorAfterRange = this._tree.findLe(range[1]).value; @@ -485,12 +487,14 @@ class OffsetStorage { } else { const offsetInfo = this._getOffsetDescriptor(token); + const extraIndent = offsetInfo.extraIndent ? offsetInfo.extraIndent : 0; + const offset = ( offsetInfo.from && offsetInfo.from.loc.start.line === token.loc.start.line && !/^\s*?\n/.test(token.value) && !offsetInfo.force - ) ? 0 : offsetInfo.offset * this._indentSize; + ) ? 0 : offsetInfo.offset * this._indentSize + extraIndent; this._desiredIndentCache.set( token, @@ -581,7 +585,7 @@ module.exports = { type: 'number', minimum: 0, }, - let: { + 'let': { type: 'number', minimum: 0, }, @@ -594,6 +598,32 @@ module.exports = { }, ], }, + VariableDeclaratorOffset: { + oneOf: [ + { + type: 'integer', + minimum: 0, + }, + { + type: 'object', + properties: { + 'var': { + type: 'integer', + minimum: 0, + }, + 'let': { + type: 'integer', + minimum: 0, + }, + 'const': { + type: 'integer', + minimum: 0, + }, + }, + additionalProperties: false, + }, + ], + }, outerIIFEBody: { type: 'integer', minimum: 0, @@ -664,6 +694,7 @@ module.exports = { create(context) { const DEFAULT_VARIABLE_INDENT = 1, + DEFAULT_VARIABLE_STATIC_OFFSET = 0, DEFAULT_PARAMETER_INDENT = 1, DEFAULT_FUNCTION_BODY_INDENT = 1; @@ -677,6 +708,11 @@ module.exports = { let: DEFAULT_VARIABLE_INDENT, 'const': DEFAULT_VARIABLE_INDENT, }, + VariableDeclaratorOffset: { + 'var': DEFAULT_VARIABLE_STATIC_OFFSET, + let: DEFAULT_VARIABLE_STATIC_OFFSET, + 'const': DEFAULT_VARIABLE_STATIC_OFFSET, + }, outerIIFEBody: 1, FunctionDeclaration: { parameters: DEFAULT_PARAMETER_INDENT, @@ -717,6 +753,14 @@ module.exports = { 'const': options.VariableDeclarator, }; } + + if (typeof options.VariableDeclaratorOffset === 'number') { + options.VariableDeclaratorOffset = { + 'var': options.VariableDeclaratorOffset, + let: options.VariableDeclaratorOffset, + 'const': options.VariableDeclaratorOffset, + }; + } } } @@ -1464,6 +1508,10 @@ module.exports = { ? options.VariableDeclarator[node.kind] : DEFAULT_VARIABLE_INDENT; + const extraVariableIndent = Object.prototype.hasOwnProperty.call(options.VariableDeclaratorOffset, node.kind) + ? options.VariableDeclaratorOffset[node.kind] + : 0; + if (node.declarations[node.declarations.length - 1].loc.start.line > node.loc.start.line) { /* @@ -1489,7 +1537,19 @@ module.exports = { */ const firstToken = sourceCode.getFirstToken(node); - offsets.setDesiredOffsets(node.range, firstToken, variableIndent, true); + offsets.setDesiredOffsets(node.range, firstToken, variableIndent, true, extraVariableIndent); + } else if (node.loc.start.line === node.loc.end.line) { + + /* Only add the extra space if this declaration doesn't span multiple + * lines. Otherwise, we can't do: + * const myArr [ + * { + * a: 1, + * b: 2, + * }, + * ]; + */ + offsets.setDesiredOffsets(node.range, sourceCode.getFirstToken(node), variableIndent, extraVariableIndent); } else { offsets.setDesiredOffsets(node.range, sourceCode.getFirstToken(node), variableIndent); } diff --git a/tests/lib/rules/indent.test.js b/tests/lib/rules/indent.test.js index e144ace..a2ef8f7 100644 --- a/tests/lib/rules/indent.test.js +++ b/tests/lib/rules/indent.test.js @@ -83,7 +83,7 @@ constExample = formatCode( ' a: 1,', ' b: 2,', ' },', - '];', + '];' ); constInvalid = formatCode( @@ -120,8 +120,8 @@ ruleTester.run('indent', rule, { code: invalidExample, errors: [ { - message: 'Expected indentation of 7 space characters but found 6.', - type: 'VariableDeclarator', + message: 'Expected indentation of 7 spaces but found 6.', + type: 'Identifier', }, ], options: [ 3, { 'VariableDeclaratorOffset': { 'var': 1, 'let': 1, 'const': 3 }, 'SwitchCase': 1 } ], @@ -130,8 +130,8 @@ ruleTester.run('indent', rule, { code: invalidExample2, errors: [ { - message: 'Expected indentation of 3 space characters but found 2.', - type: 'ExpressionStatement', + message: 'Expected indentation of 3 spaces but found 2.', + type: 'Identifier', }, ], options: [ 3, { 'VariableDeclaratorOffset': { 'var': 1, 'let': 1, 'const': 3 }, 'SwitchCase': 1 } ], @@ -140,8 +140,8 @@ ruleTester.run('indent', rule, { code: invalidExample3, errors: [ { - message: 'Expected indentation of 3 space characters but found 0.', - type: 'ExpressionStatement', + message: 'Expected indentation of 3 spaces but found 0.', + type: 'Identifier', }, ], options: [ 3, { 'VariableDeclaratorOffset': { 'var': 1, 'let': 1, 'const': 3 }, 'SwitchCase': 1 } ], @@ -150,20 +150,20 @@ ruleTester.run('indent', rule, { code: switchTest, errors: [ { - message: 'Expected indentation of 0 space characters but found 3.', - type: 'SwitchCase', + message: 'Expected indentation of 0 spaces but found 3.', + type: 'Keyword', }, { - message: 'Expected indentation of 3 space characters but found 6.', - type: 'BreakStatement', + message: 'Expected indentation of 3 spaces but found 6.', + type: 'Keyword', }, { - message: 'Expected indentation of 0 space characters but found 3.', - type: 'SwitchCase', + message: 'Expected indentation of 0 spaces but found 3.', + type: 'Keyword', }, { - message: 'Expected indentation of 3 space characters but found 6.', - type: 'ExpressionStatement', + message: 'Expected indentation of 3 spaces but found 6.', + type: 'Identifier', }, ], options: [ 3, { 'VariableDeclaratorOffset': { 'var': 1, 'let': 1, 'const': 3 } } ], @@ -172,12 +172,12 @@ ruleTester.run('indent', rule, { code: constInvalid, errors: [ { - message: 'Expected indentation of 6 space characters but found 3.', - type: 'VariableDeclarator', + message: 'Expected indentation of 6 spaces but found 3.', + type: 'Identifier', }, { - message: 'Expected indentation of 6 space characters but found 4.', - type: 'VariableDeclarator', + message: 'Expected indentation of 6 spaces but found 4.', + type: 'Identifier', }, ], options: [ 3, { 'VariableDeclaratorOffset': { 'var': 1, 'let': 1, 'const': 3 }, 'SwitchCase': 1 } ],