const path = require('path'); const fs = require('fs'); const prettier = require('prettier'); const lodash = require('lodash'); const utils = require('@umijs/utils'); const { prettier: defaultPrettierOptions } = require('@umijs/fabric'); const { dirname } = require('path'); const getAbsolutePath = (filePath) => { if(filePath && !path.isAbsolute(filePath)) { return path.join(process.cwd(), filePath); } return filePath; } const mkdir = (dir) => { if(!fs.existsSync(dir)) { mkdir(path.dirname(dir)); fs.mkdirSync(dir); } } const prettierFile = (content) => { let result = content; let hasError = false; try { result = prettier.format(content, { singleQuote: true, trailingComma: 'all', printWidth: 100, parser: 'babel', ...defaultPrettierOptions, }); } catch (error) { hasError = true; } return [result, hasError]; }; const writeFile = (folderPath, fileName, content) => { const filePath = path.join(folderPath, fileName); mkdir(path.dirname(filePath)); const [prettierContent, hasError] = prettierFile(content); fs.writeFileSync(filePath, prettierContent, { encoding: 'utf8', }); return hasError; }; const getTagName = (name) => { const result = name.split('.'); // 数据源中的 tag 等同于全量的 op API 名,确定为 4-5 段,如上格式 // 取中间的 1-2 字段作为 tag,作为 serviceController 创建目录的依据 if (result.length === 4) { return result[2]; } if (result.length === 5) { return result[2] + lodash.upperFirst(result[3]); } return name; }; /** * 根据当前的数据源类型,对请求回来的 apiInfo 进行格式化 * 如果是 op 数据源,对 tags 以及 path 中的 tags 进行处理 * - before: 前缀(产品集.产品码) + 操作对象(必填)+ 子操作对象(可选)+ 动作(必填) * - after: 操作对象(必填)+ 子操作对象(可选) ==> 驼峰 */ const formatApiInfo = (apiInfo) => { if (!(apiInfo && apiInfo.schema.info && apiInfo.schema.info.extensions && apiInfo.schema.info.extensions['x-antTech-description'])) { // 非 op 数据源,直接返回 return apiInfo; } apiInfo.schema.tags = apiInfo.schema.tags.map((item) => { return { ...item, name: getTagName(item.name), }; }); for (const child_path in apiInfo.schema.paths) { apiInfo.schema.paths[child_path].post.tags = apiInfo.schema.paths[child_path].post.tags.map((tag) => getTagName(tag)); } return apiInfo; }; /** * 一方化场景下,由于 onex 会对请求的响应做处理 * 1. 将 Response & Request 中的参数字段会变更为小驼峰写法 * onex 相关代码 : http://gitlab.alipay-inc.com/one-console/sdk/blob/master/src/request.ts#L110 * 2. 另外要注意: * op 返回的数据,请求参数的类型格式 需要做额外的处理 * - (name) key.n, (type) string ==> key: string [] * - (name) key.m, (type) string ===> key: string [] * - (name) key.key1 , (type) string ==> key: {key1:string} * - (name) key.n.key1 ,(type) string => key:{ key1 :string}[] * - (name) key.n.key1.m,(type) string ==> key:{key1: string[]}[] */ function formatParamsForYFH(params, paramsObject = {}) { Object.keys(params).forEach((name) => { const prop = params[name]; let key = name; const nameList = name.split('.'); const nameListLength = nameList.length; if (nameListLength === 1) { // 正常的 key paramsObject[key] = { ...prop }; } else if (nameListLength === 2 && nameList[1] !== 'n' && nameList[1] !== 'm') { const [childKey] = nameList; // key.child_key const key_child_key = lodash.camelCase(nameList[1]); paramsObject[childKey] = combineParams(childKey, key_child_key, prop, paramsObject); } else { // key.n.child_key if (nameList[nameListLength - 2] === 'n' || nameList[nameListLength - 2] === 'm') { const child_key = lodash.camelCase(nameList.pop()); nameList.pop(); key = nameList.join('.'); paramsObject[key] = combineParams(key, child_key, prop, paramsObject, '.n.key'); } else { const child_key = lodash.camelCase(nameList.pop()); key = nameList.join('.'); // .key.n if (child_key === 'n' || child_key === 'm') { // .n.key.m if (nameList[nameList.length - 2] === 'n' || nameList[nameList.length - 2] === 'm') { const child_child_key = lodash.camelCase(nameList.pop()); nameList.pop(); key = nameList.join('.'); paramsObject[key] = combineParams(key, child_child_key, prop, paramsObject, '.n.key.m'); } else { prop.type = `${prop.type}[]`; paramsObject[key] = { ...prop }; } } else { paramsObject[key] = combineParams(key, child_key, prop, paramsObject); } } } paramsObject[key].name = lodash_1.camelCase(key); }); const hasInvoke = Object.keys(paramsObject).filter((param) => param.includes('.')).length > 0; if (hasInvoke) { // 递归 return formatParamsForYFH(paramsObject); } return paramsObject; } function combineParams(key, child_key, prop, paramsObject, type) { const typeSuffix = type === '.n.key.m' ? '[]' : ''; const keySuffix = type === '.n.key' || type === '.n.key.m' ? '[]' : ''; if (paramsObject[key]) { const child_type = `{${child_key}:${prop.type}${typeSuffix}, ${paramsObject[key].type.slice(1)}`; paramsObject[key] = { ...paramsObject[key], type: child_type, }; } else { paramsObject[key] = { ...prop, type: `{${child_key}:${prop.type} }${keySuffix}`, }; } return paramsObject[key]; } const stripDot = (str) => { return str.replace(/[-_ .](\w)/g, (_all, letter) => letter.toUpperCase()); }; const writeTmpFile = ({path: p, content}) => { const absTmpPath = path.join(process.cwd(), 'src/.temp'); const absPath = path.join(absTmpPath, p); console.log(absPath) utils.mkdirp.sync(path.dirname(absPath)); if(!fs.existsSync(absPath) || fs.readFileSync(absPath, 'utf-8') !== content) { fs.writeFileSync(absPath, prettier.format(content, { singleQuote: true, trailingComma: 'all', printWidth: 100, parser: 'babel', ...defaultPrettierOptions, }), 'utf-8'); } } module.exports = { getAbsolutePath, mkdir, prettierFile, writeFile, getTagName, formatApiInfo, formatParamsForYFH, combineParams, stripDot, writeTmpFile }