UNPKG

@paultaku/node-mock-server

Version:

A TypeScript-based mock server with automatic Swagger-based mock file generation

355 lines (332 loc) 12.1 kB
/******/ (() => { // webpackBootstrap /******/ "use strict"; /******/ var __webpack_modules__ = ({ /***/ 115: /***/ ((module) => { module.exports = require("yaml"); /***/ }), /***/ 315: /***/ ((__unused_webpack_module, exports, __webpack_require__) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.SwaggerDocSchema = void 0; const zod_1 = __webpack_require__(569); exports.SwaggerDocSchema = zod_1.z.object({ openapi: zod_1.z.string(), info: zod_1.z.object({ title: zod_1.z.string(), version: zod_1.z.string(), }), paths: zod_1.z.record(zod_1.z.string(), zod_1.z.any()), components: zod_1.z.optional(zod_1.z.any()), }); /***/ }), /***/ 569: /***/ ((module) => { module.exports = require("zod"); /***/ }), /***/ 652: /***/ ((module) => { module.exports = require("fs-extra"); /***/ }), /***/ 755: /***/ (function(module, exports, __webpack_require__) { var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", ({ value: true })); exports.generateMockFromSwagger = generateMockFromSwagger; const fs = __importStar(__webpack_require__(652)); const yaml = __importStar(__webpack_require__(115)); const path = __importStar(__webpack_require__(928)); const swagger_1 = __webpack_require__(315); // Safe filename generation function sanitizeFileName(name) { return name .toLowerCase() .replace(/\s+/g, "-") // Convert spaces to - .replace(/[^a-z0-9\-_]/g, "-") // Convert all illegal characters to - .replace(/-+/g, "-") // Merge consecutive - .replace(/^-|-$/g, "") // Remove leading and trailing - .substring(0, 100); // Limit length } // 递归生成 mock 数据 function generateMockDataFromSchema(schema, components) { if (!schema) return null; // 处理 $ref if (schema.$ref) { const refPath = schema.$ref.replace(/^#\//, "").split("/"); let ref = components; for (const seg of refPath.slice(1)) { if (ref && ref[seg]) { ref = ref[seg]; } else { console.warn(`Warning: Could not resolve $ref: ${schema.$ref}`); return null; } } return generateMockDataFromSchema(ref, components); } // 优先 example if (schema.example !== undefined) return schema.example; // type: object if (schema.type === "object" || schema.properties) { const obj = {}; const props = schema.properties || {}; for (const [key, propSchema] of Object.entries(props)) { obj[key] = generateMockDataFromSchema(propSchema, components); } return obj; } // type: array if (schema.type === "array" && schema.items) { const item = generateMockDataFromSchema(schema.items, components); return [item]; } // type: string if (schema.type === "string") { if (schema.enum && schema.enum.length > 0) { return schema.enum[0]; } if (schema.format === "date-time") return "2023-01-01T00:00:00Z"; if (schema.format === "date") return "2023-01-01"; if (schema.format === "email") return "user@example.com"; if (schema.format === "uri") return "https://example.com"; if (schema.format === "uuid") return "123e4567-e89b-12d3-a456-426614174000"; return "string"; } // type: integer/number if (schema.type === "integer" || schema.type === "number") { if (schema.minimum !== undefined) return schema.minimum; if (schema.maximum !== undefined) return Math.floor(schema.maximum / 2); return 0; } // type: boolean if (schema.type === "boolean") { return true; } // fallback return null; } // 生成默认的响应文件 function generateDefaultResponses() { return { "200": { description: "Successful operation", content: { "application/json": { schema: { type: "object", properties: { success: { type: "boolean" }, message: { type: "string" }, }, }, }, }, }, "400": { description: "Bad request", content: { "application/json": { schema: { type: "object", properties: { error: { type: "string" }, code: { type: "string" }, }, }, }, }, }, "404": { description: "Not found", content: { "application/json": { schema: { type: "object", properties: { error: { type: "string" }, code: { type: "string" }, }, }, }, }, }, "500": { description: "Internal server error", content: { "application/json": { schema: { type: "object", properties: { error: { type: "string" }, code: { type: "string" }, }, }, }, }, }, }; } async function generateMockFromSwagger(swaggerPath, outputPath) { try { console.log(`Reading Swagger file: ${swaggerPath}`); // 读取 swagger yaml const raw = await fs.readFile(swaggerPath, "utf-8"); const doc = yaml.parse(raw); // 类型校验 const swagger = swagger_1.SwaggerDocSchema.parse(doc); const components = swagger.components || {}; console.log(`Processing ${Object.keys(swagger.paths).length} paths...`); // 遍历 paths for (const [apiPath, methods] of Object.entries(swagger.paths)) { for (const [method, operation] of Object.entries(methods)) { const methodUpper = method.toUpperCase(); // 跳过非HTTP方法 if (![ "GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS", ].includes(methodUpper)) { continue; } // 构建目录路径 const pathParts = apiPath.replace(/^\//, "").split("/"); const safePathParts = pathParts.map((part) => { // 保持路径参数格式 {paramName} if (part.startsWith("{") && part.endsWith("}")) { return part; } // 其他部分进行安全处理 return sanitizeFileName(part); }); const endpointDir = path.join(outputPath, ...safePathParts, methodUpper); await fs.ensureDir(endpointDir); console.log(`Generated directory: ${endpointDir}`); // 处理响应 const responses = operation.responses || generateDefaultResponses(); for (const [status, resp] of Object.entries(responses)) { const desc = resp.description ? sanitizeFileName(resp.description) : "response"; const fileName = `${desc}-${status}.json`; const filePath = path.join(endpointDir, fileName); // 生成 mock 数据 let mockBody = {}; // 只处理 application/json const content = resp.content?.["application/json"]; if (content && content.schema) { mockBody = generateMockDataFromSchema(content.schema, components); } else { // 如果没有schema,生成默认响应 mockBody = { success: status === "200", message: resp.description || "Response", status: parseInt(status), }; } const mock = { header: [], body: mockBody, }; await fs.writeJson(filePath, mock, { spaces: 2 }); console.log(`Generated mock file: ${filePath}`); } } } console.log("Mock generation completed successfully!"); } catch (error) { console.error("Error generating mock files:", error); throw error; } } // 为了兼容性保留 CommonJS 导出 module.exports = { generateMockFromSwagger }; /***/ }), /***/ 928: /***/ ((module) => { module.exports = require("path"); /***/ }) /******/ }); /************************************************************************/ /******/ // The module cache /******/ var __webpack_module_cache__ = {}; /******/ /******/ // The require function /******/ function __webpack_require__(moduleId) { /******/ // Check if module is in cache /******/ var cachedModule = __webpack_module_cache__[moduleId]; /******/ if (cachedModule !== undefined) { /******/ return cachedModule.exports; /******/ } /******/ // Create a new module (and put it into the cache) /******/ var module = __webpack_module_cache__[moduleId] = { /******/ // no module.id needed /******/ // no module.loaded needed /******/ exports: {} /******/ }; /******/ /******/ // Execute the module function /******/ __webpack_modules__[moduleId].call(module.exports, module, module.exports, __webpack_require__); /******/ /******/ // Return the exports of the module /******/ return module.exports; /******/ } /******/ /************************************************************************/ /******/ /******/ // startup /******/ // Load entry module and return exports /******/ // This entry module is referenced by other modules so it can't be inlined /******/ var __webpack_exports__ = __webpack_require__(755); /******/ module.exports = __webpack_exports__; /******/ /******/ })() ; //# sourceMappingURL=mock-generator.js.map