fetch-block.js 3.92 KB
Newer Older
陈帅's avatar
陈帅 committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
const parser = require('@babel/parser');
const traverse = require('@babel/traverse');
const generate = require('@babel/generator');
const t = require('@babel/types');
const path = require('path');
const fs = require('fs');
const exec = require('child_process').exec;

const prettier = require('prettier');

const router = require('./router.config');

const getNewRouteCode = (configPath, newRoute, absSrcPath) => {
  const ast = parser.parse(fs.readFileSync(configPath, 'utf-8'), {
    sourceType: 'module',
    plugins: ['typescript'],
  });
  let routesNode = null;
  const importModules = [];
  // 查询当前配置文件是否导出 routes 属性
  traverse.default(ast, {
    Program({ node }) {
      // find import
      const { body } = node;
      body.forEach(item => {
        if (t.isImportDeclaration(item)) {
          const { specifiers } = item;
          const defaultEpecifier = specifiers.find(s => {
            return t.isImportDefaultSpecifier(s) && t.isIdentifier(s.local);
          });
          if (defaultEpecifier && t.isStringLiteral(item.source)) {
            importModules.push({
              identifierName: defaultEpecifier.local.name,
              modulePath: item.source.value,
            });
          }
        }
      });
    },
    ObjectExpression({ node, parent }) {
      // find routes on object, like { routes: [] }
      if (t.isArrayExpression(parent)) {
        // children routes
        return;
      }
      const { properties } = node;
      properties.forEach(p => {
        const { key, value } = p;
        if (t.isObjectProperty(p) && t.isIdentifier(key) && key.name === 'routes') {
          if (value) {
            // find json file program expression
            (p.value = parser.parse(JSON.stringify(newRoute)).program.body[0].expression),
              (routesNode = value);
          }
        }
      });
    },
  });
  if (routesNode) {
    const code = generateCode(ast);
    return { code, routesPath: configPath };
  } else {
    throw new Error('route array config not found.');
  }
};

/**
 * 生成代码
 * @param {*} ast
 */
function generateCode(ast) {
  const newCode = generate.default(ast, {}).code;
  return prettier.format(newCode, {
    // format same as ant-design-pro
    singleQuote: true,
    trailingComma: 'es5',
    printWidth: 100,
    parser: 'typescript',
  });
}

const relativePath = path.join(__dirname, '../config/config.ts');

const filterParentRouter = router => {
  return [...router]
    .map(item => {
      if (item.routes) {
        return { ...item, routes: filterParentRouter(item.routes) };
      }
      return null;
    })
    .filter(item => item);
};
const parentRouter = filterParentRouter(router);
const { routesPath, code } = getNewRouteCode(relativePath, parentRouter);
// write ParentRouter
fs.writeFileSync(routesPath, code);

const findAllInstallRouter = router => {
  let routers = [];
  router.forEach(item => {
    if (item.routes) {
      routers = routers.concat(findAllInstallRouter(item.routes));
    }
    if (item.component && item.path) {
      if (item.path === '/user' || item.path === '/') {
        return;
      }
      routers.push({
        ...item,
        routes: '',
      });
    }
    return null;
  });
  return routers;
};

const installRouters = findAllInstallRouter(router);
let i = 0;
const firstUpperCase = pathString => {
  return pathString
    .split(/\/|\-/)
    .map(s => s.toLowerCase().replace(/( |^)[a-z]/g, L => L.toUpperCase()))
    .filter(s => s)
    .join('');
};
const installBlock = () => {
  const item = installRouters[i];

  if (!item || !item.path) {
    return;
  }
  console.log('install  ' + item.name + '   to:  ' + item.component);

  const cmd = `umi block add https://github.com/ant-design/pro-blocks/tree/master/${firstUpperCase(
    item.path,
  )} --npm-client=cnpm   --path=${item.path}`;
  exec(cmd, { encoding: 'utf8' }, (error, statusbar) => {
    if (error) console.log(error);
    i += 1;
    installBlock();
  });
};
installBlock();