no-await-expression-member.js 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. 'use strict';
  2. const {
  3. removeParentheses,
  4. removeMemberExpressionProperty,
  5. } = require('./fix/index.js');
  6. const {isLiteral} = require('./ast/index.js');
  7. const MESSAGE_ID = 'no-await-expression-member';
  8. const messages = {
  9. [MESSAGE_ID]: 'Do not access a member directly from an await expression.',
  10. };
  11. /** @param {import('eslint').Rule.RuleContext} context */
  12. const create = context => {
  13. const sourceCode = context.getSourceCode();
  14. return {
  15. 'MemberExpression[object.type="AwaitExpression"]'(memberExpression) {
  16. const {property} = memberExpression;
  17. const problem = {
  18. node: property,
  19. messageId: MESSAGE_ID,
  20. };
  21. // `const foo = (await bar)[0]`
  22. if (
  23. memberExpression.computed
  24. && !memberExpression.optional
  25. && (isLiteral(property, 0) || isLiteral(property, 1))
  26. && memberExpression.parent.type === 'VariableDeclarator'
  27. && memberExpression.parent.init === memberExpression
  28. && memberExpression.parent.id.type === 'Identifier'
  29. && !memberExpression.parent.id.typeAnnotation
  30. ) {
  31. problem.fix = function * (fixer) {
  32. const variable = memberExpression.parent.id;
  33. yield fixer.insertTextBefore(variable, property.value === 0 ? '[' : '[, ');
  34. yield fixer.insertTextAfter(variable, ']');
  35. yield removeMemberExpressionProperty(fixer, memberExpression, sourceCode);
  36. yield * removeParentheses(memberExpression.object, fixer, sourceCode);
  37. };
  38. return problem;
  39. }
  40. // `const foo = (await bar).foo`
  41. if (
  42. !memberExpression.computed
  43. && !memberExpression.optional
  44. && property.type === 'Identifier'
  45. && memberExpression.parent.type === 'VariableDeclarator'
  46. && memberExpression.parent.init === memberExpression
  47. && memberExpression.parent.id.type === 'Identifier'
  48. && memberExpression.parent.id.name === property.name
  49. && !memberExpression.parent.id.typeAnnotation
  50. ) {
  51. problem.fix = function * (fixer) {
  52. const variable = memberExpression.parent.id;
  53. yield fixer.insertTextBefore(variable, '{');
  54. yield fixer.insertTextAfter(variable, '}');
  55. yield removeMemberExpressionProperty(fixer, memberExpression, sourceCode);
  56. yield * removeParentheses(memberExpression.object, fixer, sourceCode);
  57. };
  58. return problem;
  59. }
  60. return problem;
  61. },
  62. };
  63. };
  64. /** @type {import('eslint').Rule.RuleModule} */
  65. module.exports = {
  66. create,
  67. meta: {
  68. type: 'suggestion',
  69. docs: {
  70. description: 'Disallow member access from await expression.',
  71. },
  72. fixable: 'code',
  73. messages,
  74. },
  75. };