You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

332 lines
8.6 KiB

"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.writeNewRoute = writeNewRoute;
exports.getNewRouteCode = getNewRouteCode;
exports.writeRouteNode = writeRouteNode;
function _react() {
const data = _interopRequireDefault(require("react"));
_react = function _react() {
return data;
};
return data;
}
function _fs() {
const data = require("fs");
_fs = function _fs() {
return data;
};
return data;
}
function _path() {
const data = require("path");
_path = function _path() {
return data;
};
return data;
}
function parser() {
const data = _interopRequireWildcard(require("@babel/parser"));
parser = function parser() {
return data;
};
return data;
}
function _traverse() {
const data = _interopRequireDefault(require("@babel/traverse"));
_traverse = function _traverse() {
return data;
};
return data;
}
function _generator() {
const data = _interopRequireDefault(require("@babel/generator"));
_generator = function _generator() {
return data;
};
return data;
}
function t() {
const data = _interopRequireWildcard(require("@babel/types"));
t = function t() {
return data;
};
return data;
}
function _utils() {
const data = require("@umijs/utils");
_utils = function _utils() {
return data;
};
return data;
}
function _prettier() {
const data = _interopRequireDefault(require("prettier"));
_prettier = function _prettier() {
return data;
};
return data;
}
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 }; }
const debug = (0, _utils().createDebug)('umi-build-dev:writeNewRoute');
/**
* 将路由写入路由文件
* @param {*} newRoute 新的路由配置: { path, component, ... }
* @param {*} configPath 配置路径
* @param {*} absSrcPath 代码路径
*/
function writeNewRoute(newRoute, configPath, absSrcPath) {
const _getNewRouteCode = getNewRouteCode(configPath, newRoute, absSrcPath),
code = _getNewRouteCode.code,
routesPath = _getNewRouteCode.routesPath;
(0, _fs().writeFileSync)(routesPath, code, 'utf-8');
}
/**
* 获取目标
* @param {*} configPath
* @param {*} newRoute
*/
function getNewRouteCode(configPath, newRoute, absSrcPath) {
debug(`find routes in configPath: ${configPath}`);
const ast = parser().parse((0, _fs().readFileSync)(configPath, 'utf-8'), {
sourceType: 'module',
plugins: ['typescript']
});
let routesNode = null;
const importModules = []; // 查询当前配置文件是否导出 routes 属性
(0, _traverse().default)(ast, {
Program({
node
}) {
// find import
const body = node.body;
body.forEach(item => {
if (t().isImportDeclaration(item)) {
const specifiers = item.specifiers;
const defaultEpecifier = specifiers.find(s => t().isImportDefaultSpecifier(s) && t().isIdentifier(s.local));
if (defaultEpecifier && t().isStringLiteral(item.source)) {
importModules.push({
identifierName: defaultEpecifier.local.name,
modulePath: item.source.value
});
}
}
});
},
AssignmentExpression({
node
}) {
// for exports.routes
const left = node.left,
operator = node.operator,
right = node.right;
if (operator === '=' && t().isMemberExpression(left) && t().isIdentifier(left.object) && left.object.name === 'exports' && t().isIdentifier(left.property) && left.property.name === 'routes') {
routesNode = right;
}
},
ExportDefaultDeclaration({
node
}) {
// export default []
const declaration = node.declaration;
if (t().isArrayExpression(declaration)) {
routesNode = declaration;
}
},
ObjectExpression({
node,
parent
}) {
// find routes on object, like { routes: [] }
if (t().isArrayExpression(parent)) {
// children routes
return;
}
const properties = node.properties;
properties.forEach(p => {
const key = p.key,
value = p.value;
if (t().isObjectProperty(p) && t().isIdentifier(key) && key.name === 'routes') {
routesNode = value;
}
});
}
});
if (routesNode) {
// routes 配置不在当前文件, 需要 load 对应的文件 export default { routes: pageRoutes } case 1
if (!t().isArrayExpression(routesNode)) {
const source = importModules.find(m => m.identifierName === routesNode.name);
if (source) {
const newConfigPath = getModulePath(configPath, source.modulePath, absSrcPath);
return getNewRouteCode(newConfigPath, newRoute, absSrcPath);
}
throw new Error(`can not find import of ${routesNode.name}`);
} else {
// 配置在当前文件 // export default { routes: [] } case 2
writeRouteNode(routesNode, newRoute);
}
} else {
throw new Error('route array config not found.');
}
const code = generateCode(ast);
debug(code, configPath);
return {
code,
routesPath: configPath
};
}
function getNewRouteNode(newRoute) {
return parser().parse(`(${JSON.stringify(newRoute)})`).program.body[0].expression;
}
/**
* 写入节点
* @param {*} node 找到的节点
* @param {*} newRoute 新的路由配置
*/
function writeRouteNode(targetNode, newRoute, currentPath = '/') {
debug(`writeRouteNode currentPath newRoute.path: ${newRoute.path} currentPath: ${currentPath}`);
const elements = targetNode.elements;
const paths = elements.map(ele => {
if (!t().isObjectExpression(ele)) {
return false;
}
const properties = ele.properties;
const redirect = properties.find(p => p.key.name === 'redirect');
if (redirect) {
return false;
}
const pathProp = properties.find(p => p.key.name === 'path');
if (!pathProp) {
return currentPath;
}
let fullPath = pathProp.value.value;
if (fullPath.indexOf('/') !== 0) {
fullPath = (0, _path().join)(currentPath, fullPath);
}
return fullPath;
});
debug('paths', paths);
const matchedIndex = paths.findIndex(p => p && newRoute.path.indexOf((0, _utils().winPath)(p)) === 0);
const newNode = getNewRouteNode(newRoute);
if (matchedIndex === -1) {
elements.push(newNode); // return container for test
return targetNode;
} // matched, insert to children routes
const matchedEle = elements[matchedIndex];
const routesProp = matchedEle.properties.find(p => p.key.name === 'routes' || process.env.BIGFISH_COMPAT && p.key.name === 'childRoutes');
if (!routesProp) {
// not find children routes, insert before the matched element
elements.splice(matchedIndex, 0, newNode);
return targetNode;
}
return writeRouteNode(routesProp.value, newRoute, paths[matchedIndex]);
}
/**
* 生成代码
* @param {*} ast
*/
function generateCode(ast) {
const newCode = (0, _generator().default)(ast, {}).code;
return _prettier().default.format(newCode, {
// format same as ant-design-pro
singleQuote: true,
trailingComma: 'es5',
printWidth: 100,
parser: 'typescript'
});
}
/**
* 获取路由配置的真实路径
* @param {*} modulePath
*/
function getModulePath(configPath, modulePath, absSrcPath) {
// like @/route.config
if (/^@\//.test(modulePath)) {
modulePath = (0, _path().join)(absSrcPath, modulePath.replace(/^@\//, ''));
} else {
modulePath = (0, _path().join)((0, _path().dirname)(configPath), modulePath);
}
if (!/\.[j|t]s$/.test(modulePath)) {
if ((0, _fs().existsSync)(`${modulePath}.js`)) {
modulePath = `${modulePath}.js`;
} else {
modulePath = `${modulePath}.ts`;
}
}
return modulePath;
}