Skip to content

Commit

Permalink
Use optional chaining (#1913)
Browse files Browse the repository at this point in the history
  • Loading branch information
fisker committed Sep 21, 2022
1 parent 3a1e1bc commit 550c412
Show file tree
Hide file tree
Showing 31 changed files with 61 additions and 111 deletions.
2 changes: 1 addition & 1 deletion rules/ast/is-empty-node.js
Expand Up @@ -10,7 +10,7 @@ function isEmptyNode(node, additionalEmpty) {
return true;
}

if (additionalEmpty && additionalEmpty(node)) {
if (additionalEmpty?.(node)) {
return true;
}

Expand Down
4 changes: 1 addition & 3 deletions rules/ast/is-static-require.js
Expand Up @@ -3,9 +3,7 @@
const {isStringLiteral} = require('./literal.js');

const isStaticRequire = node => Boolean(
node
&& node.type === 'CallExpression'
&& node.callee
node?.type === 'CallExpression'
&& node.callee.type === 'Identifier'
&& node.callee.name === 'require'
&& !node.optional
Expand Down
13 changes: 5 additions & 8 deletions rules/consistent-function-scoping.js
Expand Up @@ -21,7 +21,7 @@ function checkReferences(scope, parent, scopeManager) {
const [definition] = resolved.defs;

// Skip recursive function name
if (definition && definition.type === 'FunctionName' && resolved.name === definition.name.name) {
if (definition?.type === 'FunctionName' && resolved.name === definition.name.name) {
return false;
}

Expand Down Expand Up @@ -92,23 +92,20 @@ const reactHooks = [
].flatMap(hookName => [hookName, `React.${hookName}`]);

const isReactHook = scope =>
scope.block
&& scope.block.parent
&& scope.block.parent.callee
scope.block?.parent?.callee
&& isNodeMatches(scope.block.parent.callee, reactHooks);

const isArrowFunctionWithThis = scope =>
scope.type === 'function'
&& scope.block
&& scope.block.type === 'ArrowFunctionExpression'
&& scope.block?.type === 'ArrowFunctionExpression'
&& (scope.thisFound || scope.childScopes.some(scope => isArrowFunctionWithThis(scope)));

const iifeFunctionTypes = new Set([
'FunctionExpression',
'ArrowFunctionExpression',
]);
const isIife = node => node
&& iifeFunctionTypes.has(node.type)
const isIife = node =>
iifeFunctionTypes.has(node.type)
&& node.parent.type === 'CallExpression'
&& node.parent.callee === node;

Expand Down
6 changes: 3 additions & 3 deletions rules/custom-error-definition.js
Expand Up @@ -137,15 +137,15 @@ function * customErrorDefinition(context, node) {
if (!nameExpression) {
const nameProperty = body.find(node => isPropertyDefinition(node, 'name'));

if (!nameProperty || !nameProperty.value || nameProperty.value.value !== name) {
if (!nameProperty?.value || nameProperty.value.value !== name) {
yield {
node: nameProperty && nameProperty.value ? nameProperty.value : constructorBodyNode,
node: nameProperty?.value ? nameProperty.value : constructorBodyNode,
message: `The \`name\` property should be set to \`${name}\`.`,
};
}
} else if (nameExpression.expression.right.value !== name) {
yield {
node: nameExpression ? nameExpression.expression.right : constructorBodyNode,
node: nameExpression?.expression.right ?? constructorBodyNode,
message: `The \`name\` property should be set to \`${name}\`.`,
};
}
Expand Down
2 changes: 1 addition & 1 deletion rules/filename-case.js
Expand Up @@ -107,7 +107,7 @@ function splitFilename(filename) {
for (const char of tailing) {
const isIgnored = isIgnoredChar(char);

if (lastWord && lastWord.ignored === isIgnored) {
if (lastWord?.ignored === isIgnored) {
lastWord.word += char;
} else {
lastWord = {
Expand Down
8 changes: 4 additions & 4 deletions rules/no-for-loop.js
Expand Up @@ -16,7 +16,7 @@ const defaultElementName = 'element';
const isLiteralZero = node => isLiteral(node, 0);
const isLiteralOne = node => isLiteral(node, 1);

const isIdentifierWithName = (node, name) => node && node.type === 'Identifier' && node.name === name;
const isIdentifierWithName = (node, name) => node?.type === 'Identifier' && node.name === name;

const getIndexIdentifierName = forStatement => {
const {init: variableDeclaration} = forStatement;
Expand Down Expand Up @@ -103,7 +103,7 @@ const getArrayIdentifier = (forStatement, indexIdentifierName) => {
};

const isLiteralOnePlusIdentifierWithName = (node, identifierName) => {
if (node && node.type === 'BinaryExpression' && node.operator === '+') {
if (node?.type === 'BinaryExpression' && node.operator === '+') {
return (isIdentifierWithName(node.left, identifierName) && isLiteralOne(node.right))
|| (isIdentifierWithName(node.right, identifierName) && isLiteralOne(node.left));
}
Expand Down Expand Up @@ -335,8 +335,8 @@ const create = context => {

return true;
});
const elementNode = elementReference && elementReference.identifier.parent.parent;
const elementIdentifierName = elementNode && elementNode.id.name;
const elementNode = elementReference?.identifier.parent.parent;
const elementIdentifierName = elementNode?.id.name;
const elementVariable = elementIdentifierName && resolveIdentifierName(elementIdentifierName, bodyScope);

const shouldFix = !someVariablesLeakOutOfTheLoop(node, [indexVariable, elementVariable].filter(Boolean), forScope);
Expand Down
10 changes: 3 additions & 7 deletions rules/no-keyword-prefix.js
Expand Up @@ -63,7 +63,7 @@ function checkObjectPattern(report, node, options) {
report(node, keyword);
}

// Prevent checking righthand side of destructured object
// Prevent checking right hand side of destructured object
if (parent.key === node && parent.value !== node) {
return true;
}
Expand Down Expand Up @@ -113,7 +113,7 @@ const create = context => {
parent.type === 'Property'
|| parent.type === 'AssignmentPattern'
) {
if (parent.parent && parent.parent.type === 'ObjectPattern') {
if (parent.parent.type === 'ObjectPattern') {
const finished = checkObjectPattern(report, node, options);
if (finished) {
return;
Expand Down Expand Up @@ -145,11 +145,7 @@ const create = context => {
].includes(parent.type)
) {
// Report only if the local imported identifier is invalid
if (
Boolean(keyword)
&& parent.local
&& parent.local.name === name
) {
if (Boolean(keyword) && parent.local?.name === name) {
report(node, keyword);
}

Expand Down
7 changes: 2 additions & 5 deletions rules/no-thenable.js
Expand Up @@ -11,11 +11,8 @@ const messages = {
[MESSAGE_ID_CLASS]: 'Do not add `then` to a class.',
};

const isStringThen = (node, context) => {
const result = getStaticValue(node, context.getScope());

return result && result.value === 'then';
};
const isStringThen = (node, context) =>
getStaticValue(node, context.getScope())?.value === 'then';

const cases = [
// `{then() {}}`,
Expand Down
4 changes: 2 additions & 2 deletions rules/no-unsafe-regex.js
Expand Up @@ -38,12 +38,12 @@ const create = () => ({
let flags;
if (hasRegExp) {
({pattern} = arguments_[0].regex);
flags = arguments_[1] && arguments_[1].type === 'Literal'
flags = arguments_[1]?.type === 'Literal'
? arguments_[1].value
: arguments_[0].regex.flags;
} else {
pattern = arguments_[0].value;
flags = arguments_[1] && arguments_[1].type === 'Literal'
flags = arguments_[1]?.type === 'Literal'
? arguments_[1].value
: '';
}
Expand Down
6 changes: 2 additions & 4 deletions rules/no-unused-properties.js
Expand Up @@ -11,13 +11,11 @@ const getDeclaratorOrPropertyValue = declaratorOrProperty =>
|| declaratorOrProperty.value;

const isMemberExpressionCall = memberExpression =>
memberExpression.parent
&& memberExpression.parent.type === 'CallExpression'
memberExpression.parent.type === 'CallExpression'
&& memberExpression.parent.callee === memberExpression;

const isMemberExpressionAssignment = memberExpression =>
memberExpression.parent
&& memberExpression.parent.type === 'AssignmentExpression';
memberExpression.parent.type === 'AssignmentExpression';

const isMemberExpressionComputedBeyondPrediction = memberExpression =>
memberExpression.computed
Expand Down
6 changes: 3 additions & 3 deletions rules/no-useless-promise-resolve-reject.js
Expand Up @@ -101,7 +101,7 @@ function fix(callExpression, isInTryStatement, sourceCode) {
}

const {callee, parent, arguments: [errorOrValue]} = callExpression;
if (errorOrValue && errorOrValue.type === 'SpreadElement') {
if (errorOrValue?.type === 'SpreadElement') {
return;
}

Expand All @@ -122,7 +122,7 @@ function fix(callExpression, isInTryStatement, sourceCode) {

let text = errorOrValue ? sourceCode.getText(errorOrValue) : '';

if (errorOrValue && errorOrValue.type === 'SequenceExpression') {
if (errorOrValue?.type === 'SequenceExpression') {
text = `(${text})`;
}

Expand Down Expand Up @@ -155,7 +155,7 @@ function fix(callExpression, isInTryStatement, sourceCode) {
} else if (parent.type === 'ReturnStatement') {
text = `return${text ? ' ' : ''}${text};`;
} else {
if (errorOrValue && errorOrValue.type === 'ObjectExpression') {
if (errorOrValue?.type === 'ObjectExpression') {
text = `(${text})`;
}

Expand Down
3 changes: 1 addition & 2 deletions rules/no-useless-undefined.js
Expand Up @@ -63,7 +63,6 @@ const shouldIgnore = node => {
} else if (
node.type === 'MemberExpression'
&& node.computed === false
&& node.property
&& node.property.type === 'Identifier'
) {
name = node.property.name;
Expand Down Expand Up @@ -104,7 +103,7 @@ const create = context => {
const listener = (fix, checkFunctionReturnType) => node => {
if (checkFunctionReturnType) {
const functionNode = getFunction(context.getScope());
if (functionNode && functionNode.returnType) {
if (functionNode?.returnType) {
return;
}
}
Expand Down
6 changes: 2 additions & 4 deletions rules/prefer-array-find.js
Expand Up @@ -239,11 +239,10 @@ const fixDestructuringAndReplaceFilter = (sourceCode, node) => {
};

const isAccessingZeroIndex = node =>
node.parent
&& node.parent.type === 'MemberExpression'
node.parent.type === 'MemberExpression'
&& node.parent.computed === true
&& node.parent.object === node
&& node.parent.property?.type === 'Literal'
&& node.parent.property.type === 'Literal'
&& node.parent.property.raw === '0';

const isDestructuringFirstElement = node => {
Expand All @@ -252,7 +251,6 @@ const isDestructuringFirstElement = node => {
&& right
&& right === node
&& left.type === 'ArrayPattern'
&& left.elements
&& left.elements.length === 1
&& left.elements[0].type !== 'RestElement';
};
Expand Down
6 changes: 2 additions & 4 deletions rules/prefer-json-parse-buffer.js
Expand Up @@ -59,10 +59,8 @@ function getIdentifierDeclaration(node, scope) {
return getIdentifierDeclaration(identifier.parent.init, variable.scope);
}

const isUtf8EncodingStringNode = (node, scope) => {
const staticValue = getStaticValue(node, scope);
return staticValue && isUtf8EncodingString(staticValue.value);
};
const isUtf8EncodingStringNode = (node, scope) =>
isUtf8EncodingString(getStaticValue(node, scope)?.value);

const isUtf8EncodingString = value => {
if (typeof value !== 'string') {
Expand Down
25 changes: 8 additions & 17 deletions rules/prefer-keyboard-event-key.js
Expand Up @@ -15,23 +15,20 @@ const keys = new Set([
]);

const isPropertyNamedAddEventListener = node =>
node
&& node.type === 'CallExpression'
&& node.callee
node?.type === 'CallExpression'
&& node.callee.type === 'MemberExpression'
&& node.callee.property
&& node.callee.property.name === 'addEventListener';

const getEventNodeAndReferences = (context, node) => {
const eventListener = getMatchingAncestorOfType(node, 'CallExpression', isPropertyNamedAddEventListener);
const callback = eventListener && eventListener.arguments && eventListener.arguments[1];
switch (callback && callback.type) {
const callback = eventListener?.arguments[1];
switch (callback?.type) {
case 'ArrowFunctionExpression':
case 'FunctionExpression': {
const eventVariable = context.getDeclaredVariables(callback)[0];
const references = eventVariable && eventVariable.references;
const references = eventVariable?.references;
return {
event: callback.params && callback.params[0],
event: callback.params[0],
references,
};
}
Expand All @@ -43,10 +40,7 @@ const getEventNodeAndReferences = (context, node) => {
};

const isPropertyOf = (node, eventNode) =>
node
&& node.parent
&& node.parent.type === 'MemberExpression'
&& node.parent.object
node?.parent?.type === 'MemberExpression'
&& node.parent.object === eventNode;

// The third argument is a condition function, as one passed to `Array#filter()`
Expand Down Expand Up @@ -133,7 +127,7 @@ const create = context => ({

Property(node) {
// Destructured case
const propertyName = node.value && node.value.name;
const propertyName = node.value.name;
if (!keys.has(propertyName)) {
return;
}
Expand All @@ -147,10 +141,7 @@ const create = context => ({
node,
'VariableDeclarator',
);
const initObject
= nearestVariableDeclarator
&& nearestVariableDeclarator.init
&& nearestVariableDeclarator.init;
const initObject = nearestVariableDeclarator?.init;

// Make sure initObject is a reference of eventVariable
if (
Expand Down
9 changes: 3 additions & 6 deletions rules/prefer-native-coercion-functions.js
Expand Up @@ -11,13 +11,11 @@ const nativeCoercionFunctionNames = new Set(['String', 'Number', 'BigInt', 'Bool
const arrayMethodsWithBooleanCallback = new Set(['every', 'filter', 'find', 'findLast', 'findIndex', 'findLastIndex', 'some']);

const isNativeCoercionFunctionCall = (node, firstArgumentName) =>
node
&& node.type === 'CallExpression'
node?.type === 'CallExpression'
&& !node.optional
&& node.callee.type === 'Identifier'
&& nativeCoercionFunctionNames.has(node.callee.name)
&& node.arguments[0]
&& node.arguments[0].type === 'Identifier'
&& node.arguments[0]?.type === 'Identifier'
&& node.arguments[0].name === firstArgumentName;

const isIdentityFunction = node =>
Expand All @@ -33,8 +31,7 @@ const isIdentityFunction = node =>
node.body.type === 'BlockStatement'
&& node.body.body.length === 1
&& node.body.body[0].type === 'ReturnStatement'
&& node.body.body[0].argument
&& node.body.body[0].argument.type === 'Identifier'
&& node.body.body[0].argument?.type === 'Identifier'
&& node.body.body[0].argument.name === node.params[0].name
);

Expand Down
1 change: 0 additions & 1 deletion rules/prefer-negative-index.js
Expand Up @@ -54,7 +54,6 @@ const getMemberName = node => {

if (
type === 'MemberExpression'
&& property
&& property.type === 'Identifier'
) {
return property.name;
Expand Down
2 changes: 1 addition & 1 deletion rules/prefer-number-properties.js
Expand Up @@ -24,7 +24,7 @@ const globalObjects = {

const isNegative = node => {
const {parent} = node;
return parent && parent.type === 'UnaryExpression' && parent.operator === '-' && parent.argument === node;
return parent.type === 'UnaryExpression' && parent.operator === '-' && parent.argument === node;
};

function checkProperty({node, path: [name]}, sourceCode) {
Expand Down
7 changes: 2 additions & 5 deletions rules/prefer-prototype-methods.js
Expand Up @@ -51,11 +51,8 @@ function create(context) {
yield fixer.replaceText(node.object, `${constructorName}.prototype`);

if (
node.object
&& (
node.object.type === 'ArrayExpression'
|| node.object.type === 'ObjectExpression'
)
node.object.type === 'ArrayExpression'
|| node.object.type === 'ObjectExpression'
) {
yield * fixSpaceAroundKeyword(fixer, node.parent.parent, context.getSourceCode());
}
Expand Down

0 comments on commit 550c412

Please sign in to comment.