UNPKG

@paultaku/node-mock-server

Version:

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

881 lines (806 loc) 28.7 kB
#!/usr/bin/env node /******/ (() => { // webpackBootstrap /******/ "use strict"; /******/ var __webpack_modules__ = ({ /***/ 35: /***/ (function(__unused_webpack_module, exports, __webpack_require__) { /** * File Reader Utility * * Wrapper around fs-extra for file read operations. * Provides a consistent interface for file reading across all domains. */ 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.readFile = readFile; exports.readJson = readJson; exports.isDirectory = isDirectory; exports.isFile = isFile; exports.readDirectory = readDirectory; const fs = __importStar(__webpack_require__(652)); /** * Read file content as a string */ async function readFile(filePath, options) { return await fs.readFile(filePath, options?.encoding || 'utf8'); } /** * Read and parse JSON file */ async function readJson(filePath) { return await fs.readJson(filePath); } /** * Check if a path is a directory */ async function isDirectory(dirPath) { try { const stats = await fs.stat(dirPath); return stats.isDirectory(); } catch { return false; } } /** * Check if a path is a file */ async function isFile(filePath) { try { const stats = await fs.stat(filePath); return stats.isFile(); } catch { return false; } } /** * List files in a directory */ async function readDirectory(dirPath) { return await fs.readdir(dirPath); } /***/ }), /***/ 115: /***/ ((module) => { module.exports = require("yaml"); /***/ }), /***/ 192: /***/ ((__unused_webpack_module, exports, __webpack_require__) => { /** * Generate Command * * CLI command for generating mock files from Swagger/OpenAPI specifications. * Orchestrates the mock generation workflow. */ Object.defineProperty(exports, "__esModule", ({ value: true })); exports.executeGenerateCommand = executeGenerateCommand; const mock_generation_1 = __webpack_require__(272); const command_parser_1 = __webpack_require__(972); /** * Execute the generate command * Parses CLI arguments and triggers mock generation */ async function executeGenerateCommand() { const program = (0, command_parser_1.createGenerateCommand)(); program.parse(process.argv); const { swaggerPath, outputPath } = (0, command_parser_1.parseGenerateOptions)(program); try { await (0, mock_generation_1.generateMockFromSwagger)(swaggerPath, outputPath); console.log("✅ Mock files generated successfully!"); } catch (error) { console.error("❌ Failed to generate mock files:", error); process.exit(1); } } /***/ }), /***/ 256: /***/ ((__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()), }); /***/ }), /***/ 271: /***/ ((__unused_webpack_module, exports) => { /** * Response Builder * * Generates mock response data from OpenAPI/Swagger schemas. * Converts JSON Schema definitions into realistic mock data. */ Object.defineProperty(exports, "__esModule", ({ value: true })); exports.generateMockDataFromSchema = generateMockDataFromSchema; exports.generateDefaultResponses = generateDefaultResponses; exports.buildMockResponseBody = buildMockResponseBody; /** * Recursively generate mock data from a JSON Schema * @param schema - JSON Schema object * @param components - Swagger components for $ref resolution * @returns Generated mock data matching the schema */ function generateMockDataFromSchema(schema, components) { if (!schema) return null; // Handle $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); } // Prefer example when present 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; } /** * Generate default response templates for common HTTP status codes * Used when no response schema is defined in the OpenAPI spec * @returns Record of status code to response definition */ 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" }, }, }, }, }, }, }; } /** * Build mock response body from a Swagger response definition * @param responseDefinition - Swagger response object * @param status - HTTP status code * @param components - Swagger components for schema resolution * @returns Mock response body */ function buildMockResponseBody(responseDefinition, status, components) { let mockBody = {}; // Only handle application/json const content = responseDefinition.content?.["application/json"]; if (content && content.schema) { mockBody = generateMockDataFromSchema(content.schema, components); } else { // If no schema, generate default response mockBody = { success: status === "200", message: responseDefinition.description || "Response", status: parseInt(status), }; } return mockBody; } /***/ }), /***/ 272: /***/ ((__unused_webpack_module, exports, __webpack_require__) => { /** * Mock Generation Domain - Public Interface * * This domain handles parsing Swagger/OpenAPI specifications * and generating mock response files. * * Bounded Context: Mock Generation * Responsibility: Transform API specifications into mock data files */ Object.defineProperty(exports, "__esModule", ({ value: true })); exports.generateMockFromSwagger = void 0; // Main service function var mock_file_generator_1 = __webpack_require__(463); Object.defineProperty(exports, "generateMockFromSwagger", ({ enumerable: true, get: function () { return mock_file_generator_1.generateMockFromSwagger; } })); // DO NOT import internal utilities (swagger-parser, response-builder) // These are domain-internal implementation details /***/ }), /***/ 453: /***/ (function(__unused_webpack_module, exports, __webpack_require__) { /** * File System Utilities - Public Interface * * This module exports file system utilities used across domains. * Wraps fs-extra to provide a consistent, domain-friendly interface. */ 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 __exportStar = (this && this.__exportStar) || function(m, exports) { for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); }; Object.defineProperty(exports, "__esModule", ({ value: true })); __exportStar(__webpack_require__(767), exports); __exportStar(__webpack_require__(35), exports); /***/ }), /***/ 463: /***/ (function(__unused_webpack_module, exports, __webpack_require__) { /** * Mock File Generator * * Generates mock response files from parsed Swagger specifications. * Handles file organization and directory structure creation. */ 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 path = __importStar(__webpack_require__(928)); const file_system_1 = __webpack_require__(453); const swagger_parser_1 = __webpack_require__(566); const response_builder_1 = __webpack_require__(271); /** * Safe filename generation * Sanitizes strings to be used as filenames */ 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 } /** * HTTP methods supported by the mock server */ const SUPPORTED_HTTP_METHODS = [ "GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS", ]; /** * Generate mock files from a Swagger/OpenAPI specification * @param swaggerPath - Path to the Swagger YAML file * @param outputPath - Directory where mock files will be created * @returns Generation result with statistics */ async function generateMockFromSwagger(swaggerPath, outputPath) { try { console.log(`Reading Swagger file: ${swaggerPath}`); // Parse Swagger specification const swagger = await (0, swagger_parser_1.parseSwaggerSpec)(swaggerPath); const components = (0, swagger_parser_1.getComponents)(swagger); const paths = (0, swagger_parser_1.getSwaggerPaths)(swagger); console.log(`Processing ${paths.length} paths...`); let filesCreated = 0; let pathsProcessed = 0; // Iterate over paths for (const apiPath of paths) { const methods = (0, swagger_parser_1.getPathMethods)(swagger, apiPath); for (const [method, operation] of Object.entries(methods)) { const methodUpper = method.toUpperCase(); // Skip non-HTTP methods if (!SUPPORTED_HTTP_METHODS.includes(methodUpper)) { continue; } // Build directory path const pathParts = apiPath.replace(/^\//, "").split("/"); const safePathParts = pathParts.map((part) => { // Keep path parameter format {paramName} if (part.startsWith("{") && part.endsWith("}")) { return part; } // Sanitize other parts return sanitizeFileName(part); }); const endpointDir = path.join(outputPath, ...safePathParts, methodUpper); await (0, file_system_1.ensureDirectory)(endpointDir); console.log(`Generated directory: ${endpointDir}`); // Handle responses const responses = operation.responses || (0, response_builder_1.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); // Generate mock data const mockBody = (0, response_builder_1.buildMockResponseBody)(resp, status, components); const mock = { header: [], body: mockBody, }; await (0, file_system_1.writeJson)(filePath, mock, { spaces: 2 }); console.log(`Generated mock file: ${filePath}`); filesCreated++; } pathsProcessed++; } } console.log("Mock generation completed successfully!"); return { filesCreated, pathsProcessed, outputDirectory: outputPath, }; } catch (error) { console.error("Error generating mock files:", error); throw error; } } /***/ }), /***/ 566: /***/ (function(__unused_webpack_module, exports, __webpack_require__) { /** * Swagger Parser * * Parses and validates Swagger/OpenAPI specification files. * Handles YAML parsing and schema validation. */ 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.parseSwaggerSpec = parseSwaggerSpec; exports.getSwaggerPaths = getSwaggerPaths; exports.getPathMethods = getPathMethods; exports.getComponents = getComponents; const yaml = __importStar(__webpack_require__(115)); const swagger_types_1 = __webpack_require__(256); const file_system_1 = __webpack_require__(453); /** * Parse a Swagger/OpenAPI specification file * @param swaggerPath - Path to the Swagger YAML file * @returns Parsed and validated Swagger document */ async function parseSwaggerSpec(swaggerPath) { const raw = await (0, file_system_1.readFile)(swaggerPath); const doc = yaml.parse(raw); // Type validation using Zod schema const swagger = swagger_types_1.SwaggerDocSchema.parse(doc); return swagger; } /** * Get all paths from a Swagger document * @param swagger - Parsed Swagger document * @returns Array of API paths */ function getSwaggerPaths(swagger) { return Object.keys(swagger.paths); } /** * Get methods for a specific path * @param swagger - Parsed Swagger document * @param apiPath - API path to query * @returns Object containing method definitions */ function getPathMethods(swagger, apiPath) { return swagger.paths[apiPath]; } /** * Get components (schemas, responses, etc.) from Swagger document * @param swagger - Parsed Swagger document * @returns Components object */ function getComponents(swagger) { return swagger.components || {}; } /***/ }), /***/ 569: /***/ ((module) => { module.exports = require("zod"); /***/ }), /***/ 623: /***/ ((__unused_webpack_module, exports, __webpack_require__) => { /** * CLI Tools Domain - Public Interface * * This domain handles command-line interface operations. * Provides CLI commands for mock generation and server management. * * Bounded Context: CLI Tools * Responsibility: Parse CLI arguments and execute commands */ Object.defineProperty(exports, "__esModule", ({ value: true })); exports.parseGenerateOptions = exports.createGenerateCommand = exports.executeGenerateCommand = void 0; // Main command executor var generate_command_1 = __webpack_require__(192); Object.defineProperty(exports, "executeGenerateCommand", ({ enumerable: true, get: function () { return generate_command_1.executeGenerateCommand; } })); // Command parsing utilities var command_parser_1 = __webpack_require__(972); Object.defineProperty(exports, "createGenerateCommand", ({ enumerable: true, get: function () { return command_parser_1.createGenerateCommand; } })); Object.defineProperty(exports, "parseGenerateOptions", ({ enumerable: true, get: function () { return command_parser_1.parseGenerateOptions; } })); // DO NOT import internal implementation details // This domain orchestrates Mock Generation and Server Runtime domains /***/ }), /***/ 652: /***/ ((module) => { module.exports = require("fs-extra"); /***/ }), /***/ 767: /***/ (function(__unused_webpack_module, exports, __webpack_require__) { /** * File Writer Utility * * Wrapper around fs-extra for file write operations. * Provides a consistent interface for file writing across all domains. */ 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.writeFile = writeFile; exports.writeJson = writeJson; exports.ensureDirectory = ensureDirectory; exports.fileExists = fileExists; const fs = __importStar(__webpack_require__(652)); const path = __importStar(__webpack_require__(928)); /** * Write content to a file, creating parent directories if needed */ async function writeFile(filePath, content, options) { const dir = path.dirname(filePath); await fs.ensureDir(dir); await fs.writeFile(filePath, content, options?.encoding || 'utf8'); } /** * Write JSON content to a file */ async function writeJson(filePath, data, options) { const dir = path.dirname(filePath); await fs.ensureDir(dir); await fs.writeJson(filePath, data, { spaces: options?.spaces || 2 }); } /** * Ensure a directory exists, creating it if necessary */ async function ensureDirectory(dirPath) { await fs.ensureDir(dirPath); } /** * Check if a file exists */ async function fileExists(filePath) { try { await fs.access(filePath); return true; } catch { return false; } } /***/ }), /***/ 858: /***/ ((module) => { module.exports = require("commander"); /***/ }), /***/ 928: /***/ ((module) => { module.exports = require("path"); /***/ }), /***/ 972: /***/ (function(__unused_webpack_module, exports, __webpack_require__) { /** * Command Parser * * Parses and validates CLI arguments using Commander.js. * Provides utilities for CLI option handling. */ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.createGenerateCommand = createGenerateCommand; exports.parseGenerateOptions = parseGenerateOptions; const commander_1 = __webpack_require__(858); const path_1 = __importDefault(__webpack_require__(928)); /** * Create and configure the generate command * @returns Configured Command instance */ function createGenerateCommand() { const program = new commander_1.Command(); program .name("node-mock-server") .description("Generate mock files from Swagger YAML") .version("1.1.0-rc-4") .requiredOption("-s, --swagger <path>", "Path to swagger yaml file") .requiredOption("-o, --output <path>", "Output mock root directory"); return program; } /** * Parse generate command options * @param program - Configured Command instance * @returns Parsed options with resolved paths */ function parseGenerateOptions(program) { const options = program.opts(); return { swaggerPath: path_1.default.resolve(options.swagger), outputPath: path_1.default.resolve(options.output), }; } /***/ }) /******/ }); /************************************************************************/ /******/ // 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; /******/ } /******/ /************************************************************************/ var __webpack_exports__ = {}; // This entry needs to be wrapped in an IIFE because it uses a non-standard name for the exports (exports). (() => { var exports = __webpack_exports__; /** * CLI Entry Point * * Minimal entry point that delegates to the CLI Tools domain. * This file is kept as the executable entry point for the npm package. */ Object.defineProperty(exports, "__esModule", ({ value: true })); const cli_tools_1 = __webpack_require__(623); // Execute the generate command (0, cli_tools_1.executeGenerateCommand)(); })(); module.exports = __webpack_exports__; /******/ })() ; //# sourceMappingURL=generate-mock.js.map