Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
// it is x!?.[y].z
suggest.push({
messageId: 'suggestOptionalChain',
fix: removeToken(),
});
} else {
// it is x!?.y.z
suggest.push({
messageId: 'suggestOptionalChain',
fix: removeToken(),
});
}
}
} else if (
(node.parent.type === AST_NODE_TYPES.CallExpression ||
node.parent.type === AST_NODE_TYPES.OptionalCallExpression) &&
node.parent.callee === node
) {
if (!node.parent.optional) {
// it is x.y?.z!()
suggest.push({
messageId: 'suggestOptionalChain',
fix: convertTokenToOptional('?.'),
});
} else {
// it is x.y.z!?.()
suggest.push({
messageId: 'suggestOptionalChain',
fix: removeToken(),
});
}
}
function isFunctionArgument(
parent: TSESTree.Node,
callee?: TSESTree.ArrowFunctionExpression | TSESTree.FunctionExpression,
): boolean {
return (
(parent.type === AST_NODE_TYPES.CallExpression ||
parent.type === AST_NODE_TYPES.OptionalCallExpression) &&
// make sure this isn't an IIFE
parent.callee !== callee
);
}
function isOptionalOptionalChain(
node: TSESTree.Node,
): node is TSESTree.OptionalCallExpression {
return (
node.type === AST_NODE_TYPES.OptionalCallExpression &&
// this flag means the call expression itself is option
// i.e. it is foo.bar?.() and not foo?.bar()
node.optional
);
}
isValidChainTarget(node.object, true);
const isPropertyValid = node.computed
? ALLOWED_COMPUTED_PROP_TYPES.has(node.property.type) &&
// make sure to validate the member expression is of our expected structure
(node.property.type === AST_NODE_TYPES.MemberExpression ||
node.property.type === AST_NODE_TYPES.OptionalMemberExpression
? isValidChainTarget(node.property, allowIdentifier)
: true)
: ALLOWED_NON_COMPUTED_PROP_TYPES.has(node.property.type);
return isObjectValid && isPropertyValid;
}
if (
node.type === AST_NODE_TYPES.CallExpression ||
node.type === AST_NODE_TYPES.OptionalCallExpression
) {
return isValidChainTarget(node.callee, allowIdentifier);
}
if (
allowIdentifier &&
(node.type === AST_NODE_TYPES.Identifier ||
node.type === AST_NODE_TYPES.ThisExpression)
) {
return true;
}
/*
special case for the following, where we only want the left
- foo !== null
- foo != null
function isFunctionCall(
init: TSESTree.Expression,
callName: string,
): boolean {
return (
(init.type === AST_NODE_TYPES.CallExpression ||
init.type === AST_NODE_TYPES.OptionalCallExpression) &&
init.callee.type === AST_NODE_TYPES.Identifier &&
init.callee.name === callName
);
}
function isLiteral(init: TSESTree.Expression, typeName: string): boolean {
'CallExpression, OptionalCallExpression'(
node: TSESTree.CallExpression | TSESTree.OptionalCallExpression,
): void {
if (
node.callee.type === AST_NODE_TYPES.Identifier &&
node.callee.name === 'require' &&
node.parent &&
(node.parent.type === AST_NODE_TYPES.VariableDeclarator ||
node.parent.type === AST_NODE_TYPES.CallExpression ||
node.parent.type === AST_NODE_TYPES.OptionalCallExpression)
) {
context.report({
node,
messageId: 'noVarReqs',
});
}
},
};
argNode.type !== AST_NODE_TYPES.TemplateLiteral &&
argNode.type !== AST_NODE_TYPES.Identifier &&
argNode.type !== AST_NODE_TYPES.MemberExpression &&
argNode.type !== AST_NODE_TYPES.OptionalMemberExpression &&
argNode.type !== AST_NODE_TYPES.CallExpression &&
argNode.type !== AST_NODE_TYPES.OptionalCallExpression;
yield fixer.removeRange([callNode.range[0], argNode.range[0]]);
if (needsParen) {
yield fixer.insertTextBefore(argNode, '(');
yield fixer.insertTextAfter(argNode, ')');
}
yield fixer.insertTextAfter(
argNode,
`${
callNode.type === AST_NODE_TYPES.OptionalCallExpression
? '?.'
: '.'
}includes(${JSON.stringify(text)}`,
);
},
});
function isSafeUse(node: TSESTree.Node): boolean {
const parent = node.parent!;
switch (parent.type) {
case AST_NODE_TYPES.IfStatement:
case AST_NODE_TYPES.ForStatement:
case AST_NODE_TYPES.MemberExpression:
case AST_NODE_TYPES.OptionalMemberExpression:
case AST_NODE_TYPES.SwitchStatement:
case AST_NODE_TYPES.UpdateExpression:
case AST_NODE_TYPES.WhileStatement:
return true;
case AST_NODE_TYPES.CallExpression:
case AST_NODE_TYPES.OptionalCallExpression:
return parent.callee === node;
case AST_NODE_TYPES.ConditionalExpression:
return parent.test === node;
case AST_NODE_TYPES.LogicalExpression:
return parent.operator !== '||';
case AST_NODE_TYPES.TaggedTemplateExpression:
return parent.tag === node;
case AST_NODE_TYPES.UnaryExpression:
return parent.operator === 'typeof';
case AST_NODE_TYPES.BinaryExpression:
return ['instanceof', '==', '!=', '===', '!=='].includes(parent.operator);
*fix(fixer) {
const argNode = callNode.arguments[0];
const needsParen =
argNode.type !== AST_NODE_TYPES.Literal &&
argNode.type !== AST_NODE_TYPES.TemplateLiteral &&
argNode.type !== AST_NODE_TYPES.Identifier &&
argNode.type !== AST_NODE_TYPES.MemberExpression &&
argNode.type !== AST_NODE_TYPES.OptionalMemberExpression &&
argNode.type !== AST_NODE_TYPES.CallExpression &&
argNode.type !== AST_NODE_TYPES.OptionalCallExpression;
yield fixer.removeRange([callNode.range[0], argNode.range[0]]);
if (needsParen) {
yield fixer.insertTextBefore(argNode, '(');
yield fixer.insertTextAfter(argNode, ')');
}
yield fixer.insertTextAfter(
argNode,
`${
callNode.type === AST_NODE_TYPES.OptionalCallExpression
? '?.'
: '.'
}includes(${JSON.stringify(text)}`,
);
},
});
node: TSESTree.TSTypeAssertion | TSESTree.TSAsExpression,
): void {
if (
options.assertionStyle === 'never' ||
options.objectLiteralTypeAssertions === 'allow' ||
node.expression.type !== AST_NODE_TYPES.ObjectExpression
) {
return;
}
if (
options.objectLiteralTypeAssertions === 'allow-as-parameter' &&
node.parent &&
(node.parent.type === AST_NODE_TYPES.NewExpression ||
node.parent.type === AST_NODE_TYPES.CallExpression ||
node.parent.type === AST_NODE_TYPES.OptionalCallExpression ||
node.parent.type === AST_NODE_TYPES.ThrowStatement ||
node.parent.type === AST_NODE_TYPES.AssignmentPattern)
) {
return;
}
if (
checkType(node.typeAnnotation) &&
node.expression.type === AST_NODE_TYPES.ObjectExpression
) {
context.report({
node,
messageId: 'unexpectedObjectTypeAssertion',
});
}
}