text: /**
   * @fileoverview Prevent usage of unsafe lifecycle methods
   * @author Sergei Startsev
   */
  
  'use strict';
  
  const Components = require('../util/Components');
  const astUtil = require('../util/ast');
  const docsUrl = require('../util/docsUrl');
  const versionUtil = require('../util/version');
  const report = require('../util/report');
  
  // ------------------------------------------------------------------------------
  // Rule Definition
  // ------------------------------------------------------------------------------
  
  const messages = {
    unsafeMethod: '{{method}} is unsafe for use in async rendering. Update the component to use {{newMethod}} instead. {{details}}',
  };
  
  module.exports = {
    meta: {
      docs: {
        description: 'Prevent usage of unsafe lifecycle methods',
        category: 'Best Practices',
        recommended: false,
        url: docsUrl('no-unsafe'),
      },
  
      messages,
  
      schema: [
        {
          type: 'object',
          properties: {
            checkAliases: {
              default: false,
              type: 'boolean',
            },
          },
          additionalProperties: false,
        },
      ],
    },
  
    create: Components.detect((context, components, utils) => {
      const config = context.options[0] || {};
      const checkAliases = config.checkAliases || false;
  
      const isApplicable = versionUtil.testReactVersion(context, '16.3.0');
      if (!isApplicable) {
        return {};
      }
  
      const unsafe = {
        UNSAFE_componentWillMount: {
          newMethod: 'componentDidMount',
          details:
            'See https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html.',
        },
        UNSAFE_componentWillReceiveProps: {
          newMethod: 'getDerivedStateFromProps',
          details:
            'See https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html.',
        },
        UNSAFE_componentWillUpdate: {
          newMethod: 'componentDidUpdate',
          details:
            'See https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html.',
        },
      };
      if (checkAliases) {
        unsafe.componentWillMount = unsafe.UNSAFE_componentWillMount;
        unsafe.componentWillReceiveProps = unsafe.UNSAFE_componentWillReceiveProps;
        unsafe.componentWillUpdate = unsafe.UNSAFE_componentWillUpdate;
      }
  
      /**
       * Returns a list of unsafe methods
       * @returns {Array} A list of unsafe methods
       */
      function getUnsafeMethods() {
        return Object.keys(unsafe);
      }
  
      /**
       * Checks if a passed method is unsafe
       * @param {string} method Life cycle method
       * @returns {boolean} Returns true for unsafe methods, otherwise returns false
       */
      function isUnsafe(method) {
        const unsafeMethods = getUnsafeMethods();
        return unsafeMethods.indexOf(method) !== -1;
      }
  
      /**
       * Reports the error for an unsafe method
       * @param {ASTNode} node The AST node being checked
       * @param {string} method Life cycle method
       */
      function checkUnsafe(node, method) {
        if (!isUnsafe(method)) {
          return;
        }
  
        const meta = unsafe[method];
        const newMethod = meta.newMethod;
        const details = meta.details;
  
        report(context, messages.unsafeMethod, 'unsafeMethod', {
          node,
          data: {
            method,
            newMethod,
            details,
          },
        });
      }
  
      /**
       * Returns life cycle methods if available
       * @param {ASTNode} node The AST node being checked.
       * @returns {Array} The array of methods.
       */
      function getLifeCycleMethods(node) {
        const properties = astUtil.getComponentProperties(node);
        return properties.map((property) => astUtil.getPropertyName(property));
      }
  
      /**
       * Checks life cycle methods
       * @param {ASTNode} node The AST node being checked.
       */
      function checkLifeCycleMethods(node) {
        if (utils.isES5Component(node) || utils.isES6Component(node)) {
          const methods = getLifeCycleMethods(node);
          methods.forEach((method) => checkUnsafe(node, method));
        }
      }
  
      return {
        ClassDeclaration: checkLifeCycleMethods,
        ClassExpression: checkLifeCycleMethods,
        ObjectExpression: checkLifeCycleMethods,
      };
    }),
  };
  