├── .npmignore ├── .travis.yml ├── .github └── workflows │ └── add-to-project.yaml ├── index.js ├── LICENSE ├── package.json ├── README.md ├── rules ├── no-callback-literal.js ├── computed-property-even-spacing.js ├── array-bracket-even-spacing.js └── object-curly-even-spacing.js └── tests ├── no-callback-literal.js ├── computed-property-even-spacing.js ├── object-curly-even-spacing.js └── array-bracket-even-spacing.js /.npmignore: -------------------------------------------------------------------------------- 1 | .travis.yml 2 | tests/ 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - lts/* 4 | -------------------------------------------------------------------------------- /.github/workflows/add-to-project.yaml: -------------------------------------------------------------------------------- 1 | on: 2 | pull_request: 3 | types: [opened] 4 | issues: 5 | types: [opened] 6 | 7 | jobs: 8 | add-to-project: 9 | uses: standard/.github/.github/workflows/add-to-project.yaml@master 10 | secrets: inherit 11 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /*! eslint-plugin-standard. MIT License. Feross Aboukhadijeh */ 2 | 'use strict' 3 | 4 | module.exports = { 5 | rules: { 6 | 'array-bracket-even-spacing': require('./rules/array-bracket-even-spacing.js'), 7 | 'computed-property-even-spacing': require('./rules/computed-property-even-spacing.js'), 8 | 'object-curly-even-spacing': require('./rules/object-curly-even-spacing.js'), 9 | 'no-callback-literal': require('./rules/no-callback-literal.js') 10 | }, 11 | rulesConfig: { 12 | 'object-curly-even-spacing': 0, 13 | 'array-bracket-even-spacing': 0, 14 | 'computed-property-even-spacing': 0, 15 | 'no-callback-literal': 0 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Jamund Ferguson 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "eslint-plugin-standard", 3 | "description": "ESlint Plugin for the Standard Linter", 4 | "version": "5.0.0", 5 | "author": { 6 | "name": "Feross Aboukhadijeh", 7 | "email": "feross@feross.org", 8 | "url": "https://feross.org" 9 | }, 10 | "bugs": { 11 | "url": "https://github.com/standard/eslint-plugin-standard/issues" 12 | }, 13 | "dependencies": {}, 14 | "devDependencies": { 15 | "eslint": "^7.0.0", 16 | "mocha": "^6.2.0", 17 | "standard": "*" 18 | }, 19 | "homepage": "https://github.com/standard/eslint-plugin-standard#readme", 20 | "keywords": [ 21 | "eslint", 22 | "eslintplugin" 23 | ], 24 | "license": "MIT", 25 | "main": "index.js", 26 | "repository": { 27 | "type": "git", 28 | "url": "git+https://github.com/standard/eslint-plugin-standard.git" 29 | }, 30 | "scripts": { 31 | "test": "standard && mocha tests/" 32 | }, 33 | "peerDependencies": { 34 | "eslint": ">=5.0.0" 35 | }, 36 | "funding": [ 37 | { 38 | "type": "github", 39 | "url": "https://github.com/sponsors/feross" 40 | }, 41 | { 42 | "type": "patreon", 43 | "url": "https://www.patreon.com/feross" 44 | }, 45 | { 46 | "type": "consulting", 47 | "url": "https://feross.org/support" 48 | } 49 | ] 50 | } 51 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # eslint-plugin-standard [![travis][travis-image]][travis-url] [![npm][npm-image]][npm-url] [![downloads][downloads-image]][downloads-url] [![javascript style guide][standard-image]][standard-url] 2 | 3 | [travis-image]: https://img.shields.io/travis/standard/eslint-plugin-standard/master.svg 4 | [travis-url]: https://travis-ci.org/standard/eslint-plugin-standard 5 | [npm-image]: https://img.shields.io/npm/v/eslint-plugin-standard.svg 6 | [npm-url]: https://npmjs.org/package/eslint-plugin-standard 7 | [downloads-image]: https://img.shields.io/npm/dm/eslint-plugin-standard.svg 8 | [downloads-url]: https://npmjs.org/package/eslint-plugin-standard 9 | [standard-image]: https://img.shields.io/badge/code_style-standard-brightgreen.svg 10 | [standard-url]: https://standardjs.com 11 | 12 | ### Deprecated: This package isn't used by `standard` anymore, as of `standard` v16. See: https://github.com/standard/standard/issues/1316 13 | 14 | ESlint Rules for the Standard Linter 15 | 16 | ### Usage 17 | 18 | `npm install --save-dev eslint-plugin-standard` 19 | 20 | ### Configuration 21 | 22 | ```js 23 | module.exports = { 24 | rules: { 25 | 'standard/object-curly-even-spacing': [2, 'either'], 26 | 'standard/array-bracket-even-spacing': [2, 'either'], 27 | 'standard/computed-property-even-spacing': [2, 'even'], 28 | 'standard/no-callback-literal': [2, ['cb', 'callback']] 29 | } 30 | } 31 | ``` 32 | 33 | ### Rules Explanations 34 | 35 | There are several rules that were created specifically for the `standard` linter. 36 | 37 | - `object-curly-even-spacing` - Like `object-curly-spacing` from ESLint except it has an `either` option which lets you have 1 or 0 spaces padding. 38 | - `array-bracket-even-spacing` - Like `array-bracket-even-spacing` from ESLint except it has an `either` option which lets you have 1 or 0 spacing padding. 39 | - `computed-property-even-spacing` - Like `computed-property-spacing` around ESLint except is has an `even` option which lets you have 1 or 0 spacing padding. 40 | - `no-callback-literal` - Ensures that we strictly follow the callback pattern with `undefined`, `null` or an error object in the first position of a callback. 41 | -------------------------------------------------------------------------------- /rules/no-callback-literal.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Ensures that the callback pattern is followed properly 3 | * with an Error object (or undefined or null) in the first position. 4 | */ 5 | 6 | 'use strict' 7 | 8 | // ------------------------------------------------------------------------------ 9 | // Helpers 10 | // ------------------------------------------------------------------------------ 11 | 12 | /** 13 | * Determine if a node has a possiblity to be an Error object 14 | * @param {ASTNode} node ASTNode to check 15 | * @returns {boolean} True if there is a chance it contains an Error obj 16 | */ 17 | function couldBeError (node) { 18 | let exprs 19 | switch (node.type) { 20 | case 'Identifier': 21 | case 'CallExpression': 22 | case 'NewExpression': 23 | case 'MemberExpression': 24 | case 'TaggedTemplateExpression': 25 | case 'YieldExpression': 26 | return true // possibly an error object. 27 | 28 | case 'AssignmentExpression': 29 | return couldBeError(node.right) 30 | 31 | case 'SequenceExpression': 32 | exprs = node.expressions 33 | return exprs.length !== 0 && couldBeError(exprs[exprs.length - 1]) 34 | 35 | case 'LogicalExpression': 36 | return couldBeError(node.left) || couldBeError(node.right) 37 | 38 | case 'ConditionalExpression': 39 | return couldBeError(node.consequent) || couldBeError(node.alternate) 40 | 41 | default: 42 | return node.value === null 43 | } 44 | } 45 | 46 | // ------------------------------------------------------------------------------ 47 | // Rule Definition 48 | // ------------------------------------------------------------------------------ 49 | 50 | module.exports = { 51 | meta: { 52 | type: 'suggestion', 53 | docs: { 54 | url: 'https://github.com/standard/eslint-plugin-standard#rules-explanations' 55 | } 56 | }, 57 | 58 | create: function (context) { 59 | const callbackNames = context.options[0] || ['callback', 'cb'] 60 | 61 | function isCallback (name) { 62 | return callbackNames.indexOf(name) > -1 63 | } 64 | 65 | return { 66 | 67 | CallExpression: function (node) { 68 | const errorArg = node.arguments[0] 69 | const calleeName = node.callee.name 70 | 71 | if (errorArg && !couldBeError(errorArg) && isCallback(calleeName)) { 72 | context.report(node, 'Unexpected literal in error position of callback.') 73 | } 74 | } 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /tests/no-callback-literal.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @fileoverview Tests for the no-callback-literal rule 3 | * @author Jamund Ferguson 4 | * @copyright 2016 Jamund Ferguson. All rights reserved. 5 | */ 6 | 'use strict' 7 | 8 | // ------------------------------------------------------------------------------ 9 | // Requirements 10 | // ------------------------------------------------------------------------------ 11 | 12 | const RuleTester = require('eslint').RuleTester 13 | const rule = require('../rules/no-callback-literal') 14 | 15 | // ------------------------------------------------------------------------------ 16 | // Tests 17 | // ------------------------------------------------------------------------------ 18 | 19 | const ruleTester = new RuleTester() 20 | ruleTester.run('no-callback-literal', rule, { 21 | valid: [ 22 | 23 | // random stuff 24 | 'horse()', 25 | 'sort(null)', 26 | 'require("zyx")', 27 | 'require("zyx", data)', 28 | 29 | // callback() 30 | 'callback()', 31 | 'callback(undefined)', 32 | 'callback(null)', 33 | 'callback(x)', 34 | 'callback(new Error("error"))', 35 | 'callback(friendly, data)', 36 | 'callback(undefined, data)', 37 | 'callback(null, data)', 38 | 'callback(x, data)', 39 | 'callback(new Error("error"), data)', 40 | 41 | // cb() 42 | 'cb()', 43 | 'cb(undefined)', 44 | 'cb(null)', 45 | 'cb(undefined, "super")', 46 | 'cb(null, "super")', 47 | 48 | // custom callback 49 | { 50 | code: 'callback(44); cb("55"); power(new Error("super thing")); power(null);', 51 | options: [['power']] 52 | } 53 | ], 54 | 55 | invalid: [ 56 | // callback 57 | { code: 'callback(false, "snork")', errors: [{ message: 'Unexpected literal in error position of callback.' }] }, 58 | { code: 'callback("help")', errors: [{ message: 'Unexpected literal in error position of callback.' }] }, 59 | { code: 'callback("help", data)', errors: [{ message: 'Unexpected literal in error position of callback.' }] }, 60 | 61 | // cb 62 | { code: 'cb(false)', errors: [{ message: 'Unexpected literal in error position of callback.' }] }, 63 | { code: 'cb("help")', errors: [{ message: 'Unexpected literal in error position of callback.' }] }, 64 | { code: 'cb("help", data)', errors: [{ message: 'Unexpected literal in error position of callback.' }] }, 65 | 66 | // custom callback name 67 | { 68 | code: 'next(44)', 69 | options: [['next']], 70 | errors: [{ message: 'Unexpected literal in error position of callback.' }] 71 | } 72 | ] 73 | }) 74 | -------------------------------------------------------------------------------- /rules/computed-property-even-spacing.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | /** 4 | * @fileoverview Disallows or enforces spaces inside computed properties. 5 | * @author Jamund Ferguson 6 | * @copyright 2015 Jamund Ferguson. All rights reserved. 7 | */ 8 | // ------------------------------------------------------------------------------ 9 | // Rule Definition 10 | // ------------------------------------------------------------------------------ 11 | 12 | module.exports = { 13 | meta: { 14 | type: 'layout', 15 | docs: { 16 | url: 'https://github.com/standard/eslint-plugin-standard#rules-explanations' 17 | } 18 | }, 19 | 20 | create: function (context) { 21 | const propertyNameMustBeSpaced = context.options[0] === 'always' // default is "never" 22 | const propertyNameMustBeEven = context.options[0] === 'even' // default is "never" 23 | 24 | // -------------------------------------------------------------------------- 25 | // Helpers 26 | // -------------------------------------------------------------------------- 27 | 28 | /** 29 | * Determines whether two adjacent tokens are have whitespace between them. 30 | * @param {Object} left - The left token object. 31 | * @param {Object} right - The right token object. 32 | * @returns {boolean} Whether or not there is space between the tokens. 33 | */ 34 | function isSpaced (left, right) { 35 | return left.range[1] < right.range[0] 36 | } 37 | 38 | /** 39 | * Determines whether two adjacent tokens are on the same line. 40 | * @param {Object} left - The left token object. 41 | * @param {Object} right - The right token object. 42 | * @returns {boolean} Whether or not the tokens are on the same line. 43 | */ 44 | function isSameLine (left, right) { 45 | return left.loc.start.line === right.loc.start.line 46 | } 47 | 48 | /** 49 | * Reports that there shouldn't be a space after the first token 50 | * @param {ASTNode} node - The node to report in the event of an error. 51 | * @param {Token} token - The token to use for the report. 52 | * @returns {void} 53 | */ 54 | function reportNoBeginningSpace (node, token) { 55 | context.report(node, token.loc.start, 56 | "There should be no space after '" + token.value + "'") 57 | } 58 | 59 | /** 60 | * Reports that there shouldn't be a space before the last token 61 | * @param {ASTNode} node - The node to report in the event of an error. 62 | * @param {Token} token - The token to use for the report. 63 | * @returns {void} 64 | */ 65 | function reportNoEndingSpace (node, token) { 66 | context.report(node, token.loc.start, 67 | "There should be no space before '" + token.value + "'") 68 | } 69 | 70 | /** 71 | * Reports that there should be a space after the first token 72 | * @param {ASTNode} node - The node to report in the event of an error. 73 | * @param {Token} token - The token to use for the report. 74 | * @returns {void} 75 | */ 76 | function reportRequiredBeginningSpace (node, token) { 77 | context.report(node, token.loc.start, 78 | "A space is required after '" + token.value + "'") 79 | } 80 | 81 | /** 82 | * Reports that there should be a space before the last token 83 | * @param {ASTNode} node - The node to report in the event of an error. 84 | * @param {Token} token - The token to use for the report. 85 | * @returns {void} 86 | */ 87 | function reportRequiredEndingSpace (node, token) { 88 | context.report(node, token.loc.start, 89 | "A space is required before '" + token.value + "'") 90 | } 91 | 92 | /** 93 | * Returns a function that checks the spacing of a node on the property name 94 | * that was passed in. 95 | * @param {String} propertyName The property on the node to check for spacing 96 | * @returns {Function} A function that will check spacing on a node 97 | */ 98 | function checkSpacing (propertyName) { 99 | return function (node) { 100 | if (!node.computed) { 101 | return 102 | } 103 | 104 | const property = node[propertyName] 105 | 106 | const before = context.getTokenBefore(property) 107 | const first = context.getFirstToken(property) 108 | const last = context.getLastToken(property) 109 | const after = context.getTokenAfter(property) 110 | let startSpace, endSpace 111 | 112 | if (propertyNameMustBeEven) { 113 | if (!isSameLine(before, after)) { 114 | context.report(node, 'Expected "[" and "]" to be on the same line') 115 | return 116 | } 117 | startSpace = first.loc.start.column - before.loc.end.column 118 | endSpace = after.loc.start.column - last.loc.end.column 119 | 120 | if (startSpace !== endSpace || startSpace > 1) { 121 | context.report(node, 'Expected 1 or 0 spaces around "[" and "]"') 122 | } 123 | 124 | return 125 | } 126 | 127 | if (isSameLine(before, first)) { 128 | if (propertyNameMustBeSpaced) { 129 | if (!isSpaced(before, first) && isSameLine(before, first)) { 130 | reportRequiredBeginningSpace(node, before) 131 | } 132 | } else { 133 | if (isSpaced(before, first)) { 134 | reportNoBeginningSpace(node, before) 135 | } 136 | } 137 | } 138 | 139 | if (isSameLine(last, after)) { 140 | if (propertyNameMustBeSpaced) { 141 | if (!isSpaced(last, after) && isSameLine(last, after)) { 142 | reportRequiredEndingSpace(node, after) 143 | } 144 | } else { 145 | if (isSpaced(last, after)) { 146 | reportNoEndingSpace(node, after) 147 | } 148 | } 149 | } 150 | } 151 | } 152 | 153 | // -------------------------------------------------------------------------- 154 | // Public 155 | // -------------------------------------------------------------------------- 156 | 157 | return { 158 | Property: checkSpacing('key'), 159 | MemberExpression: checkSpacing('property') 160 | } 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /rules/array-bracket-even-spacing.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | /** 4 | * @fileoverview Disallows or enforces spaces inside of array brackets. 5 | * @author Jamund Ferguson 6 | * @copyright 2015 Jamund Ferguson. All rights reserved. 7 | * @copyright 2014 Brandyn Bennett. All rights reserved. 8 | * @copyright 2014 Michael Ficarra. No rights reserved. 9 | * @copyright 2014 Vignesh Anand. All rights reserved. 10 | */ 11 | // ------------------------------------------------------------------------------ 12 | // Rule Definition 13 | // ------------------------------------------------------------------------------ 14 | 15 | module.exports = { 16 | meta: { 17 | type: 'layout', 18 | docs: { 19 | url: 'https://github.com/standard/eslint-plugin-standard#rules-explanations' 20 | } 21 | }, 22 | 23 | create: function (context) { 24 | const spaced = context.options[0] === 'always' 25 | const either = context.options[0] === 'either' 26 | 27 | /** 28 | * Determines whether an option is set, relative to the spacing option. 29 | * If spaced is "always", then check whether option is set to false. 30 | * If spaced is "never", then check whether option is set to true. 31 | * @param {Object} option - The option to exclude. 32 | * @returns {boolean} Whether or not the property is excluded. 33 | */ 34 | function isOptionSet (option) { 35 | return context.options[1] != null ? context.options[1][option] === !spaced : false 36 | } 37 | 38 | const options = { 39 | either, 40 | spaced, 41 | singleElementException: isOptionSet('singleValue'), 42 | objectsInArraysException: isOptionSet('objectsInArrays'), 43 | arraysInArraysException: isOptionSet('arraysInArrays') 44 | } 45 | 46 | // -------------------------------------------------------------------------- 47 | // Helpers 48 | // -------------------------------------------------------------------------- 49 | 50 | /** 51 | * Determines whether two adjacent tokens are have whitespace between them. 52 | * @param {Object} left - The left token object. 53 | * @param {Object} right - The right token object. 54 | * @returns {boolean} Whether or not there is space between the tokens. 55 | */ 56 | function isSpaced (left, right) { 57 | return left.range[1] < right.range[0] 58 | } 59 | 60 | /** 61 | * Determines whether two adjacent tokens are on the same line. 62 | * @param {Object} left - The left token object. 63 | * @param {Object} right - The right token object. 64 | * @returns {boolean} Whether or not the tokens are on the same line. 65 | */ 66 | function isSameLine (left, right) { 67 | return left.loc.start.line === right.loc.start.line 68 | } 69 | 70 | /** 71 | * Reports that there shouldn't be a space after the first token 72 | * @param {ASTNode} node - The node to report in the event of an error. 73 | * @param {Token} token - The token to use for the report. 74 | * @returns {void} 75 | */ 76 | function reportNoBeginningSpace (node, token) { 77 | context.report(node, token.loc.start, 78 | "There should be no space after '" + token.value + "'") 79 | } 80 | 81 | /** 82 | * Reports that there shouldn't be a space before the last token 83 | * @param {ASTNode} node - The node to report in the event of an error. 84 | * @param {Token} token - The token to use for the report. 85 | * @returns {void} 86 | */ 87 | function reportNoEndingSpace (node, token) { 88 | context.report(node, token.loc.start, 89 | "There should be no space before '" + token.value + "'") 90 | } 91 | 92 | /** 93 | * Reports that there should be a space after the first token 94 | * @param {ASTNode} node - The node to report in the event of an error. 95 | * @param {Token} token - The token to use for the report. 96 | * @returns {void} 97 | */ 98 | function reportRequiredBeginningSpace (node, token) { 99 | context.report(node, token.loc.start, 100 | "A space is required after '" + token.value + "'") 101 | } 102 | 103 | /** 104 | * Reports that there should be a space before the last token 105 | * @param {ASTNode} node - The node to report in the event of an error. 106 | * @param {Token} token - The token to use for the report. 107 | * @returns {void} 108 | */ 109 | function reportRequiredEndingSpace (node, token) { 110 | context.report(node, token.loc.start, 111 | "A space is required before '" + token.value + "'") 112 | } 113 | 114 | /** 115 | * Checks if a start and end brace in a node are spaced evenly 116 | * and not too long (>1 space) 117 | * @param node 118 | * @param start 119 | * @param end 120 | * @returns {boolean} 121 | */ 122 | function isEvenlySpacedAndNotTooLong (node, start, end) { 123 | const expectedSpace = start[1].range[0] - start[0].range[1] 124 | const endSpace = end[1].range[0] - end[0].range[1] 125 | return endSpace === expectedSpace && endSpace <= 1 126 | } 127 | 128 | /** 129 | * Validates the spacing around array brackets 130 | * @param {ASTNode} node - The node we're checking for spacing 131 | * @returns {void} 132 | */ 133 | function validateArraySpacing (node) { 134 | if (node.elements.length === 0) { 135 | return 136 | } 137 | 138 | const first = context.getFirstToken(node) 139 | const second = context.getFirstToken(node, 1) 140 | const penultimate = context.getLastToken(node, 1) 141 | const last = context.getLastToken(node) 142 | 143 | const openingBracketMustBeSpaced = 144 | (options.objectsInArraysException && second.value === '{') || 145 | (options.arraysInArraysException && second.value === '[') || 146 | (options.singleElementException && node.elements.length === 1) 147 | ? !options.spaced 148 | : options.spaced 149 | 150 | const closingBracketMustBeSpaced = 151 | (options.objectsInArraysException && penultimate.value === '}') || 152 | (options.arraysInArraysException && penultimate.value === ']') || 153 | (options.singleElementException && node.elements.length === 1) 154 | ? !options.spaced 155 | : options.spaced 156 | 157 | // we only care about evenly spaced things 158 | if (options.either) { 159 | // newlines at any point means return 160 | if (!isSameLine(first, last)) { 161 | return 162 | } 163 | 164 | // confirm that the object expression/literal is spaced evenly 165 | if (!isEvenlySpacedAndNotTooLong(node, [first, second], [penultimate, last])) { 166 | context.report(node, 'Expected consistent spacing') 167 | } 168 | 169 | return 170 | } 171 | 172 | if (isSameLine(first, second)) { 173 | if (openingBracketMustBeSpaced && !isSpaced(first, second)) { 174 | reportRequiredBeginningSpace(node, first) 175 | } 176 | if (!openingBracketMustBeSpaced && isSpaced(first, second)) { 177 | reportNoBeginningSpace(node, first) 178 | } 179 | } 180 | 181 | if (isSameLine(penultimate, last)) { 182 | if (closingBracketMustBeSpaced && !isSpaced(penultimate, last)) { 183 | reportRequiredEndingSpace(node, last) 184 | } 185 | if (!closingBracketMustBeSpaced && isSpaced(penultimate, last)) { 186 | reportNoEndingSpace(node, last) 187 | } 188 | } 189 | } 190 | 191 | // -------------------------------------------------------------------------- 192 | // Public 193 | // -------------------------------------------------------------------------- 194 | 195 | return { 196 | ArrayPattern: validateArraySpacing, 197 | ArrayExpression: validateArraySpacing 198 | } 199 | } 200 | } 201 | -------------------------------------------------------------------------------- /rules/object-curly-even-spacing.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | /** 4 | * @fileoverview Disallows or enforces spaces inside of object literals. 5 | * @author Jamund Ferguson 6 | * @copyright 2014 Brandyn Bennett. All rights reserved. 7 | * @copyright 2014 Michael Ficarra. No rights reserved. 8 | * @copyright 2014 Vignesh Anand. All rights reserved. 9 | * @copyright 2015 Jamund Ferguson. All rights reserved. 10 | */ 11 | // ------------------------------------------------------------------------------ 12 | // Rule Definition 13 | // ------------------------------------------------------------------------------ 14 | 15 | module.exports = { 16 | meta: { 17 | type: 'layout', 18 | docs: { 19 | url: 'https://github.com/standard/eslint-plugin-standard#rules-explanations' 20 | } 21 | }, 22 | 23 | create: function (context) { 24 | const spaced = context.options[0] === 'always' 25 | const either = context.options[0] === 'either' 26 | 27 | /** 28 | * Determines whether an option is set, relative to the spacing option. 29 | * If spaced is "always", then check whether option is set to false. 30 | * If spaced is "never", then check whether option is set to true. 31 | * @param {Object} option - The option to exclude. 32 | * @returns {boolean} Whether or not the property is excluded. 33 | */ 34 | function isOptionSet (option) { 35 | return context.options[1] != null ? context.options[1][option] === !spaced : false 36 | } 37 | 38 | const options = { 39 | spaced, 40 | either, 41 | arraysInObjectsException: isOptionSet('arraysInObjects'), 42 | objectsInObjectsException: isOptionSet('objectsInObjects') 43 | } 44 | 45 | // -------------------------------------------------------------------------- 46 | // Helpers 47 | // -------------------------------------------------------------------------- 48 | 49 | /** 50 | * Determines whether two adjacent tokens are have whitespace between them. 51 | * @param {Object} left - The left token object. 52 | * @param {Object} right - The right token object. 53 | * @returns {boolean} Whether or not there is space between the tokens. 54 | */ 55 | function isSpaced (left, right) { 56 | return left.range[1] < right.range[0] 57 | } 58 | 59 | /** 60 | * Determines whether two adjacent tokens are on the same line. 61 | * @param {Object} left - The left token object. 62 | * @param {Object} right - The right token object. 63 | * @returns {boolean} Whether or not the tokens are on the same line. 64 | */ 65 | function isSameLine (left, right) { 66 | return left.loc.start.line === right.loc.start.line 67 | } 68 | 69 | /** 70 | * Reports that there shouldn't be a space after the first token 71 | * @param {ASTNode} node - The node to report in the event of an error. 72 | * @param {Token} token - The token to use for the report. 73 | * @returns {void} 74 | */ 75 | function reportNoBeginningSpace (node, token) { 76 | context.report(node, token.loc.start, 77 | "There should be no space after '" + token.value + "'") 78 | } 79 | 80 | /** 81 | * Reports that there shouldn't be a space before the last token 82 | * @param {ASTNode} node - The node to report in the event of an error. 83 | * @param {Token} token - The token to use for the report. 84 | * @returns {void} 85 | */ 86 | function reportNoEndingSpace (node, token) { 87 | context.report(node, token.loc.start, 88 | "There should be no space before '" + token.value + "'") 89 | } 90 | 91 | /** 92 | * Reports that there should be a space after the first token 93 | * @param {ASTNode} node - The node to report in the event of an error. 94 | * @param {Token} token - The token to use for the report. 95 | * @returns {void} 96 | */ 97 | function reportRequiredBeginningSpace (node, token) { 98 | context.report(node, token.loc.start, 99 | "A space is required after '" + token.value + "'") 100 | } 101 | 102 | /** 103 | * Reports that there should be a space before the last token 104 | * @param {ASTNode} node - The node to report in the event of an error. 105 | * @param {Token} token - The token to use for the report. 106 | * @returns {void} 107 | */ 108 | function reportRequiredEndingSpace (node, token) { 109 | context.report(node, token.loc.start, 110 | "A space is required before '" + token.value + "'") 111 | } 112 | 113 | /** 114 | * Checks if a start and end brace in a node are spaced evenly 115 | * and not too long (>1 space) 116 | * @param node 117 | * @param start 118 | * @param end 119 | * @returns {boolean} 120 | */ 121 | function isEvenlySpacedAndNotTooLong (node, start, end) { 122 | const expectedSpace = start[1].range[0] - start[0].range[1] 123 | const endSpace = end[1].range[0] - end[0].range[1] 124 | return endSpace === expectedSpace && endSpace <= 1 125 | } 126 | 127 | /** 128 | * Determines if spacing in curly braces is valid. 129 | * @param {ASTNode} node The AST node to check. 130 | * @param {Token} first The first token to check (should be the opening brace) 131 | * @param {Token} second The second token to check (should be first after the opening brace) 132 | * @param {Token} penultimate The penultimate token to check (should be last before closing brace) 133 | * @param {Token} last The last token to check (should be closing brace) 134 | * @returns {void} 135 | */ 136 | function validateBraceSpacing (node, first, second, penultimate, last) { 137 | const closingCurlyBraceMustBeSpaced = 138 | (options.arraysInObjectsException && penultimate.value === ']') || 139 | (options.objectsInObjectsException && penultimate.value === '}') 140 | ? !options.spaced 141 | : options.spaced 142 | 143 | // we only care about evenly spaced things 144 | if (options.either) { 145 | // newlines at any point means return 146 | if (!isSameLine(first, last)) { 147 | return 148 | } 149 | 150 | // confirm that the object expression/literal is spaced evenly 151 | if (!isEvenlySpacedAndNotTooLong(node, [first, second], [penultimate, last])) { 152 | context.report(node, 'Expected consistent spacing') 153 | } 154 | 155 | return 156 | } 157 | 158 | // { and key are on same line 159 | if (isSameLine(first, second)) { 160 | if (options.spaced && !isSpaced(first, second)) { 161 | reportRequiredBeginningSpace(node, first) 162 | } 163 | if (!options.spaced && isSpaced(first, second)) { 164 | reportNoBeginningSpace(node, first) 165 | } 166 | } 167 | 168 | // final key and } ore on the same line 169 | if (isSameLine(penultimate, last)) { 170 | if (closingCurlyBraceMustBeSpaced && !isSpaced(penultimate, last)) { 171 | reportRequiredEndingSpace(node, last) 172 | } 173 | if (!closingCurlyBraceMustBeSpaced && isSpaced(penultimate, last)) { 174 | reportNoEndingSpace(node, last) 175 | } 176 | } 177 | } 178 | 179 | // -------------------------------------------------------------------------- 180 | // Public 181 | // -------------------------------------------------------------------------- 182 | 183 | return { 184 | // var {x} = y 185 | ObjectPattern: function (node) { 186 | if (node.properties.length === 0) { 187 | return 188 | } 189 | 190 | const firstSpecifier = node.properties[0] 191 | const lastSpecifier = node.properties[node.properties.length - 1] 192 | 193 | const first = context.getTokenBefore(firstSpecifier) 194 | const second = context.getFirstToken(firstSpecifier) 195 | let penultimate = context.getLastToken(lastSpecifier) 196 | let last = context.getTokenAfter(lastSpecifier) 197 | 198 | // support trailing commas 199 | if (last.value === ',') { 200 | penultimate = last 201 | last = context.getTokenAfter(last) 202 | } 203 | 204 | validateBraceSpacing(node, first, second, penultimate, last) 205 | }, 206 | 207 | // import {y} from 'x' 208 | ImportDeclaration: function (node) { 209 | const firstSpecifier = node.specifiers[0] 210 | const lastSpecifier = node.specifiers[node.specifiers.length - 1] 211 | 212 | // don't do anything for namespace or default imports 213 | if (firstSpecifier && lastSpecifier && firstSpecifier.type === 'ImportSpecifier' && lastSpecifier.type === 'ImportSpecifier') { 214 | const first = context.getTokenBefore(firstSpecifier) 215 | const second = context.getFirstToken(firstSpecifier) 216 | const penultimate = context.getLastToken(lastSpecifier) 217 | const last = context.getTokenAfter(lastSpecifier) 218 | 219 | validateBraceSpacing(node, first, second, penultimate, last) 220 | } 221 | }, 222 | 223 | // export {name} from 'yo' 224 | ExportNamedDeclaration: function (node) { 225 | if (!node.specifiers.length) { 226 | return 227 | } 228 | 229 | const firstSpecifier = node.specifiers[0] 230 | const lastSpecifier = node.specifiers[node.specifiers.length - 1] 231 | const first = context.getTokenBefore(firstSpecifier) 232 | const second = context.getFirstToken(firstSpecifier) 233 | const penultimate = context.getLastToken(lastSpecifier) 234 | const last = context.getTokenAfter(lastSpecifier) 235 | 236 | validateBraceSpacing(node, first, second, penultimate, last) 237 | }, 238 | 239 | // var y = {x: 'y'} 240 | ObjectExpression: function (node) { 241 | if (node.properties.length === 0) { 242 | return 243 | } 244 | 245 | const first = context.getFirstToken(node) 246 | const second = context.getFirstToken(node, 1) 247 | const penultimate = context.getLastToken(node, 1) 248 | const last = context.getLastToken(node) 249 | 250 | validateBraceSpacing(node, first, second, penultimate, last) 251 | } 252 | } 253 | } 254 | } 255 | -------------------------------------------------------------------------------- /tests/computed-property-even-spacing.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @fileoverview Disallows or enforces spaces inside computed properties. 3 | * @author Jamund Ferguson 4 | * @copyright 2015 Jamund Ferguson. All rights reserved. 5 | */ 6 | 'use strict' 7 | 8 | // ------------------------------------------------------------------------------ 9 | // Requirements 10 | // ------------------------------------------------------------------------------ 11 | 12 | const RuleTester = require('eslint').RuleTester 13 | const rule = require('../rules/computed-property-even-spacing') 14 | 15 | const parserOptions = { ecmaVersion: 2018, sourceType: 'module' } 16 | 17 | // ------------------------------------------------------------------------------ 18 | // Tests 19 | // ------------------------------------------------------------------------------ 20 | 21 | const ruleTester = new RuleTester() 22 | ruleTester.run('computed-property-even-spacing', rule, { 23 | valid: [ 24 | 25 | // even 26 | { code: 'bar[ foo ]', options: ['even'] }, 27 | { code: 'bar[foo]', options: ['even'] }, 28 | { code: "bar['foo']", options: ['even'] }, 29 | { code: "bar[ 'foo' ]", options: ['even'] }, 30 | 31 | // default - never 32 | { code: 'obj[foo]' }, 33 | { code: "obj['foo']" }, 34 | { code: 'var x = {[b]: a}', parserOptions }, 35 | 36 | // always 37 | { code: 'obj[ foo ]', options: ['always'] }, 38 | { code: 'obj[\nfoo\n]', options: ['always'] }, 39 | { code: "obj[ 'foo' ]", options: ['always'] }, 40 | { code: "obj[ 'foo' + 'bar' ]", options: ['always'] }, 41 | { code: 'obj[ obj2[ foo ] ]', options: ['always'] }, 42 | { code: 'obj.map(function(item) { return [\n1,\n2,\n3,\n4\n]; })', options: ['always'] }, 43 | { code: "obj[ 'map' ](function(item) { return [\n1,\n2,\n3,\n4\n]; })", options: ['always'] }, 44 | { code: "obj[ 'for' + 'Each' ](function(item) { return [\n1,\n2,\n3,\n4\n]; })", options: ['always'] }, 45 | { code: 'obj[ obj2[ foo ] ]', options: ['always'] }, 46 | { code: 'var foo = obj[ 1 ]', options: ['always'] }, 47 | { code: "var foo = obj[ 'foo' ];", options: ['always'] }, 48 | { code: 'var foo = obj[ [1, 1] ];', options: ['always'] }, 49 | 50 | // always - objectLiteralComputedProperties 51 | { code: 'var x = {[ "a" ]: a}', options: ['always'], parserOptions }, 52 | { code: 'var y = {[ x ]: a}', options: ['always'], parserOptions }, 53 | { code: 'var x = {[ "a" ]() {}}', options: ['always'], parserOptions }, 54 | { code: 'var y = {[ x ]() {}}', options: ['always'], parserOptions }, 55 | 56 | // always - unrelated cases 57 | { code: 'var foo = {};', options: ['always'] }, 58 | { code: 'var foo = [];', options: ['always'] }, 59 | 60 | // never 61 | { code: 'obj[foo]', options: ['never'] }, 62 | { code: "obj['foo']", options: ['never'] }, 63 | { code: "obj['foo' + 'bar']", options: ['never'] }, 64 | { code: "obj['foo'+'bar']", options: ['never'] }, 65 | { code: 'obj[obj2[foo]]', options: ['never'] }, 66 | { code: 'obj.map(function(item) { return [\n1,\n2,\n3,\n4\n]; })', options: ['never'] }, 67 | { code: "obj['map'](function(item) { return [\n1,\n2,\n3,\n4\n]; })", options: ['never'] }, 68 | { code: "obj['for' + 'Each'](function(item) { return [\n1,\n2,\n3,\n4\n]; })", options: ['never'] }, 69 | { code: "obj['for' + 'Each'](function(item) { return [\n1,\n2,\n3,\n4\n]; })", options: ['never'] }, 70 | { code: 'obj[\nfoo]', options: ['never'] }, 71 | { code: 'obj[foo\n]', options: ['never'] }, 72 | { code: 'var foo = obj[1]', options: ['never'] }, 73 | { code: "var foo = obj['foo'];", options: ['never'] }, 74 | { code: 'var foo = obj[[ 1, 1 ]];', options: ['never'] }, 75 | 76 | // never - objectLiteralComputedProperties 77 | { code: 'var x = {["a"]: a}', options: ['never'], parserOptions }, 78 | { code: 'var y = {[x]: a}', options: ['never'], parserOptions }, 79 | { code: 'var x = {["a"]() {}}', options: ['never'], parserOptions }, 80 | { code: 'var y = {[x]() {}}', options: ['never'], parserOptions }, 81 | 82 | // never - unrelated cases 83 | { code: 'var foo = {};', options: ['never'] }, 84 | { code: 'var foo = [];', options: ['never'] }, 85 | { code: 'bar[ foo ]', options: ['even'] }, 86 | 87 | // even - unrelated cases 88 | { code: 'const { a, ...b } = obj', options: ['even'], parserOptions }, 89 | { code: 'func(a, { ...b })', options: ['even'], parserOptions } 90 | 91 | ], 92 | 93 | invalid: [ 94 | 95 | // even 96 | { code: "bar[ 'foo' ]", options: ['even'], errors: [{ message: 'Expected 1 or 0 spaces around "[" and "]"' }] }, 97 | { code: "bar['foo' ]", options: ['even'], errors: [{ message: 'Expected 1 or 0 spaces around "[" and "]"' }] }, 98 | { code: "bar[ 'foo' ]", options: ['even'], errors: [{ message: 'Expected 1 or 0 spaces around "[" and "]"' }] }, 99 | { code: "bar[ 'foo']", options: ['even'], errors: [{ message: 'Expected 1 or 0 spaces around "[" and "]"' }] }, 100 | { code: "bar[\n'foo' ]", options: ['even'], errors: [{ message: 'Expected "[" and "]" to be on the same line' }] }, 101 | { code: "bar[\n'foo' ]", options: ['even'], errors: [{ message: 'Expected "[" and "]" to be on the same line' }] }, 102 | { code: "bar[\n'foo' ]", options: ['even'], errors: [{ message: 'Expected "[" and "]" to be on the same line' }] }, 103 | { code: "bar[\n\t'foo' ]", options: ['even'], errors: [{ message: 'Expected "[" and "]" to be on the same line' }] }, 104 | { code: "bar[\n\t'foo'\n]", options: ['even'], errors: [{ message: 'Expected "[" and "]" to be on the same line' }] }, 105 | 106 | { 107 | code: 'var foo = obj[ 1];', 108 | options: ['always'], 109 | errors: [ 110 | { 111 | message: "A space is required before ']'", 112 | type: 'MemberExpression', 113 | line: 1 114 | } 115 | ] 116 | }, 117 | { 118 | code: 'var foo = obj[1 ];', 119 | options: ['always'], 120 | errors: [ 121 | { 122 | message: "A space is required after '['", 123 | type: 'MemberExpression', 124 | line: 1 125 | } 126 | ] 127 | }, 128 | { 129 | code: 'var foo = obj[ 1];', 130 | options: ['never'], 131 | errors: [ 132 | { 133 | message: "There should be no space after '['", 134 | type: 'MemberExpression', 135 | line: 1 136 | } 137 | ] 138 | }, 139 | { 140 | code: 'var foo = obj[1 ];', 141 | options: ['never'], 142 | errors: [ 143 | { 144 | message: "There should be no space before ']'", 145 | type: 'MemberExpression' 146 | } 147 | ] 148 | }, 149 | { 150 | code: 'var foo = obj[ 1];', 151 | options: ['always'], 152 | errors: [ 153 | { 154 | message: "A space is required before ']'", 155 | type: 'MemberExpression', 156 | line: 1 157 | } 158 | ] 159 | }, 160 | { 161 | code: 'var foo = obj[1 ];', 162 | options: ['always'], 163 | errors: [ 164 | { 165 | message: "A space is required after '['", 166 | type: 'MemberExpression', 167 | line: 1 168 | } 169 | ] 170 | }, 171 | { 172 | code: 'obj[ foo ]', 173 | options: ['never'], 174 | errors: [ 175 | { 176 | message: "There should be no space after '['", 177 | type: 'MemberExpression', 178 | line: 1 179 | }, 180 | { 181 | message: "There should be no space before ']'", 182 | type: 'MemberExpression', 183 | line: 1 184 | } 185 | ] 186 | }, 187 | { 188 | code: 'obj[foo ]', 189 | options: ['never'], 190 | errors: [ 191 | { 192 | message: "There should be no space before ']'", 193 | type: 'MemberExpression', 194 | line: 1 195 | } 196 | ] 197 | }, 198 | { 199 | code: 'obj[ foo]', 200 | options: ['never'], 201 | errors: [ 202 | { 203 | message: "There should be no space after '['", 204 | type: 'MemberExpression', 205 | line: 1 206 | } 207 | ] 208 | }, 209 | { 210 | code: 'var foo = obj[1]', 211 | options: ['always'], 212 | errors: [ 213 | { 214 | message: "A space is required after '['", 215 | type: 'MemberExpression', 216 | line: 1 217 | }, 218 | { 219 | message: "A space is required before ']'", 220 | type: 'MemberExpression', 221 | line: 1 222 | } 223 | ] 224 | }, 225 | 226 | // always - objectLiteralComputedProperties 227 | { 228 | code: 'var x = {[a]: b}', 229 | options: ['always'], 230 | parserOptions, 231 | errors: [ 232 | { 233 | message: "A space is required after '['", 234 | type: 'Property', 235 | line: 1 236 | }, 237 | { 238 | message: "A space is required before ']'", 239 | type: 'Property', 240 | line: 1 241 | } 242 | ] 243 | }, 244 | { 245 | code: 'var x = {[a ]: b}', 246 | options: ['always'], 247 | parserOptions, 248 | errors: [ 249 | { 250 | message: "A space is required after '['", 251 | type: 'Property', 252 | line: 1 253 | } 254 | ] 255 | }, 256 | { 257 | code: 'var x = {[ a]: b}', 258 | options: ['always'], 259 | parserOptions, 260 | errors: [ 261 | { 262 | message: "A space is required before ']'", 263 | type: 'Property', 264 | line: 1 265 | } 266 | ] 267 | }, 268 | 269 | // never - objectLiteralComputedProperties 270 | { 271 | code: 'var x = {[ a ]: b}', 272 | options: ['never'], 273 | parserOptions, 274 | errors: [ 275 | { 276 | message: "There should be no space after '['", 277 | type: 'Property', 278 | line: 1 279 | }, 280 | { 281 | message: "There should be no space before ']'", 282 | type: 'Property', 283 | line: 1 284 | } 285 | ] 286 | }, 287 | { 288 | code: 'var x = {[a ]: b}', 289 | options: ['never'], 290 | parserOptions, 291 | errors: [ 292 | { 293 | message: "There should be no space before ']'", 294 | type: 'Property', 295 | line: 1 296 | } 297 | ] 298 | }, 299 | { 300 | code: 'var x = {[ a]: b}', 301 | options: ['never'], 302 | parserOptions, 303 | errors: [ 304 | { 305 | message: "There should be no space after '['", 306 | type: 'Property', 307 | line: 1 308 | } 309 | ] 310 | }, 311 | { 312 | code: 'var x = {[ a\n]: b}', 313 | options: ['never'], 314 | parserOptions, 315 | errors: [ 316 | { 317 | message: "There should be no space after '['", 318 | type: 'Property', 319 | line: 1 320 | } 321 | ] 322 | } 323 | 324 | ] 325 | }) 326 | -------------------------------------------------------------------------------- /tests/object-curly-even-spacing.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @fileoverview Disallows or enforces spaces inside of object literals. 3 | * @author Jamund Ferguson 4 | * @copyright 2014 Vignesh Anand. All rights reserved. 5 | * @copyright 2015 Jamund Ferguson. All rights reserved. 6 | */ 7 | 'use strict' 8 | 9 | // ------------------------------------------------------------------------------ 10 | // Requirements 11 | // ------------------------------------------------------------------------------ 12 | 13 | const RuleTester = require('eslint').RuleTester 14 | const rule = require('../rules/object-curly-even-spacing') 15 | const parserOptions = { ecmaVersion: 2018, sourceType: 'module' } 16 | 17 | // ------------------------------------------------------------------------------ 18 | // Tests 19 | // ------------------------------------------------------------------------------ 20 | 21 | const ruleTester = new RuleTester() 22 | ruleTester.run('object-curly-even-spacing', rule, { 23 | valid: [ 24 | 25 | // either 26 | { code: "var x = { a: 'b' }", options: ['either'] }, 27 | { code: "var x = {\na: 'b'\n}", options: ['either'] }, 28 | { code: "var x = {\n\ta: 'b'\n}", options: ['either'] }, 29 | { code: "var x = {\n a: 'b' \n}", options: ['either'] }, 30 | { code: 'var foo = {};', options: ['either'] }, 31 | { code: 'var {x} = y', options: ['either'], parserOptions }, 32 | { code: 'var {} = y', options: ['either'], parserOptions }, 33 | { code: 'var { x } = y', options: ['either'], parserOptions }, 34 | { code: 'var {\nx\n} = y', options: ['either'], parserOptions }, 35 | { code: 'var {\n\tx\n} = y', options: ['either'], parserOptions }, 36 | { code: "import {x} from 'y'", options: ['either'], parserOptions }, 37 | 38 | // always - object literals 39 | { code: 'var obj = { foo: bar, baz: qux };', options: ['always'] }, 40 | { code: 'var obj = { foo: { bar: quxx }, baz: qux };', options: ['always'] }, 41 | { code: 'var obj = {\nfoo: bar,\nbaz: qux\n};', options: ['always'] }, 42 | 43 | // always - destructuring 44 | { code: 'var { x } = y', options: ['always'], parserOptions }, 45 | { code: 'var { x, y } = y', options: ['always'], parserOptions }, 46 | { code: 'var { x,y } = y', options: ['always'], parserOptions }, 47 | { code: 'var {\nx,y } = y', options: ['always'], parserOptions }, 48 | { code: 'var {\nx,y\n} = z', options: ['always'], parserOptions }, 49 | { code: 'var { x = 10, y } = y', options: ['always'], parserOptions }, 50 | { code: 'var { x: { z }, y } = y', options: ['always'], parserOptions }, 51 | { code: 'var {\ny,\n} = x', options: ['always'], parserOptions }, 52 | { code: 'var { y, } = x', options: ['always'], parserOptions }, 53 | { code: 'var {} = x', options: ['always'], parserOptions }, 54 | 55 | // always - import / export 56 | { code: "import { door } from 'room'", options: ['always'], parserOptions }, 57 | { code: "import {\ndoor } from 'room'", options: ['always'], parserOptions }, 58 | { code: "export { door } from 'room'", options: ['always'], parserOptions }, 59 | { code: "import { house, mouse } from 'caravan'", options: ['always'], parserOptions }, 60 | // { code: 'export { door }', options: ['always'], parserOptions: parserOptions }, 61 | { code: "import {} from 'room'", options: ['always'], parserOptions }, 62 | { code: "export {} from 'room'", options: ['always'], parserOptions }, 63 | { code: "import 'room'", options: ['always'], parserOptions }, 64 | 65 | // always - empty object 66 | { code: 'var foo = {};', options: ['always'] }, 67 | 68 | // always - objectsInObjects 69 | { code: "var obj = { 'foo': { 'bar': 1, 'baz': 2 }};", options: ['always', { objectsInObjects: false }] }, 70 | 71 | // always - arraysInObjects 72 | { code: "var obj = { 'foo': [ 1, 2 ]};", options: ['always', { arraysInObjects: false }] }, 73 | 74 | // always - arraysInObjects, objectsInObjects 75 | { code: "var obj = { 'qux': [ 1, 2 ], 'foo': { 'bar': 1, 'baz': 2 }};", options: ['always', { arraysInObjects: false, objectsInObjects: false }] }, 76 | 77 | // always - arraysInObjects, objectsInObjects (reverse) 78 | { code: "var obj = { 'foo': { 'bar': 1, 'baz': 2 }, 'qux': [ 1, 2 ]};", options: ['always', { arraysInObjects: false, objectsInObjects: false }] }, 79 | 80 | // never 81 | { code: 'var obj = {foo: bar,\nbaz: qux\n};', options: ['never'] }, 82 | { code: 'var obj = {\nfoo: bar,\nbaz: qux};', options: ['never'] }, 83 | 84 | // never - object literals 85 | { code: 'var obj = {foo: bar, baz: qux};', options: ['never'] }, 86 | { code: 'var obj = {foo: {bar: quxx}, baz: qux};', options: ['never'] }, 87 | { code: 'var obj = {foo: {\nbar: quxx}, baz: qux\n};', options: ['never'] }, 88 | { code: 'var obj = {foo: {\nbar: quxx\n}, baz: qux};', options: ['never'] }, 89 | { code: 'var obj = {\nfoo: bar,\nbaz: qux\n};', options: ['never'] }, 90 | 91 | // never - destructuring 92 | { code: 'var {x} = y', options: ['never'], parserOptions }, 93 | { code: 'var {x, y} = y', options: ['never'], parserOptions }, 94 | { code: 'var {x,y} = y', options: ['never'], parserOptions }, 95 | { code: 'var {\nx,y\n} = y', options: ['never'], parserOptions }, 96 | { code: 'var {x = 10} = y', options: ['never'], parserOptions }, 97 | { code: 'var {x = 10, y} = y', options: ['never'], parserOptions }, 98 | { code: 'var {x: {z}, y} = y', options: ['never'], parserOptions }, 99 | { code: 'var {\nx: {z\n}, y} = y', options: ['never'], parserOptions }, 100 | { code: 'var {\ny,\n} = x', options: ['never'], parserOptions }, 101 | { code: 'var {y,} = x', options: ['never'], parserOptions }, 102 | 103 | // never - import / export 104 | { code: "import {door} from 'room'", options: ['never'], parserOptions }, 105 | { code: "export {door} from 'room'", options: ['never'], parserOptions }, 106 | { code: "import {\ndoor} from 'room'", options: ['never'], parserOptions }, 107 | { code: "export {\ndoor\n} from 'room'", options: ['never'], parserOptions }, 108 | { code: "import {house,mouse} from 'caravan'", options: ['never'], parserOptions }, 109 | { code: "import {house, mouse} from 'caravan'", options: ['never'], parserOptions }, 110 | // { code: 'export {door}', options: ['never'], parserOptions: parserOptions }, 111 | { code: "import 'room'", options: ['never'], parserOptions }, 112 | 113 | // never - empty object 114 | { code: 'var foo = {};', options: ['never'] }, 115 | 116 | // never - objectsInObjects 117 | { code: "var obj = {'foo': {'bar': 1, 'baz': 2} };", options: ['never', { objectsInObjects: true }] } 118 | 119 | ], 120 | 121 | invalid: [ 122 | 123 | // either 124 | { 125 | code: "import { x } from 'y'", 126 | options: ['either'], 127 | parserOptions, 128 | errors: [ 129 | { 130 | message: 'Expected consistent spacing', 131 | type: 'ImportDeclaration', 132 | line: 1, 133 | column: 1 134 | } 135 | ] 136 | 137 | }, 138 | { 139 | code: "import { x } from 'y'", 140 | options: ['either'], 141 | parserOptions, 142 | errors: [ 143 | { 144 | message: 'Expected consistent spacing', 145 | type: 'ImportDeclaration', 146 | line: 1, 147 | column: 1 148 | } 149 | ] 150 | 151 | }, 152 | { 153 | code: "import { x} from 'y'", 154 | options: ['either'], 155 | parserOptions, 156 | errors: [ 157 | { 158 | message: 'Expected consistent spacing', 159 | type: 'ImportDeclaration', 160 | line: 1, 161 | column: 1 162 | } 163 | ] 164 | 165 | }, 166 | { 167 | code: "import { x} from 'y'", 168 | options: ['either'], 169 | parserOptions, 170 | errors: [ 171 | { 172 | message: 'Expected consistent spacing', 173 | type: 'ImportDeclaration', 174 | line: 1, 175 | column: 1 176 | } 177 | ] 178 | 179 | }, 180 | { 181 | code: 'var { x} = y', 182 | options: ['either'], 183 | parserOptions, 184 | errors: [ 185 | { 186 | message: 'Expected consistent spacing', 187 | type: 'ObjectPattern', 188 | line: 1, 189 | column: 5 190 | } 191 | ] 192 | 193 | }, 194 | { 195 | code: 'var { x } = y', 196 | options: ['either'], 197 | parserOptions, 198 | errors: [ 199 | { 200 | message: 'Expected consistent spacing', 201 | type: 'ObjectPattern', 202 | line: 1, 203 | column: 5 204 | } 205 | ] 206 | }, 207 | { 208 | code: "var x = { x: '10' }", 209 | options: ['either'], 210 | parserOptions, 211 | errors: [ 212 | { 213 | message: 'Expected consistent spacing', 214 | type: 'ObjectExpression', 215 | line: 1, 216 | column: 9 217 | } 218 | ] 219 | }, 220 | 221 | // import 222 | 223 | { 224 | code: "import {bar} from 'foo.js';", 225 | options: ['always'], 226 | parserOptions, 227 | errors: [ 228 | { 229 | message: "A space is required after '{'", 230 | type: 'ImportDeclaration', 231 | line: 1, 232 | column: 8 233 | }, 234 | { 235 | message: "A space is required before '}'", 236 | type: 'ImportDeclaration', 237 | line: 1, 238 | column: 12 239 | } 240 | ] 241 | }, 242 | // { 243 | // code: 'export {bar};', 244 | // options: ['always'], 245 | // parserOptions: parserOptions, 246 | // errors: [ 247 | // { 248 | // message: "A space is required after '{'", 249 | // type: 'ExportNamedDeclaration', 250 | // line: 1, 251 | // column: 8 252 | // }, 253 | // { 254 | // message: "A space is required before '}'", 255 | // type: 'ExportNamedDeclaration', 256 | // line: 1, 257 | // column: 12 258 | // } 259 | // ] 260 | // }, 261 | 262 | // always - arraysInObjects 263 | { 264 | code: "var obj = { 'foo': [ 1, 2 ] };", 265 | options: ['always', { arraysInObjects: false }], 266 | errors: [ 267 | { 268 | message: "There should be no space before '}'", 269 | type: 'ObjectExpression' 270 | } 271 | ] 272 | }, 273 | { 274 | code: "var obj = { 'foo': [ 1, 2 ] , 'bar': [ 'baz', 'qux' ] };", 275 | options: ['always', { arraysInObjects: false }], 276 | errors: [ 277 | { 278 | message: "There should be no space before '}'", 279 | type: 'ObjectExpression' 280 | } 281 | ] 282 | }, 283 | 284 | // always-objectsInObjects 285 | { 286 | code: "var obj = { 'foo': { 'bar': 1, 'baz': 2 } };", 287 | options: ['always', { objectsInObjects: false }], 288 | errors: [ 289 | { 290 | message: "There should be no space before '}'", 291 | type: 'ObjectExpression', 292 | line: 1, 293 | column: 43 294 | } 295 | ] 296 | }, 297 | { 298 | code: "var obj = { 'foo': [ 1, 2 ] , 'bar': { 'baz': 1, 'qux': 2 } };", 299 | options: ['always', { objectsInObjects: false }], 300 | errors: [ 301 | { 302 | message: "There should be no space before '}'", 303 | type: 'ObjectExpression', 304 | line: 1, 305 | column: 61 306 | } 307 | ] 308 | }, 309 | 310 | // always-destructuring trailing comma 311 | { 312 | code: 'var { a,} = x;', 313 | options: ['always'], 314 | parserOptions, 315 | errors: [ 316 | { 317 | message: "A space is required before '}'", 318 | type: 'ObjectPattern', 319 | line: 1, 320 | column: 9 321 | } 322 | ] 323 | }, 324 | { 325 | code: 'var {a, } = x;', 326 | options: ['never'], 327 | parserOptions, 328 | errors: [ 329 | { 330 | message: "There should be no space before '}'", 331 | type: 'ObjectPattern', 332 | line: 1, 333 | column: 9 334 | } 335 | ] 336 | }, 337 | 338 | // never-objectsInObjects 339 | { 340 | code: "var obj = {'foo': {'bar': 1, 'baz': 2}};", 341 | options: ['never', { objectsInObjects: true }], 342 | errors: [ 343 | { 344 | message: "A space is required before '}'", 345 | type: 'ObjectExpression', 346 | line: 1, 347 | column: 39 348 | } 349 | ] 350 | }, 351 | { 352 | code: "var obj = {'foo': [1, 2] , 'bar': {'baz': 1, 'qux': 2}};", 353 | options: ['never', { objectsInObjects: true }], 354 | errors: [ 355 | { 356 | message: "A space is required before '}'", 357 | type: 'ObjectExpression', 358 | line: 1, 359 | column: 55 360 | } 361 | ] 362 | }, 363 | 364 | // always & never 365 | { 366 | code: 'var obj = {foo: bar, baz: qux};', 367 | options: ['always'], 368 | errors: [ 369 | { 370 | message: "A space is required after '{'", 371 | type: 'ObjectExpression', 372 | line: 1, 373 | column: 11 374 | }, 375 | { 376 | message: "A space is required before '}'", 377 | type: 'ObjectExpression', 378 | line: 1, 379 | column: 30 380 | } 381 | ] 382 | }, 383 | { 384 | code: 'var obj = {foo: bar, baz: qux };', 385 | options: ['always'], 386 | errors: [ 387 | { 388 | message: "A space is required after '{'", 389 | type: 'ObjectExpression', 390 | line: 1, 391 | column: 11 392 | } 393 | ] 394 | }, 395 | { 396 | code: 'var obj = { foo: bar, baz: qux};', 397 | options: ['always'], 398 | errors: [ 399 | { 400 | message: "A space is required before '}'", 401 | type: 'ObjectExpression', 402 | line: 1, 403 | column: 31 404 | } 405 | ] 406 | }, 407 | { 408 | code: 'var obj = { foo: bar, baz: qux };', 409 | options: ['never'], 410 | errors: [ 411 | { 412 | message: "There should be no space after '{'", 413 | type: 'ObjectExpression', 414 | line: 1, 415 | column: 11 416 | }, 417 | { 418 | message: "There should be no space before '}'", 419 | type: 'ObjectExpression', 420 | line: 1, 421 | column: 32 422 | } 423 | ] 424 | }, 425 | { 426 | code: 'var obj = {foo: bar, baz: qux };', 427 | options: ['never'], 428 | errors: [ 429 | { 430 | message: "There should be no space before '}'", 431 | type: 'ObjectExpression', 432 | line: 1, 433 | column: 31 434 | } 435 | ] 436 | }, 437 | { 438 | code: 'var obj = { foo: bar, baz: qux};', 439 | options: ['never'], 440 | errors: [ 441 | { 442 | message: "There should be no space after '{'", 443 | type: 'ObjectExpression', 444 | line: 1, 445 | column: 11 446 | } 447 | ] 448 | }, 449 | { 450 | code: 'var obj = { foo: { bar: quxx}, baz: qux};', 451 | options: ['never'], 452 | errors: [ 453 | { 454 | message: "There should be no space after '{'", 455 | type: 'ObjectExpression', 456 | line: 1, 457 | column: 11 458 | }, 459 | { 460 | message: "There should be no space after '{'", 461 | type: 'ObjectExpression', 462 | line: 1, 463 | column: 18 464 | } 465 | ] 466 | }, 467 | { 468 | code: 'var obj = {foo: {bar: quxx }, baz: qux };', 469 | options: ['never'], 470 | errors: [ 471 | { 472 | message: "There should be no space before '}'", 473 | type: 'ObjectExpression', 474 | line: 1, 475 | column: 28 476 | }, 477 | { 478 | message: "There should be no space before '}'", 479 | type: 'ObjectExpression', 480 | line: 1, 481 | column: 40 482 | } 483 | ] 484 | }, 485 | { 486 | code: 'export const thing = {value: 1 };', 487 | parserOptions, 488 | options: ['always'], 489 | errors: [ 490 | { 491 | message: "A space is required after '{'", 492 | type: 'ObjectExpression', 493 | line: 1, 494 | column: 22 495 | } 496 | ] 497 | }, 498 | 499 | // destructuring 500 | { 501 | code: 'var {x, y} = y', 502 | parserOptions, 503 | options: ['always'], 504 | errors: [ 505 | { 506 | message: "A space is required after '{'", 507 | type: 'ObjectPattern', 508 | line: 1, 509 | column: 5 510 | }, 511 | { 512 | message: "A space is required before '}'", 513 | type: 'ObjectPattern', 514 | line: 1, 515 | column: 10 516 | } 517 | ] 518 | }, 519 | { 520 | code: 'var { x, y} = y', 521 | parserOptions, 522 | options: ['always'], 523 | errors: [ 524 | { 525 | message: "A space is required before '}'", 526 | type: 'ObjectPattern', 527 | line: 1, 528 | column: 11 529 | } 530 | ] 531 | }, 532 | { 533 | code: 'var { x, y } = y', 534 | parserOptions, 535 | options: ['never'], 536 | errors: [ 537 | { 538 | message: "There should be no space after '{'", 539 | type: 'ObjectPattern', 540 | line: 1, 541 | column: 5 542 | }, 543 | { 544 | message: "There should be no space before '}'", 545 | type: 'ObjectPattern', 546 | line: 1, 547 | column: 12 548 | } 549 | ] 550 | }, 551 | { 552 | code: 'var {x, y } = y', 553 | parserOptions, 554 | options: ['never'], 555 | errors: [ 556 | { 557 | message: "There should be no space before '}'", 558 | type: 'ObjectPattern', 559 | line: 1, 560 | column: 11 561 | } 562 | ] 563 | }, 564 | { 565 | code: 'var { x=10} = y', 566 | parserOptions, 567 | options: ['always'], 568 | errors: [ 569 | { 570 | message: "A space is required before '}'", 571 | type: 'ObjectPattern', 572 | line: 1, 573 | column: 11 574 | } 575 | ] 576 | }, 577 | { 578 | code: 'var {x=10 } = y', 579 | parserOptions, 580 | options: ['always'], 581 | errors: [ 582 | { 583 | message: "A space is required after '{'", 584 | type: 'ObjectPattern', 585 | line: 1, 586 | column: 5 587 | } 588 | ] 589 | }, 590 | 591 | // never - arraysInObjects 592 | { 593 | code: "var obj = {'foo': [1, 2]};", 594 | options: ['never', { arraysInObjects: true }], 595 | errors: [ 596 | { 597 | message: "A space is required before '}'", 598 | type: 'ObjectExpression' 599 | } 600 | ] 601 | }, 602 | { 603 | code: "var obj = {'foo': [1, 2] , 'bar': ['baz', 'qux']};", 604 | options: ['never', { arraysInObjects: true }], 605 | errors: [ 606 | { 607 | message: "A space is required before '}'", 608 | type: 'ObjectExpression' 609 | } 610 | ] 611 | } 612 | ] 613 | }) 614 | -------------------------------------------------------------------------------- /tests/array-bracket-even-spacing.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @fileoverview Disallows or enforces spaces inside of brackets. 3 | * @author Ian Christian Myers 4 | * @copyright 2014 Vignesh Anand. All rights reserved. 5 | */ 6 | 'use strict' 7 | 8 | // ------------------------------------------------------------------------------ 9 | // Requirements 10 | // ------------------------------------------------------------------------------ 11 | 12 | const RuleTester = require('eslint').RuleTester 13 | const rule = require('../rules/array-bracket-even-spacing') 14 | const parserOptions = { ecmaVersion: 2018, sourceType: 'module' } 15 | 16 | // ------------------------------------------------------------------------------ 17 | // Tests 18 | // ------------------------------------------------------------------------------ 19 | 20 | const ruleTester = new RuleTester() 21 | ruleTester.run('array-bracket-even-spacing', rule, { 22 | valid: [ 23 | 24 | // either 25 | { code: 'var x = [ a ]', options: ['either'] }, 26 | { code: 'var x = [a]', options: ['either'] }, 27 | { code: 'var x = [a,b,c]', options: ['either'] }, 28 | { code: 'var x = [ a,b,c ]', options: ['either'] }, 29 | { code: 'var x = [\na,b,c\n]', options: ['either'] }, 30 | { code: 'var x = [\n\ta,b,c\n]', options: ['either'] }, 31 | { code: 'var foo = [];', options: ['either'] }, 32 | { code: 'var [x] = y', options: ['either'], parserOptions }, 33 | { code: 'var [ x ] = y', options: ['either'], parserOptions }, 34 | { code: 'var [\nx\n] = y', options: ['either'], parserOptions }, 35 | { code: 'var [\n\tx\n] = y', options: ['either'], parserOptions }, 36 | 37 | { code: 'var foo = obj[ 1 ]', options: ['always'] }, 38 | { code: "var foo = obj[ 'foo' ];", options: ['always'] }, 39 | { code: 'var foo = obj[ [ 1, 1 ] ];', options: ['always'] }, 40 | 41 | // always - singleValue 42 | { code: "var foo = ['foo']", options: ['always', { singleValue: false }] }, 43 | { code: 'var foo = [2]', options: ['always', { singleValue: false }] }, 44 | { code: 'var foo = [[ 1, 1 ]]', options: ['always', { singleValue: false }] }, 45 | { code: "var foo = [{ 'foo': 'bar' }]", options: ['always', { singleValue: false }] }, 46 | { code: 'var foo = [bar]', options: ['always', { singleValue: false }] }, 47 | 48 | // always - objectsInArrays 49 | { code: "var foo = [{ 'bar': 'baz' }, 1, 5 ];", options: ['always', { objectsInArrays: false }] }, 50 | { code: "var foo = [ 1, 5, { 'bar': 'baz' }];", options: ['always', { objectsInArrays: false }] }, 51 | { code: "var foo = [{\n'bar': 'baz', \n'qux': [{ 'bar': 'baz' }], \n'quxx': 1 \n}]", options: ['always', { objectsInArrays: false }] }, 52 | { code: "var foo = [{ 'bar': 'baz' }]", options: ['always', { objectsInArrays: false }] }, 53 | { code: "var foo = [{ 'bar': 'baz' }, 1, { 'bar': 'baz' }];", options: ['always', { objectsInArrays: false }] }, 54 | { code: "var foo = [ 1, { 'bar': 'baz' }, 5 ];", options: ['always', { objectsInArrays: false }] }, 55 | { code: "var foo = [ 1, { 'bar': 'baz' }, [{ 'bar': 'baz' }] ];", options: ['always', { objectsInArrays: false }] }, 56 | 57 | // always - arraysInArrays 58 | { code: 'var arr = [[ 1, 2 ], 2, 3, 4 ];', options: ['always', { arraysInArrays: false }] }, 59 | { code: 'var arr = [[ 1, 2 ], [[[ 1 ]]], 3, 4 ];', options: ['always', { arraysInArrays: false }] }, 60 | 61 | // always - arraysInArrays, objectsInArrays 62 | { code: "var arr = [[ 1, 2 ], 2, 3, { 'foo': 'bar' }];", options: ['always', { arraysInArrays: false, objectsInArrays: false }] }, 63 | 64 | // always - arraysInArrays, objectsInArrays, singleValue 65 | { code: "var arr = [[ 1, 2 ], [2], 3, { 'foo': 'bar' }];", options: ['always', { arraysInArrays: false, objectsInArrays: false, singleValue: false }] }, 66 | 67 | // always 68 | { code: 'obj[ foo ]', options: ['always'] }, 69 | { code: 'obj[\nfoo\n]', options: ['always'] }, 70 | { code: "obj[ 'foo' ]", options: ['always'] }, 71 | { code: "obj[ 'foo' + 'bar' ]", options: ['always'] }, 72 | { code: 'obj[ obj2[ foo ] ]', options: ['always'] }, 73 | { code: 'obj.map(function(item) { return [\n1,\n2,\n3,\n4\n]; })', options: ['always'] }, 74 | { code: "obj[ 'map' ](function(item) { return [\n1,\n2,\n3,\n4\n]; })", options: ['always'] }, 75 | { code: "obj[ 'for' + 'Each' ](function(item) { return [\n1,\n2,\n3,\n4\n]; })", options: ['always'] }, 76 | 77 | { code: 'var arr = [ 1, 2, 3, 4 ];', options: ['always'] }, 78 | { code: 'var arr = [ [ 1, 2 ], 2, 3, 4 ];', options: ['always'] }, 79 | { code: 'var arr = [\n1, 2, 3, 4\n];', options: ['always'] }, 80 | { code: 'var foo = [];', options: ['always'] }, 81 | 82 | // singleValue: false, objectsInArrays: true, arraysInArrays 83 | { code: "this.db.mappings.insert([\n { alias: 'a', url: 'http://www.amazon.de' },\n { alias: 'g', url: 'http://www.google.de' }\n], function() {});", options: ['always', { singleValue: false, objectsInArrays: true, arraysInArrays: true }] }, 84 | 85 | // always - destructuring assignment 86 | { code: 'var [ x, y ] = z', parserOptions, options: ['always'] }, 87 | { code: 'var [ x,y ] = z', parserOptions, options: ['always'] }, 88 | { code: 'var [ x, y\n] = z', parserOptions, options: ['always'] }, 89 | { code: 'var [\nx, y ] = z', parserOptions, options: ['always'] }, 90 | { code: 'var [\nx, y\n] = z', parserOptions, options: ['always'] }, 91 | { code: 'var [\nx, y\n] = z', parserOptions, options: ['always'] }, 92 | { code: 'var [\nx,,,\n] = z', parserOptions, options: ['always'] }, 93 | { code: 'var [ ,x, ] = z', parserOptions, options: ['always'] }, 94 | { code: 'var [\nx, ...y\n] = z', parserOptions, options: ['always'] }, 95 | { code: 'var [\nx, ...y ] = z', parserOptions, options: ['always'] }, 96 | 97 | // never 98 | { code: 'obj[foo]', options: ['never'] }, 99 | { code: "obj['foo']", options: ['never'] }, 100 | { code: "obj['foo' + 'bar']", options: ['never'] }, 101 | { code: "obj['foo'+'bar']", options: ['never'] }, 102 | { code: 'obj[obj2[foo]]', options: ['never'] }, 103 | { code: 'obj.map(function(item) { return [\n1,\n2,\n3,\n4\n]; })', options: ['never'] }, 104 | { code: "obj['map'](function(item) { return [\n1,\n2,\n3,\n4\n]; })", options: ['never'] }, 105 | { code: "obj['for' + 'Each'](function(item) { return [\n1,\n2,\n3,\n4\n]; })", options: ['never'] }, 106 | { code: "obj['for' + 'Each'](function(item) { return [\n1,\n2,\n3,\n4\n]; })", options: ['never'] }, 107 | { code: 'var arr = [1, 2, 3, 4];', options: ['never'] }, 108 | { code: 'var arr = [[1, 2], 2, 3, 4];', options: ['never'] }, 109 | { code: 'var arr = [\n1, 2, 3, 4\n];', options: ['never'] }, 110 | { code: 'obj[\nfoo]', options: ['never'] }, 111 | { code: 'obj[foo\n]', options: ['never'] }, 112 | { code: 'var arr = [1,\n2,\n3,\n4\n];', options: ['never'] }, 113 | { code: 'var arr = [\n1,\n2,\n3,\n4];', options: ['never'] }, 114 | 115 | // never - destructuring assignment 116 | { code: 'var [x, y] = z', parserOptions, options: ['never'] }, 117 | { code: 'var [x,y] = z', parserOptions, options: ['never'] }, 118 | { code: 'var [x, y\n] = z', parserOptions, options: ['never'] }, 119 | { code: 'var [\nx, y] = z', parserOptions, options: ['never'] }, 120 | { code: 'var [\nx, y\n] = z', parserOptions, options: ['never'] }, 121 | { code: 'var [\nx, y\n] = z', parserOptions, options: ['never'] }, 122 | { code: 'var [\nx,,,\n] = z', parserOptions, options: ['never'] }, 123 | { code: 'var [,x,] = z', parserOptions, options: ['never'] }, 124 | { code: 'var [\nx, ...y\n] = z', parserOptions, options: ['never'] }, 125 | { code: 'var [\nx, ...y] = z', parserOptions, options: ['never'] }, 126 | 127 | // never - singleValue 128 | { code: "var foo = [ 'foo' ]", options: ['never', { singleValue: true }] }, 129 | { code: 'var foo = [ 2 ]', options: ['never', { singleValue: true }] }, 130 | { code: 'var foo = [ [1, 1] ]', options: ['never', { singleValue: true }] }, 131 | { code: "var foo = [ {'foo': 'bar'} ]", options: ['never', { singleValue: true }] }, 132 | { code: 'var foo = [ bar ]', options: ['never', { singleValue: true }] }, 133 | 134 | // never - objectsInArrays 135 | { code: "var foo = [ {'bar': 'baz'}, 1, 5];", options: ['never', { objectsInArrays: true }] }, 136 | { code: "var foo = [1, 5, {'bar': 'baz'} ];", options: ['never', { objectsInArrays: true }] }, 137 | { code: "var foo = [ {\n'bar': 'baz', \n'qux': [ {'bar': 'baz'} ], \n'quxx': 1 \n} ]", options: ['never', { objectsInArrays: true }] }, 138 | { code: "var foo = [ {'bar': 'baz'} ]", options: ['never', { objectsInArrays: true }] }, 139 | { code: "var foo = [ {'bar': 'baz'}, 1, {'bar': 'baz'} ];", options: ['never', { objectsInArrays: true }] }, 140 | { code: "var foo = [1, {'bar': 'baz'} , 5];", options: ['never', { objectsInArrays: true }] }, 141 | { code: "var foo = [1, {'bar': 'baz'}, [ {'bar': 'baz'} ]];", options: ['never', { objectsInArrays: true }] }, 142 | 143 | // never - arraysInArrays 144 | { code: 'var arr = [ [1, 2], 2, 3, 4];', options: ['never', { arraysInArrays: true }] }, 145 | 146 | // never - arraysInArrays, singleValue 147 | { code: 'var arr = [ [1, 2], [ [ [ 1 ] ] ], 3, 4];', options: ['never', { arraysInArrays: true, singleValue: true }] }, 148 | 149 | // never - arraysInArrays, objectsInArrays 150 | { code: "var arr = [ [1, 2], 2, 3, {'foo': 'bar'} ];", options: ['never', { arraysInArrays: true, objectsInArrays: true }] }, 151 | 152 | // should not warn 153 | { code: 'var foo = {};', options: ['never'] }, 154 | { code: 'var foo = [];', options: ['never'] }, 155 | 156 | { code: "var foo = [{'bar':'baz'}, 1, {'bar': 'baz'}];", options: ['never'] }, 157 | { code: "var foo = [{'bar': 'baz'}];", options: ['never'] }, 158 | { code: "var foo = [{\n'bar': 'baz', \n'qux': [{'bar': 'baz'}], \n'quxx': 1 \n}]", options: ['never'] }, 159 | { code: "var foo = [1, {'bar': 'baz'}, 5];", options: ['never'] }, 160 | { code: "var foo = [{'bar': 'baz'}, 1, 5];", options: ['never'] }, 161 | { code: "var foo = [1, 5, {'bar': 'baz'}];", options: ['never'] }, 162 | { code: "var obj = {'foo': [1, 2]}", options: ['never'] } 163 | 164 | ], 165 | 166 | invalid: [ 167 | 168 | { 169 | code: 'var [ x] = y', 170 | options: ['either'], 171 | parserOptions, 172 | errors: [ 173 | { 174 | message: 'Expected consistent spacing', 175 | type: 'ArrayPattern', 176 | line: 1, 177 | column: 5 178 | } 179 | ] 180 | 181 | }, 182 | { 183 | code: 'var [ x,y,z] = y', 184 | options: ['either'], 185 | parserOptions, 186 | errors: [ 187 | { 188 | message: 'Expected consistent spacing', 189 | type: 'ArrayPattern', 190 | line: 1, 191 | column: 5 192 | } 193 | ] 194 | 195 | }, 196 | { 197 | code: 'var [ x ] = y', 198 | options: ['either'], 199 | parserOptions, 200 | errors: [ 201 | { 202 | message: 'Expected consistent spacing', 203 | type: 'ArrayPattern', 204 | line: 1, 205 | column: 5 206 | } 207 | ] 208 | }, 209 | { 210 | code: 'var x = [ x, y]', 211 | options: ['either'], 212 | parserOptions, 213 | errors: [ 214 | { 215 | message: 'Expected consistent spacing', 216 | type: 'ArrayExpression', 217 | line: 1, 218 | column: 9 219 | } 220 | ] 221 | }, 222 | { 223 | code: 'var x = [ x, y ]', 224 | options: ['either'], 225 | parserOptions, 226 | errors: [ 227 | { 228 | message: 'Expected consistent spacing', 229 | type: 'ArrayExpression', 230 | line: 1, 231 | column: 9 232 | } 233 | ] 234 | }, 235 | 236 | // objectsInArrays 237 | { 238 | code: "var foo = [ { 'bar': 'baz' }, 1, 5];", 239 | options: ['always', { objectsInArrays: false }], 240 | errors: [ 241 | { 242 | message: "There should be no space after '['", 243 | type: 'ArrayExpression', 244 | line: 1 245 | }, 246 | { 247 | message: "A space is required before ']'", 248 | type: 'ArrayExpression', 249 | line: 1 250 | } 251 | ] 252 | }, 253 | { 254 | code: "var foo = [1, 5, { 'bar': 'baz' } ];", 255 | options: ['always', { objectsInArrays: false }], 256 | errors: [ 257 | { 258 | message: "A space is required after '['", 259 | type: 'ArrayExpression', 260 | line: 1 261 | }, 262 | { 263 | message: "There should be no space before ']'", 264 | type: 'ArrayExpression', 265 | line: 1 266 | } 267 | ] 268 | }, 269 | { 270 | code: "var foo = [ { 'bar':'baz' }, 1, { 'bar': 'baz' } ];", 271 | options: ['always', { objectsInArrays: false }], 272 | errors: [ 273 | { 274 | message: "There should be no space after '['", 275 | type: 'ArrayExpression', 276 | line: 1 277 | }, 278 | { 279 | message: "There should be no space before ']'", 280 | type: 'ArrayExpression', 281 | line: 1 282 | } 283 | ] 284 | }, 285 | 286 | // singleValue 287 | { 288 | code: "var obj = [ 'foo' ];", 289 | options: ['always', { singleValue: false }], 290 | errors: [ 291 | { 292 | message: "There should be no space after '['", 293 | type: 'ArrayExpression', 294 | line: 1 295 | }, 296 | { 297 | message: "There should be no space before ']'", 298 | type: 'ArrayExpression', 299 | line: 1 300 | } 301 | ] 302 | }, 303 | { 304 | code: "var obj = ['foo' ];", 305 | options: ['always', { singleValue: false }], 306 | errors: [ 307 | { 308 | message: "There should be no space before ']'", 309 | type: 'ArrayExpression', 310 | line: 1 311 | } 312 | ] 313 | }, 314 | { 315 | code: "var obj = ['foo'];", 316 | options: ['never', { singleValue: true }], 317 | errors: [ 318 | { 319 | message: "A space is required after '['", 320 | type: 'ArrayExpression', 321 | line: 1 322 | }, 323 | { 324 | message: "A space is required before ']'", 325 | type: 'ArrayExpression', 326 | line: 1 327 | } 328 | ] 329 | }, 330 | 331 | // always - arraysInArrays 332 | { 333 | code: 'var arr = [ [ 1, 2 ], 2, 3, 4 ];', 334 | options: ['always', { arraysInArrays: false }], 335 | errors: [ 336 | { 337 | message: "There should be no space after '['", 338 | type: 'ArrayExpression', 339 | line: 1 340 | } 341 | ] 342 | }, 343 | { 344 | code: 'var arr = [ 1, 2, 2, [ 3, 4 ] ];', 345 | options: ['always', { arraysInArrays: false }], 346 | errors: [ 347 | { 348 | message: "There should be no space before ']'", 349 | type: 'ArrayExpression', 350 | line: 1 351 | } 352 | ] 353 | }, 354 | { 355 | code: 'var arr = [[ 1, 2 ], 2, [ 3, 4 ] ];', 356 | options: ['always', { arraysInArrays: false }], 357 | errors: [ 358 | { 359 | message: "There should be no space before ']'", 360 | type: 'ArrayExpression', 361 | line: 1 362 | } 363 | ] 364 | }, 365 | { 366 | code: 'var arr = [ [ 1, 2 ], 2, [ 3, 4 ]];', 367 | options: ['always', { arraysInArrays: false }], 368 | errors: [ 369 | { 370 | message: "There should be no space after '['", 371 | type: 'ArrayExpression', 372 | line: 1 373 | } 374 | ] 375 | }, 376 | { 377 | code: 'var arr = [ [ 1, 2 ], 2, [ 3, 4 ] ];', 378 | options: ['always', { arraysInArrays: false }], 379 | errors: [ 380 | { 381 | message: "There should be no space after '['", 382 | type: 'ArrayExpression', 383 | line: 1 384 | }, 385 | { 386 | message: "There should be no space before ']'", 387 | type: 'ArrayExpression', 388 | line: 1 389 | } 390 | ] 391 | }, 392 | 393 | // always - destructuring 394 | { 395 | code: 'var [x,y] = y', 396 | options: ['always'], 397 | parserOptions, 398 | errors: [{ 399 | message: "A space is required after '['", 400 | type: 'ArrayPattern', 401 | line: 1 402 | }, 403 | { 404 | message: "A space is required before ']'", 405 | type: 'ArrayPattern', 406 | line: 1 407 | }] 408 | }, 409 | { 410 | code: 'var [x,y ] = y', 411 | options: ['always'], 412 | parserOptions, 413 | errors: [{ 414 | message: "A space is required after '['", 415 | type: 'ArrayPattern', 416 | line: 1 417 | }] 418 | }, 419 | { 420 | code: 'var [,,,x,,] = y', 421 | options: ['always'], 422 | parserOptions, 423 | errors: [{ 424 | message: "A space is required after '['", 425 | type: 'ArrayPattern', 426 | line: 1 427 | }, 428 | { 429 | message: "A space is required before ']'", 430 | type: 'ArrayPattern', 431 | line: 1 432 | }] 433 | }, 434 | { 435 | code: 'var [ ,,,x,,] = y', 436 | options: ['always'], 437 | parserOptions, 438 | errors: [{ 439 | message: "A space is required before ']'", 440 | type: 'ArrayPattern', 441 | line: 1 442 | }] 443 | }, 444 | { 445 | code: 'var [...horse] = y', 446 | options: ['always'], 447 | parserOptions, 448 | errors: [{ 449 | message: "A space is required after '['", 450 | type: 'ArrayPattern', 451 | line: 1 452 | }, 453 | { 454 | message: "A space is required before ']'", 455 | type: 'ArrayPattern', 456 | line: 1 457 | }] 458 | }, 459 | { 460 | code: 'var [...horse ] = y', 461 | options: ['always'], 462 | parserOptions, 463 | errors: [{ 464 | message: "A space is required after '['", 465 | type: 'ArrayPattern', 466 | line: 1 467 | }] 468 | }, 469 | 470 | // never - arraysInArrays 471 | { 472 | code: 'var arr = [[1, 2], 2, [3, 4]];', 473 | options: ['never', { arraysInArrays: true }], 474 | errors: [ 475 | { 476 | message: "A space is required after '['", 477 | type: 'ArrayExpression', 478 | line: 1 479 | }, 480 | { 481 | message: "A space is required before ']'", 482 | type: 'ArrayExpression', 483 | line: 1 484 | } 485 | ] 486 | }, 487 | 488 | // always 489 | { 490 | code: 'var arr = [1, 2, 3, 4];', 491 | options: ['always'], 492 | errors: [ 493 | { 494 | message: "A space is required after '['", 495 | type: 'ArrayExpression', 496 | line: 1 497 | }, 498 | { 499 | message: "A space is required before ']'", 500 | type: 'ArrayExpression', 501 | line: 1 502 | } 503 | ] 504 | }, 505 | { 506 | code: 'var arr = [1, 2, 3, 4 ];', 507 | options: ['always'], 508 | errors: [ 509 | { 510 | message: "A space is required after '['", 511 | type: 'ArrayExpression', 512 | line: 1 513 | } 514 | ] 515 | }, 516 | { 517 | code: 'var arr = [ 1, 2, 3, 4];', 518 | options: ['always'], 519 | errors: [ 520 | { 521 | message: "A space is required before ']'", 522 | type: 'ArrayExpression', 523 | line: 1 524 | } 525 | ] 526 | }, 527 | { 528 | code: 'var arr = [ 1, 2, 3, 4 ];', 529 | options: ['never'], 530 | errors: [ 531 | { 532 | message: "There should be no space after '['", 533 | type: 'ArrayExpression', 534 | line: 1 535 | }, 536 | { 537 | message: "There should be no space before ']'", 538 | type: 'ArrayExpression', 539 | line: 1 540 | } 541 | ] 542 | }, 543 | { 544 | code: 'var arr = [1, 2, 3, 4 ];', 545 | options: ['never'], 546 | errors: [ 547 | { 548 | message: "There should be no space before ']'", 549 | type: 'ArrayExpression', 550 | line: 1 551 | } 552 | ] 553 | }, 554 | { 555 | code: 'var arr = [ 1, 2, 3, 4];', 556 | options: ['never'], 557 | errors: [ 558 | { 559 | message: "There should be no space after '['", 560 | type: 'ArrayExpression', 561 | line: 1 562 | } 563 | ] 564 | }, 565 | { 566 | code: 'var arr = [ [ 1], 2, 3, 4];', 567 | options: ['never'], 568 | errors: [ 569 | { 570 | message: "There should be no space after '['", 571 | type: 'ArrayExpression', 572 | line: 1 573 | }, 574 | { 575 | message: "There should be no space after '['", 576 | type: 'ArrayExpression', 577 | line: 1 578 | } 579 | ] 580 | }, 581 | { 582 | code: 'var arr = [[1 ], 2, 3, 4 ];', 583 | options: ['never'], 584 | errors: [ 585 | { 586 | message: "There should be no space before ']'", 587 | type: 'ArrayExpression', 588 | line: 1 589 | }, 590 | { 591 | message: "There should be no space before ']'", 592 | type: 'ArrayExpression', 593 | line: 1 594 | } 595 | ] 596 | } 597 | ] 598 | }) 599 | --------------------------------------------------------------------------------