/** * @fileoverview Disallows or enforces spaces inside computed properties. * @author Jamund Ferguson * @deprecated in ESLint v8.53.0 */ 'use strict'; const astUtils = require('./utils/ast-utils'); //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ /** @type {import('../types').Rule.RuleModule} */ module.exports = { meta: { deprecated: { message: 'Formatting rules are being moved out of ESLint core.', url: 'https://eslint.org/blog/2023/10/deprecating-formatting-rules/', deprecatedSince: '8.53.0', availableUntil: '10.0.0', replacedBy: [ { message: 'ESLint Stylistic now maintains deprecated stylistic core rules.', url: 'https://eslint.style/guide/migration', plugin: { name: '@stylistic/eslint-plugin-js', url: 'https://eslint.style/packages/js', }, rule: { name: 'computed-property-spacing', url: 'https://eslint.style/rules/js/computed-property-spacing', }, }, ], }, type: 'layout', docs: { description: 'Enforce consistent spacing inside computed property brackets', recommended: false, url: 'https://eslint.org/docs/latest/rules/computed-property-spacing', }, fixable: 'whitespace', schema: [ { enum: ['always', 'never'], }, { type: 'object', properties: { enforceForClassMembers: { type: 'boolean', default: true, }, }, additionalProperties: false, }, ], messages: { unexpectedSpaceBefore: "There should be no space before '{{tokenValue}}'.", unexpectedSpaceAfter: "There should be no space after '{{tokenValue}}'.", missingSpaceBefore: "A space is required before '{{tokenValue}}'.", missingSpaceAfter: "A space is required after '{{tokenValue}}'.", }, }, create(context) { const sourceCode = context.sourceCode; const propertyNameMustBeSpaced = context.options[0] === 'always'; // default is "never" const enforceForClassMembers = !context.options[1] || context.options[1].enforceForClassMembers; //-------------------------------------------------------------------------- // Helpers //-------------------------------------------------------------------------- /** * Reports that there shouldn't be a space after the first token * @param {ASTNode} node The node to report in the event of an error. * @param {Token} token The token to use for the report. * @param {Token} tokenAfter The token after `token`. * @returns {void} */ function reportNoBeginningSpace(node, token, tokenAfter) { context.report({ node, loc: { start: token.loc.end, end: tokenAfter.loc.start }, messageId: 'unexpectedSpaceAfter', data: { tokenValue: token.value, }, fix(fixer) { return fixer.removeRange([token.range[1], tokenAfter.range[0]]); }, }); } /** * Reports that there shouldn't be a space before the last token * @param {ASTNode} node The node to report in the event of an error. * @param {Token} token The token to use for the report. * @param {Token} tokenBefore The token before `token`. * @returns {void} */ function reportNoEndingSpace(node, token, tokenBefore) { context.report({ node, loc: { start: tokenBefore.loc.end, end: token.loc.start }, messageId: 'unexpectedSpaceBefore', data: { tokenValue: token.value, }, fix(fixer) { return fixer.removeRange([tokenBefore.range[1], token.range[0]]); }, }); } /** * Reports that there should be a space after the first token * @param {ASTNode} node The node to report in the event of an error. * @param {Token} token The token to use for the report. * @returns {void} */ function reportRequiredBeginningSpace(node, token) { context.report({ node, loc: token.loc, messageId: 'missingSpaceAfter', data: { tokenValue: token.value, }, fix(fixer) { return fixer.insertTextAfter(token, ' '); }, }); } /** * Reports that there should be a space before the last token * @param {ASTNode} node The node to report in the event of an error. * @param {Token} token The token to use for the report. * @returns {void} */ function reportRequiredEndingSpace(node, token) { context.report({ node, loc: token.loc, messageId: 'missingSpaceBefore', data: { tokenValue: token.value, }, fix(fixer) { return fixer.insertTextBefore(token, ' '); }, }); } /** * Returns a function that checks the spacing of a node on the property name * that was passed in. * @param {string} propertyName The property on the node to check for spacing * @returns {Function} A function that will check spacing on a node */ function checkSpacing(propertyName) { return function (node) { if (!node.computed) { return; } const property = node[propertyName]; const before = sourceCode.getTokenBefore( property, astUtils.isOpeningBracketToken ), first = sourceCode.getTokenAfter(before, { includeComments: true, }), after = sourceCode.getTokenAfter( property, astUtils.isClosingBracketToken ), last = sourceCode.getTokenBefore(after, { includeComments: true, }); if (astUtils.isTokenOnSameLine(before, first)) { if (propertyNameMustBeSpaced) { if ( !sourceCode.isSpaceBetweenTokens(before, first) && astUtils.isTokenOnSameLine(before, first) ) { reportRequiredBeginningSpace(node, before); } } else { if (sourceCode.isSpaceBetweenTokens(before, first)) { reportNoBeginningSpace(node, before, first); } } } if (astUtils.isTokenOnSameLine(last, after)) { if (propertyNameMustBeSpaced) { if ( !sourceCode.isSpaceBetweenTokens(last, after) && astUtils.isTokenOnSameLine(last, after) ) { reportRequiredEndingSpace(node, after); } } else { if (sourceCode.isSpaceBetweenTokens(last, after)) { reportNoEndingSpace(node, after, last); } } } }; } //-------------------------------------------------------------------------- // Public //-------------------------------------------------------------------------- const listeners = { Property: checkSpacing('key'), MemberExpression: checkSpacing('property'), }; if (enforceForClassMembers) { listeners.MethodDefinition = listeners.PropertyDefinition = listeners.Property; } return listeners; }, };