"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = void 0;

function _react() {
  const data = _interopRequireDefault(require("react"));

  _react = function _react() {
    return data;
  };

  return data;
}

function _assert() {
  const data = _interopRequireDefault(require("assert"));

  _assert = function _assert() {
    return data;
  };

  return data;
}

function _umiUtils() {
  const data = require("umi-utils");

  _umiUtils = function _umiUtils() {
    return data;
  };

  return data;
}

function t() {
  const data = _interopRequireWildcard(require("@babel/types"));

  t = function t() {
    return data;
  };

  return data;
}

var _util = require("../util");

var _constants = require("../constants");

function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function _getRequireWildcardCache() { return cache; }; return cache; }

function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

var _default = () => {
  function buildGUmiUIFlag(opts) {
    const index = opts.index,
          filename = opts.filename,
          jsx = opts.jsx,
          inline = opts.inline,
          content = opts.content;

    if (jsx) {
      const attrs = [t().jsxAttribute(t().jsxIdentifier('filename'), t().stringLiteral(`${filename}`)), t().jsxAttribute(t().jsxIdentifier('index'), t().stringLiteral(`${index}`))];

      if (inline) {
        attrs.push(t().jsxAttribute(t().jsxIdentifier('inline'), t().stringLiteral('true')));
      }

      return t().jsxElement(t().jsxOpeningElement(t().jsxIdentifier('GUmiUIFlag'), attrs), t().jsxClosingElement(t().jsxIdentifier('GUmiUIFlag')), content ? [t().jsxText(content)] : [], false);
    } else {
      const attrs = [t().objectProperty(t().identifier('filename'), t().stringLiteral(`${filename}`)), t().objectProperty(t().identifier('index'), t().stringLiteral(`${index}`))];

      if (inline) {
        attrs.push(t().objectProperty(t().identifier('inline'), t().stringLiteral('true')));
      }

      return t().callExpression(t().memberExpression(t().identifier('React'), t().identifier('createElement')), [t().identifier('GUmiUIFlag'), t().objectExpression(attrs), ...(content ? [t().stringLiteral(content)] : [])]);
    }
  }

  function addFlagToIndex(nodes, i, {
    index,
    filename,
    jsx
  }) {
    nodes.splice(i, 0, buildGUmiUIFlag({
      index,
      filename,
      jsx
    }));
  }

  function addUmiUIFlag(node, {
    filename,
    replace
  }) {
    if ((0, _util.isJSXElement)(node)) {
      if ((0, _util.isChildFunc)(node)) {
        return;
      }

      if ((0, _util.haveChildren)(node)) {
        if (t().isJSXElement(node) || t().isJSXFragment(node)) {
          let index = node.children.filter(n => (0, _util.isJSXElement)(n)).length;
          let i = node.children.length - 1;

          while (i >= 0) {
            const child = node.children[i];

            if ((0, _util.isJSXElement)(child) || i === 0) {
              addFlagToIndex(node.children, i === 0 ? i : i + 1, {
                index,
                filename,
                jsx: true
              });
              index -= 1;
            }

            i -= 1;
          }
        } else {
          const args = node.arguments;
          let index = args.filter(n => (0, _util.isReactCreateElement)(n)).length;
          let i = args.length - 1;

          while (i >= 1) {
            const arg = args[i];

            if ((0, _util.isReactCreateElement)(arg) || i === 1) {
              addFlagToIndex(args, i + 1, {
                index,
                filename,
                jsx: false
              });
              index -= 1;
            }

            i -= 1;
          }
        }
      } else {
        // root 节点没有 children，则在外面套一层
        replace(t().isJSXElement(node) ? t().jsxFragment(t().jsxOpeningFragment(), t().jsxClosingFragment(), [buildGUmiUIFlag({
          index: 0,
          filename,
          jsx: true
        }), node, buildGUmiUIFlag({
          index: 1,
          filename,
          jsx: true
        })]) : t().callExpression(t().memberExpression(t().identifier('React'), t().identifier('createElement')), [t().memberExpression(t().identifier('React'), t().identifier('Fragment')), t().nullLiteral(), buildGUmiUIFlag({
          index: 0,
          filename,
          jsx: false
        }), node, buildGUmiUIFlag({
          index: 1,
          filename,
          jsx: false
        })]));
      }
    } else {// throw new Error(`Add umi ui flag failed, unsupported node type ${node.type}.`);
    }
  }

  function isInBlackList(node, path) {
    if (t().isJSXElement(node)) {
      const name = node.openingElement.name.name;

      if (path.scope.hasBinding(name)) {
        const p = path.scope.getBinding(name).path;
        const source = p.parentPath.node.source; // 只处理 import 的声明

        if (!t().isImportDeclaration(p.parentPath.node)) return;

        if (source.value === 'react-document-title') {
          return true;
        } // antd 和 @alipay/tech-ui 里除部分用于布局的组件之外，其他组件作为根组件不会插入编辑区


        if ((source.value === 'antd' || source.value === '@alipay/bigfish/antd') && t().isImportSpecifier(p.node) && t().isIdentifier(p.node.imported) && !['Card', 'Grid', 'Layout'].includes(p.node.imported.name)) {
          return true;
        }

        if (source.value === '@alipay/tech-ui' && t().isImportSpecifier(p.node) && t().isIdentifier(p.node.imported) && !['PageContainer'].includes(p.node.imported.name)) {
          return true;
        }
      }
    }
  }

  let layoutIndexByFilename = {};
  return {
    visitor: {
      Program: {
        enter(path, state) {
          // hmr 时会重复编译相同文件
          layoutIndexByFilename = {};
          const filename = state.filename,
                _state$opts = state.opts,
                opts = _state$opts === void 0 ? {} : _state$opts;
          (0, _assert().default)(opts.doTransform, 'opts.doTransform must supplied');
          if (!opts.doTransform(filename)) return;
          const node = path.node;
          let d = (0, _util.findExportDefaultDeclaration)(node); // Support hoc

          while (t().isCallExpression(d)) {
            // eslint-disable-next-line
            d = d.arguments[0];
          }

          d = (0, _util.getIdentifierDeclaration)(d, path); // Support hoc again

          while (t().isCallExpression(d)) {
            // eslint-disable-next-line
            d = d.arguments[0];
          }

          const ret = (0, _util.getReturnNode)(d, path);

          if (ret) {
            const retNode = ret.node,
                  replace = ret.replace;

            if (retNode && !isInBlackList(retNode, path)) {
              addUmiUIFlag(retNode, {
                filename: (0, _umiUtils().winPath)(filename),
                replace
              });
            }
          }
        }

      },

      CallExpression(path, state) {
        const filename = state.filename,
              _state$opts2 = state.opts,
              opts = _state$opts2 === void 0 ? {} : _state$opts2; // 不限于路由组件，因为添加进来的区块不是路由组件
        // assert(opts.doTransform, 'opts.doTransform must supplied');
        // if (!opts.doTransform(filename)) return;

        const node = path.node;
        const callee = node.callee,
              args = node.arguments; // e.g.
        // _react.default.createElement("div", null, "INSERT_BLOCK_PLACEHOLDER")

        if (t().isStringLiteral(args[2]) && args[2].value.startsWith(_constants.INSERT_BLOCK_PLACEHOLDER) && t().isMemberExpression(callee) && t().isIdentifier(callee.property, {
          name: 'createElement'
        })) {
          if (!layoutIndexByFilename[filename]) {
            layoutIndexByFilename[filename] = 0;
          }

          const index = layoutIndexByFilename[filename];
          let content = null;

          if (args[2].value.startsWith(`${_constants.INSERT_BLOCK_PLACEHOLDER}:`)) {
            content = args[2].value.replace(`${_constants.INSERT_BLOCK_PLACEHOLDER}:`, '');
          }

          args[2] = buildGUmiUIFlag({
            index: `${_constants.BLOCK_LAYOUT_PREFIX}${index}`,
            filename: (0, _umiUtils().winPath)(filename),
            jsx: false,
            inline: true,
            content
          });
          layoutIndexByFilename[filename] += 1;
        } // _react.default.createElement(_umi.UmiUIFlag, null)


        if (t().isMemberExpression(callee) && t().isIdentifier(callee.property, {
          name: 'createElement'
        }) && t().isIdentifier(args[0]) && args[0].name === _constants.UMI_UI_FLAG_PLACEHOLDER) {
          if (!layoutIndexByFilename[filename]) {
            layoutIndexByFilename[filename] = 0;
          }

          const index = layoutIndexByFilename[filename];
          let content = null;
          let inline = false;

          if (t().isObjectExpression(args[1]) && args[1].properties.some(property => {
            var _property$key, _property$value;

            return t().isProperty(property) && ((_property$key = property.key) === null || _property$key === void 0 ? void 0 : _property$key.name) === 'inline' && ((_property$value = property.value) === null || _property$value === void 0 ? void 0 : _property$value.value) === true;
          })) {
            inline = true;
          }

          path.replaceWith(buildGUmiUIFlag({
            index: `${_constants.BLOCK_LAYOUT_PREFIX}${index}`,
            filename: (0, _umiUtils().winPath)(filename),
            jsx: false,
            inline,
            content
          }));
          layoutIndexByFilename[filename] += 1;
        }
      }

    }
  };
};

exports.default = _default;