no-arrow-functions.js 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. /**
  2. * @author Toru Nagashima <https://github.com/mysticatea>
  3. * See LICENSE file in root directory for full license.
  4. */
  5. "use strict"
  6. const { isArrowToken } = require("eslint-utils")
  7. module.exports = {
  8. meta: {
  9. docs: {
  10. description: "disallow arrow function expressions.",
  11. category: "ES2015",
  12. recommended: false,
  13. url:
  14. "http://mysticatea.github.io/eslint-plugin-es/rules/no-arrow-functions.html",
  15. },
  16. fixable: "code",
  17. schema: [],
  18. messages: {
  19. forbidden: "ES2015 arrow function expressions are forbidden.",
  20. },
  21. },
  22. create(context) {
  23. const sourceCode = context.getSourceCode()
  24. /**
  25. * ArrowFunctionExpression to FunctionExpression
  26. * @param {Node} node ArrowFunctionExpression Node
  27. * @returns {string} function expression text
  28. */
  29. function toFunctionExpression(node) {
  30. const params = node.params
  31. const paramText = params.length
  32. ? sourceCode.text.slice(
  33. params[0].range[0],
  34. params[params.length - 1].range[1]
  35. )
  36. : ""
  37. const arrowToken = sourceCode.getTokenBefore(
  38. node.body,
  39. isArrowToken
  40. )
  41. const preText = sourceCode.text.slice(
  42. arrowToken.range[1],
  43. node.body.range[0]
  44. )
  45. const bodyText = sourceCode.text.slice(
  46. arrowToken.range[1],
  47. node.range[1]
  48. )
  49. if (node.body.type === "BlockStatement") {
  50. return `function(${paramText})${bodyText}`
  51. }
  52. if (preText.includes("\n")) {
  53. return `function(${paramText}){return(${bodyText})}`
  54. }
  55. return `function(${paramText}){return ${bodyText}}`
  56. }
  57. /**
  58. * Report that ArrowFunctionExpression is being used
  59. * @param {Node} node ArrowFunctionExpression Node
  60. * @param {boolean} hasThis Whether `this` is referenced in` function` scope
  61. * @param {boolean} hasSuper Whether `super` is referenced in` function` scope
  62. * @returns {void}
  63. */
  64. function report(node, hasThis, hasSuper) {
  65. context.report({
  66. node,
  67. messageId: "forbidden",
  68. fix(fixer) {
  69. if (hasSuper) {
  70. return undefined
  71. }
  72. const functionText = toFunctionExpression(node)
  73. return fixer.replaceText(
  74. node,
  75. hasThis ? `${functionText}.bind(this)` : functionText
  76. )
  77. },
  78. })
  79. }
  80. let stack = { upper: null, hasThis: false, hasSuper: false }
  81. return {
  82. ":function"() {
  83. stack = { upper: stack, hasThis: false, hasSuper: false }
  84. },
  85. ":function:exit"(node) {
  86. const { hasThis, hasSuper } = stack
  87. stack = stack.upper
  88. if (node.type === "ArrowFunctionExpression") {
  89. report(node, hasThis, hasSuper)
  90. stack.hasThis = stack.hasThis || hasThis
  91. stack.hasSuper = stack.hasSuper || hasSuper
  92. }
  93. },
  94. ThisExpression() {
  95. stack.hasThis = true
  96. },
  97. Super() {
  98. stack.hasSuper = true
  99. },
  100. }
  101. },
  102. }