(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('fs'), require('path'), require('axios'), require('lodash'), require('prettier'), require('@vue/compiler-sfc'), require('magic-string'), require('glob')) : typeof define === 'function' && define.amd ? define(['exports', 'fs', 'path', 'axios', 'lodash', 'prettier', '@vue/compiler-sfc', 'magic-string', 'glob'], factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.index = {}, global.fs, global.path, global.axios, global.lodash, global.prettier, global.compilerSfc, global.magicString, global.glob)); })(this, (function (exports, fs, path, axios, lodash, prettier, compilerSfc, magicString, glob) { 'use strict'; const config = { type: "admin", reqUrl: "", demo: false, eps: { api: "", dist: "./build/cool", mapping: [ { // 自定义匹配 custom: ({ propertyName, type }) => { // 如果没有,返回null或者不返回,则继续遍历其他匹配规则 return null; }, }, { type: "string", test: ["varchar", "text", "simple-json"], }, { type: "string[]", test: ["simple-array"], }, { type: "Date", test: ["datetime", "date"], }, { type: "number", test: ["tinyint", "int", "decimal"], }, { type: "BigInt", test: ["bigint"], }, ], }, }; // 根目录 function rootDir(path$1) { switch (config.type) { case "app": return path.join(process.env.UNI_INPUT_DIR, path$1); default: return path.join(process.cwd(), path$1); } } // 首字母大写 function firstUpperCase(value) { return value.replace(/\b(\w)(\w*)/g, function ($0, $1, $2) { return $1.toUpperCase() + $2; }); } // 横杠转驼峰 function toCamel(str) { return str.replace(/([^-])(?:-+([^-]))/g, function ($0, $1, $2) { return $1 + $2.toUpperCase(); }); } // 创建目录 function createDir(path, recursive) { try { if (!fs.existsSync(path)) fs.mkdirSync(path, { recursive }); } catch (err) { } } // 读取文件 function readFile(path, json) { try { const content = fs.readFileSync(path, "utf8"); return json ? JSON.parse(content) : content; } catch (err) { } return ""; } // 写入文件 function writeFile(path, data) { try { return fs.writeFileSync(path, data); } catch (err) { } return ""; } // 解析body function parseJson(req) { return new Promise((resolve) => { let d = ""; req.on("data", function (chunk) { d += chunk; }); req.on("end", function () { try { resolve(JSON.parse(d)); } catch { resolve({}); } }); }); } function error(message) { console.log("\x1B[31m%s\x1B[0m", message); } let service = {}; let list = []; let customList = []; // 获取请求地址 function getEpsUrl() { let url = config.eps.api; if (!url) { url = config.type; } switch (url) { case "app": url = "/app/base/comm/eps"; break; case "admin": url = "/admin/base/open/eps"; break; } return url; } // 获取路径 function getEpsPath(filename) { return path.join(config.type == "admin" ? config.eps.dist : rootDir(config.eps.dist), filename || ""); } // 获取方法名 function getNames(v) { return Object.keys(v).filter((e) => !["namespace", "permission"].includes(e)); } // 获取数据 async function getData(data) { // 自定义数据 if (!lodash.isEmpty(data)) { customList = (data || []).map((e) => { return { ...e, isLocal: true, }; }); } // 本地文件 const epsPath = getEpsPath("eps.json"); try { list = readFile(epsPath, true) || []; } catch (err) { error(`[cool-eps] ${epsPath} 文件异常, ${err.message}`); } // 请求地址 const url = config.reqUrl + getEpsUrl(); // 请求数据 await axios .get(url, { timeout: 5000, }) .then((res) => { const { code, data, message } = res.data; if (code === 1000) { if (!lodash.isEmpty(data) && data) { lodash.merge(list, Object.values(data).flat()); } } else { error(`[cool-eps] ${message}`); } }) .catch(() => { error(`[cool-eps] 后端未启动 ➜ ${url}`); }); // 合并自定义数据 if (lodash.isArray(customList)) { customList.forEach((e) => { const d = list.find((a) => e.prefix === a.prefix); if (d) { lodash.merge(d, e); } else { list.push(e); } }); } // 设置默认值 list.forEach((e) => { if (!e.namespace) { e.namespace = ""; } if (!e.api) { e.api = []; } }); } // 创建 json 文件 function createJson() { const arr = list.map((e) => { return { prefix: e.prefix, name: e.name || "", api: e.api.map((e) => { return { name: e.name, method: e.method, path: e.path, }; }), }; }); const content = JSON.stringify(arr); const local_content = readFile(getEpsPath("eps.json")); // 是否需要更新 const isUpdate = content != local_content; if (isUpdate) { fs.createWriteStream(getEpsPath("eps.json"), { flags: "w", }).write(content); } return isUpdate; } // 创建描述文件 async function createDescribe({ list, service }) { // 获取类型 function getType({ propertyName, type }) { for (const map of config.eps.mapping) { if (map.custom) { const resType = map.custom({ propertyName, type }); if (resType) return resType; } if (map.test) { if (map.test.includes(type)) return map.type; } } return type; } // 创建 Entity function createEntity() { const t0 = []; for (const item of list) { if (!item.name) continue; const t = [`interface ${item.name} {`]; for (const col of item.columns || []) { // 描述 t.push("\n"); t.push("/**\n"); t.push(` * ${col.comment}\n`); t.push(" */\n"); t.push(`${col.propertyName}?: ${getType({ propertyName: col.propertyName, type: col.type, })};`); } t.push("\n"); t.push("/**\n"); t.push(` * 任意键值\n`); t.push(" */\n"); t.push(`[key: string]: any;`); t.push("}"); t0.push(t); } return t0.map((e) => e.join("")).join("\n\n"); } // 创建 Service function createDts() { const t0 = []; const t1 = [ ` type json = any; type Service = { request(options?: { url: string; method?: "POST" | "GET" | "PUT" | "DELETE" | "PATCH" | "HEAD" | "OPTIONS"; data?: any; params?: any; headers?: { [key: string]: any; }, timeout?: number; proxy?: boolean; [key: string]: any; }): Promise; `, ]; // 处理数据 function deep(d, k) { if (!k) k = ""; for (const i in d) { const name = k + toCamel(firstUpperCase(i.replace(/[:]/g, ""))); if (d[i].namespace) { // 查找配置 const item = list.find((e) => (e.prefix || "") === `/${d[i].namespace}`); if (item) { const t = [`interface ${name} {`]; t1.push(`${i}: ${name};`); // 插入方法 if (item.api) { // 权限列表 const permission = []; item.api.forEach((a) => { // 方法名 const n = toCamel(a.name || lodash.last(a.path.split("/")) || "").replace(/[:\/-]/g, ""); if (n) { // 参数类型 let q = []; // 参数列表 const { parameters = [] } = a.dts || {}; parameters.forEach((p) => { if (p.description) { q.push(`\n/** ${p.description} */\n`); } if (p.name.includes(":")) { return false; } const a = `${p.name}${p.required ? "" : "?"}`; const b = `${p.schema.type || "string"}`; q.push(`${a}: ${b},`); }); if (lodash.isEmpty(q)) { q = ["any"]; } else { q.unshift("{"); q.push("}"); } // 返回类型 let res = ""; // 实体名 const en = item.name || "any"; switch (a.path) { case "/page": res = ` { pagination: { size: number; page: number; total: number; [key: string]: any }; list: ${en} []; [key: string]: any; } `; break; case "/list": res = `${en} []`; break; case "/info": res = en; break; default: res = "any"; break; } // 描述 t.push("\n"); t.push("/**\n"); t.push(` * ${a.summary || n}\n`); t.push(" */\n"); t.push(`${n}(data${q.length == 1 ? "?" : ""}: ${q.join("")}): Promise<${res}>;`); permission.push(n); } }); // 权限标识 t.push("\n"); t.push("/**\n"); t.push(" * 权限标识\n"); t.push(" */\n"); t.push(`permission: { ${permission .map((e) => `${e}: string;`) .join("\n")} };`); // 权限状态 t.push("\n"); t.push("/**\n"); t.push(" * 权限状态\n"); t.push(" */\n"); t.push(`_permission: { ${permission .map((e) => `${e}: boolean;`) .join("\n")} };`); // 请求 t.push("\n"); t.push("/**\n"); t.push(" * 请求\n"); t.push(" */\n"); t.push(`request: Service['request']`); } t.push("}"); t0.push(t); } } else { t1.push(`${i}: {`); deep(d[i], name); t1.push(`},`); } } } // 深度 deep(service); // 结束 t1.push("}"); // 追加 t0.push(t1); return t0.map((e) => e.join("")).join("\n\n"); } // 文件内容 const text = ` declare namespace Eps { ${createEntity()} ${createDts()} } `; // 文本内容 const content = await prettier.format(text, { parser: "typescript", useTabs: true, tabWidth: 4, endOfLine: "lf", semi: true, singleQuote: false, printWidth: 100, trailingComma: "none", }); const local_content = readFile(getEpsPath("eps.d.ts")); // 是否需要更新 if (content != local_content) { // 创建 eps 描述文件 fs.createWriteStream(getEpsPath("eps.d.ts"), { flags: "w", }).write(content); } } // 创建 service function createService() { // 路径第一层作为 id 标识 const id = getEpsUrl().split("/")[1]; list.forEach((e) => { // 请求地址 const path = e.prefix[0] == "/" ? e.prefix.substring(1, e.prefix.length) : e.prefix; // 分隔路径 const arr = path.replace(id, "").split("/").filter(Boolean).map(toCamel); // 遍历 function deep(d, i) { const k = arr[i]; if (k) { // 是否最后一个 if (arr[i + 1]) { if (!d[k]) { d[k] = {}; } deep(d[k], i + 1); } else { // 不存在则创建 if (!d[k]) { d[k] = { namespace: path, permission: {}, }; } // 创建方法 e.api.forEach((a) => { // 方法名 const n = a.path.replace("/", ""); if (n && !/[-:]/g.test(n)) { d[k][n] = a; } }); // 创建权限 getNames(d[k]).forEach((i) => { d[k].permission[i] = `${d[k].namespace.replace(`${id}/`, "")}/${i}`.replace(/\//g, ":"); }); } } } deep(service, 0); }); } // 创建 eps async function createEps(query) { // 获取数据 await getData(query?.list || []); // 创建 service createService(); // 创建目录 createDir(getEpsPath(), true); // 创建 json 文件 const isUpdate = createJson(); // 创建描述文件 createDescribe({ service, list }); return { service, list, isUpdate, }; } function createTag(code, id) { if (/\.vue$/.test(id)) { let s; const str = () => s || (s = new magicString(code)); const { descriptor } = compilerSfc.parse(code); if (!descriptor.script && descriptor.scriptSetup) { const res = compilerSfc.compileScript(descriptor, { id }); const { name, lang } = res.attrs; str().appendLeft(0, `