123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152 |
- 'use strict';
- const {getStaticValue} = require('eslint-utils');
- // Copied from https://github.com/eslint/eslint/blob/c3e9accce2f61b04ab699fd37c90703305281aa3/lib/rules/utils/ast-utils.js#L379
- /**
- Gets the property name of a given node.
- The node can be a MemberExpression, a Property, or a MethodDefinition.
- If the name is dynamic, this returns `null`.
- For examples:
- a.b // => "b"
- a["b"] // => "b"
- a['b'] // => "b"
- a[`b`] // => "b"
- a[100] // => "100"
- a[b] // => null
- a["a" + "b"] // => null
- a[tag`b`] // => null
- a[`${b}`] // => null
- let a = {b: 1} // => "b"
- let a = {["b"]: 1} // => "b"
- let a = {['b']: 1} // => "b"
- let a = {[`b`]: 1} // => "b"
- let a = {[100]: 1} // => "100"
- let a = {[b]: 1} // => null
- let a = {["a" + "b"]: 1} // => null
- let a = {[tag`b`]: 1} // => null
- let a = {[`${b}`]: 1} // => null
- @param {ASTNode} node The node to get.
- @returns {string|undefined} The property name if static. Otherwise, undefined.
- */
- function getStaticPropertyName(node) {
- let property;
- switch (node && node.type) {
- case 'MemberExpression':
- property = node.property;
- break;
- /* istanbul ignore next: Hard to test */
- case 'ChainExpression':
- return getStaticPropertyName(node.expression);
- /* istanbul ignore next: Only reachable when use this to get class/object member key */
- case 'Property':
- case 'MethodDefinition':
- /* istanbul ignore next */
- property = node.key;
- /* istanbul ignore next */
- break;
- // No default
- }
- if (property) {
- if (property.type === 'Identifier' && !node.computed) {
- return property.name;
- }
- const staticResult = getStaticValue(property);
- if (!staticResult) {
- return;
- }
- return String(staticResult.value);
- }
- }
- /**
- Check if two literal nodes are the same value.
- @param {ASTNode} left The Literal node to compare.
- @param {ASTNode} right The other Literal node to compare.
- @returns {boolean} `true` if the two literal nodes are the same value.
- */
- function equalLiteralValue(left, right) {
- // RegExp literal.
- if (left.regex || right.regex) {
- return Boolean(
- left.regex
- && right.regex
- && left.regex.pattern === right.regex.pattern
- && left.regex.flags === right.regex.flags,
- );
- }
- // BigInt literal.
- if (left.bigint || right.bigint) {
- return left.bigint === right.bigint;
- }
- return left.value === right.value;
- }
- /**
- Check if two expressions reference the same value. For example:
- a = a
- a.b = a.b
- a[0] = a[0]
- a['b'] = a['b']
- @param {ASTNode} left The left side of the comparison.
- @param {ASTNode} right The right side of the comparison.
- @returns {boolean} `true` if both sides match and reference the same value.
- */
- function isSameReference(left, right) {
- if (left.type !== right.type) {
- // Handle `a.b` and `a?.b` are samely.
- if (left.type === 'ChainExpression') {
- return isSameReference(left.expression, right);
- }
- if (right.type === 'ChainExpression') {
- return isSameReference(left, right.expression);
- }
- return false;
- }
- switch (left.type) {
- case 'Super':
- case 'ThisExpression':
- return true;
- case 'Identifier':
- return left.name === right.name;
- case 'Literal':
- return equalLiteralValue(left, right);
- case 'ChainExpression':
- return isSameReference(left.expression, right.expression);
- case 'MemberExpression': {
- const nameA = getStaticPropertyName(left);
- // X.y = x["y"]
- return (
- typeof nameA !== 'undefined'
- && isSameReference(left.object, right.object)
- && nameA === getStaticPropertyName(right)
- );
- }
- default:
- return false;
- }
- }
- module.exports = isSameReference;
|