Permalink
Cannot retrieve contributors at this time
176 lines (154 sloc)
6.6 KB
Name already in use
A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
codeql-action/node_modules/eslint/lib/rules/dot-notation.js
Go to fileThis commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @fileoverview Rule to warn about using dot notation instead of square bracket notation when possible. | |
* @author Josh Perez | |
*/ | |
"use strict"; | |
//------------------------------------------------------------------------------ | |
// Requirements | |
//------------------------------------------------------------------------------ | |
const astUtils = require("./utils/ast-utils"); | |
const keywords = require("./utils/keywords"); | |
//------------------------------------------------------------------------------ | |
// Rule Definition | |
//------------------------------------------------------------------------------ | |
const validIdentifier = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/u; | |
// `null` literal must be handled separately. | |
const literalTypesToCheck = new Set(["string", "boolean"]); | |
/** @type {import('../shared/types').Rule} */ | |
module.exports = { | |
meta: { | |
type: "suggestion", | |
docs: { | |
description: "Enforce dot notation whenever possible", | |
recommended: false, | |
url: "https://eslint.org/docs/latest/rules/dot-notation" | |
}, | |
schema: [ | |
{ | |
type: "object", | |
properties: { | |
allowKeywords: { | |
type: "boolean", | |
default: true | |
}, | |
allowPattern: { | |
type: "string", | |
default: "" | |
} | |
}, | |
additionalProperties: false | |
} | |
], | |
fixable: "code", | |
messages: { | |
useDot: "[{{key}}] is better written in dot notation.", | |
useBrackets: ".{{key}} is a syntax error." | |
} | |
}, | |
create(context) { | |
const options = context.options[0] || {}; | |
const allowKeywords = options.allowKeywords === void 0 || options.allowKeywords; | |
const sourceCode = context.sourceCode; | |
let allowPattern; | |
if (options.allowPattern) { | |
allowPattern = new RegExp(options.allowPattern, "u"); | |
} | |
/** | |
* Check if the property is valid dot notation | |
* @param {ASTNode} node The dot notation node | |
* @param {string} value Value which is to be checked | |
* @returns {void} | |
*/ | |
function checkComputedProperty(node, value) { | |
if ( | |
validIdentifier.test(value) && | |
(allowKeywords || !keywords.includes(String(value))) && | |
!(allowPattern && allowPattern.test(value)) | |
) { | |
const formattedValue = node.property.type === "Literal" ? JSON.stringify(value) : `\`${value}\``; | |
context.report({ | |
node: node.property, | |
messageId: "useDot", | |
data: { | |
key: formattedValue | |
}, | |
*fix(fixer) { | |
const leftBracket = sourceCode.getTokenAfter(node.object, astUtils.isOpeningBracketToken); | |
const rightBracket = sourceCode.getLastToken(node); | |
const nextToken = sourceCode.getTokenAfter(node); | |
// Don't perform any fixes if there are comments inside the brackets. | |
if (sourceCode.commentsExistBetween(leftBracket, rightBracket)) { | |
return; | |
} | |
// Replace the brackets by an identifier. | |
if (!node.optional) { | |
yield fixer.insertTextBefore( | |
leftBracket, | |
astUtils.isDecimalInteger(node.object) ? " ." : "." | |
); | |
} | |
yield fixer.replaceTextRange( | |
[leftBracket.range[0], rightBracket.range[1]], | |
value | |
); | |
// Insert a space after the property if it will be connected to the next token. | |
if ( | |
nextToken && | |
rightBracket.range[1] === nextToken.range[0] && | |
!astUtils.canTokensBeAdjacent(String(value), nextToken) | |
) { | |
yield fixer.insertTextAfter(node, " "); | |
} | |
} | |
}); | |
} | |
} | |
return { | |
MemberExpression(node) { | |
if ( | |
node.computed && | |
node.property.type === "Literal" && | |
(literalTypesToCheck.has(typeof node.property.value) || astUtils.isNullLiteral(node.property)) | |
) { | |
checkComputedProperty(node, node.property.value); | |
} | |
if ( | |
node.computed && | |
astUtils.isStaticTemplateLiteral(node.property) | |
) { | |
checkComputedProperty(node, node.property.quasis[0].value.cooked); | |
} | |
if ( | |
!allowKeywords && | |
!node.computed && | |
node.property.type === "Identifier" && | |
keywords.includes(String(node.property.name)) | |
) { | |
context.report({ | |
node: node.property, | |
messageId: "useBrackets", | |
data: { | |
key: node.property.name | |
}, | |
*fix(fixer) { | |
const dotToken = sourceCode.getTokenBefore(node.property); | |
// A statement that starts with `let[` is parsed as a destructuring variable declaration, not a MemberExpression. | |
if (node.object.type === "Identifier" && node.object.name === "let" && !node.optional) { | |
return; | |
} | |
// Don't perform any fixes if there are comments between the dot and the property name. | |
if (sourceCode.commentsExistBetween(dotToken, node.property)) { | |
return; | |
} | |
// Replace the identifier to brackets. | |
if (!node.optional) { | |
yield fixer.remove(dotToken); | |
} | |
yield fixer.replaceText(node.property, `["${node.property.name}"]`); | |
} | |
}); | |
} | |
} | |
}; | |
} | |
}; |