vite-plugin-automock 1.0.0 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-KZB7ARYV.mjs → chunk-PS6HLNJZ.mjs} +2 -1
- package/dist/{chunk-KZB7ARYV.mjs.map → chunk-PS6HLNJZ.mjs.map} +1 -1
- package/dist/index.js +22 -4
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +25 -7
- package/dist/index.mjs.map +1 -1
- package/dist/{mockFileUtils-HQCNPI3U.mjs → mockFileUtils-MO32XIKQ.mjs} +4 -2
- package/package.json +8 -8
- /package/dist/{mockFileUtils-HQCNPI3U.mjs.map → mockFileUtils-MO32XIKQ.mjs.map} +0 -0
|
@@ -330,9 +330,10 @@ var writeMockFile = async (filePath, mockInfo) => {
|
|
|
330
330
|
|
|
331
331
|
export {
|
|
332
332
|
DEFAULT_CONFIG,
|
|
333
|
+
toPosixPath,
|
|
333
334
|
saveMockData,
|
|
334
335
|
buildMockIndex,
|
|
335
336
|
parseMockModule,
|
|
336
337
|
writeMockFile
|
|
337
338
|
};
|
|
338
|
-
//# sourceMappingURL=chunk-
|
|
339
|
+
//# sourceMappingURL=chunk-PS6HLNJZ.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/mockFileUtils.ts"],"sourcesContent":["import path from \"path\";\nimport fs from \"fs-extra\";\nimport prettier from \"prettier\";\n\nexport interface MockFileConfig {\n enable: boolean;\n data: unknown;\n delay: number;\n status: number;\n [key: string]: unknown;\n}\n\nexport interface MockFileInfo {\n config: MockFileConfig;\n serializable: boolean;\n hasDynamicData: boolean;\n headerComment?: string;\n description?: string;\n dataText: string;\n isBinary?: boolean;\n}\n\nexport const DEFAULT_CONFIG: MockFileConfig = {\n enable: true,\n data: null,\n delay: 0,\n status: 200,\n};\n\n// 简单实现 cross-platform 路径分隔符转换\nfunction toPosixPath(p: string): string {\n return p.replace(/\\\\/g, \"/\");\n}\n\n// 检测是否为二进制文件\nconst isBinaryResponse = (\n contentType: string | undefined,\n data: Buffer,\n): boolean => {\n if (!contentType) return false;\n\n const binaryTypes = [\n \"application/octet-stream\",\n \"application/pdf\",\n \"application/zip\",\n \"application/x-zip-compressed\",\n \"application/vnd.ms-excel\",\n \"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\",\n \"application/msword\",\n \"application/vnd.openxmlformats-officedocument.wordprocessingml.document\",\n \"application/vnd.ms-powerpoint\",\n \"application/vnd.openxmlformats-officedocument.presentationml.presentation\",\n \"image/\",\n \"video/\",\n \"audio/\",\n ];\n\n return (\n binaryTypes.some((type) => contentType.toLowerCase().includes(type)) ||\n !isBufferTextLike(data)\n );\n};\n\n// 检测Buffer是否像文本数据\nconst isBufferTextLike = (buffer: Buffer): boolean => {\n try {\n // 检查前100字节是否包含非文本字符\n const sample = buffer.slice(0, 100);\n const text = sample.toString(\"utf8\");\n\n // 如果包含null字节或过多的控制字符,可能是二进制\n const nullBytes = [...sample].filter((b) => b === 0).length;\n const controlChars = [...sample].filter(\n (b) => b < 32 && b !== 9 && b !== 10 && b !== 13,\n ).length;\n\n return nullBytes === 0 && controlChars < 5;\n } catch {\n return false;\n }\n};\n\n// 从Content-Type获取文件扩展名\nconst getFileExtension = (\n contentType: string | undefined,\n url: string,\n): string => {\n // 从Content-Type映射\n const mimeMap: Record<string, string> = {\n \"application/json\": \"json\",\n \"application/pdf\": \"pdf\",\n \"application/zip\": \"zip\",\n \"application/vnd.ms-excel\": \"xls\",\n \"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\": \"xlsx\",\n \"application/msword\": \"doc\",\n \"application/vnd.openxmlformats-officedocument.wordprocessingml.document\":\n \"docx\",\n \"application/vnd.ms-powerpoint\": \"ppt\",\n \"application/vnd.openxmlformats-officedocument.presentationml.presentation\":\n \"pptx\",\n \"image/jpeg\": \"jpg\",\n \"image/png\": \"png\",\n \"image/gif\": \"gif\",\n \"text/plain\": \"txt\",\n \"text/html\": \"html\",\n \"text/css\": \"css\",\n \"application/javascript\": \"js\",\n \"text/xml\": \"xml\",\n };\n\n if (contentType && mimeMap[contentType.toLowerCase()]) {\n return mimeMap[contentType.toLowerCase()];\n }\n\n // 尝试从URL的查询参数中解析文件名\n try {\n const urlObj = new URL(url, \"http://localhost\");\n const fileName = urlObj.searchParams.get(\"file_name\");\n if (fileName) {\n const extensionMatch = fileName.match(/\\.([a-zA-Z0-9]+)$/);\n if (extensionMatch) {\n return extensionMatch[1];\n }\n }\n } catch (error) {\n // 忽略URL解析错误\n }\n\n return \"bin\";\n};\n\nconst saveMockData = async (\n url: string,\n method: string,\n data: Buffer | string,\n rootDir: string,\n statusCode?: number,\n contentType?: string,\n): Promise<string | null> => {\n try {\n const absoluteRootDir = path.isAbsolute(rootDir)\n ? rootDir\n : path.resolve(process.cwd(), rootDir);\n\n // 正确解析URL,处理查询参数和路径\n let pathname: string;\n let search: string;\n\n try {\n // 如果url包含协议信息,直接解析\n if (url.startsWith(\"http\")) {\n const urlObj = new URL(url);\n pathname = urlObj.pathname;\n search = urlObj.search;\n } else {\n // 如果是相对路径,先补全协议\n const urlObj = new URL(url, \"http://localhost\");\n pathname = urlObj.pathname;\n search = urlObj.search;\n }\n } catch (error) {\n // 如果URL解析失败,尝试手动处理\n const [pathPart, ...searchPart] = url.split(\"?\");\n pathname = pathPart;\n search = searchPart.length > 0 ? \"?\" + searchPart.join(\"?\") : \"\";\n }\n\n const filePath = path.join(\n absoluteRootDir,\n pathname.replace(/^\\//, \"\"),\n method.toLowerCase() + \".js\",\n );\n\n const dir = path.dirname(filePath);\n fs.ensureDirSync(dir);\n\n // 检测是否为二进制文件\n const isBuffer = Buffer.isBuffer(data);\n const binaryData = isBuffer ? data : Buffer.from(data || \"\");\n const isBinary = isBinaryResponse(contentType, binaryData);\n\n if (isBinary) {\n // 二进制文件处理\n const extension = getFileExtension(contentType, url);\n const binaryFilePath = filePath.replace(/\\.js$/, \".\" + extension);\n\n // 检查文件是否已存在,如果存在则不覆盖\n if (fs.existsSync(binaryFilePath)) {\n return null;\n }\n\n // 保存二进制文件\n fs.writeFileSync(binaryFilePath, binaryData);\n\n // 创建对应的JS配置文件\n const configContent = `/**\n * Mock data for ${pathname} (${method.toUpperCase()})${search || \"\"}\n * @description ${pathname}${search || \"\"} - Binary file (${extension})\n * Generated at ${new Date().toISOString()}\n */\nexport default {\n enable: false,\n data: {\n __binaryFile: '${extension}',\n __originalPath: '${pathname}',\n __originalQuery: '${search}',\n __originalUrl: '${pathname}${search || \"\"}',\n __contentType: '${contentType}',\n __fileSize: ${binaryData.length}\n },\n delay: 0,\n status: ${statusCode || 200}\n}`;\n\n try {\n const formattedCode = await prettier.format(configContent, {\n parser: \"babel\",\n });\n fs.writeFileSync(filePath, formattedCode, \"utf-8\");\n } catch (error) {\n fs.writeFileSync(filePath, configContent, \"utf-8\");\n }\n\n return filePath;\n } else {\n // JSON文件处理\n // 检查文件是否已存在,如果存在则不覆盖\n if (fs.existsSync(filePath)) {\n return null;\n }\n\n const dataStr = isBuffer ? data.toString(\"utf8\") : data || \"\";\n let jsonData;\n // 如果响应为空或只包含空白字符\n if (!dataStr || dataStr.trim() === \"\") {\n jsonData = {\n error: true,\n message: `Empty response (${statusCode || \"unknown status\"})`,\n status: statusCode || 404,\n data: null,\n };\n } else {\n try {\n jsonData = JSON.parse(dataStr);\n // 如果解析成功且是错误状态码,添加错误标记\n if (statusCode && statusCode >= 400) {\n if (typeof jsonData === \"object\" && jsonData !== null) {\n jsonData = {\n ...jsonData,\n __mockStatusCode: statusCode,\n __isErrorResponse: true,\n };\n } else {\n jsonData = {\n originalData: jsonData,\n __mockStatusCode: statusCode,\n __isErrorResponse: true,\n };\n }\n }\n } catch {\n // 如果不是JSON格式,可能是HTML错误页面或其他格式\n jsonData = {\n error: true,\n message: `Non-JSON response (${statusCode || \"unknown status\"})`,\n status: statusCode || 404,\n data: dataStr,\n __mockStatusCode: statusCode,\n __isErrorResponse: true,\n };\n }\n }\n\n const content = `/**\n * Mock data for ${pathname} (${method.toUpperCase()})${search || \"\"}\n * @description ${pathname}${search || \"\"}\n * Generated at ${new Date().toISOString()}\n */\nexport default {\n enable: false,\n data: ${JSON.stringify(jsonData)},\n delay: 0,\n status: ${statusCode || 200}\n}`;\n\n try {\n const formattedCode = await prettier.format(content, {\n parser: \"babel\",\n });\n fs.writeFileSync(filePath, formattedCode, \"utf-8\");\n return filePath;\n } catch (error) {\n fs.writeFileSync(filePath, content, \"utf-8\");\n return filePath;\n }\n }\n } catch (error) {\n console.error(`Failed to save mock data for ${url}:`, error);\n console.error(\n `URL details: url=${url}, method=${method}, statusCode=${statusCode}, contentType=${contentType}`,\n );\n throw error;\n }\n};\n\nconst recursiveReadAllFiles = (dir: string): string[] => {\n if (!fs.existsSync(dir)) return [];\n\n const files: string[] = [];\n try {\n const list = fs.readdirSync(dir);\n list.forEach((file) => {\n const filePath = path.join(dir, file);\n const stat = fs.statSync(filePath);\n if (stat.isDirectory()) {\n files.push(...recursiveReadAllFiles(filePath));\n } else {\n files.push(filePath);\n }\n });\n } catch (error) {\n console.error(`Error reading directory ${dir}:`, error);\n }\n return files;\n};\n\nconst buildMockIndex = (mockDir: string): Map<string, string> => {\n const mockFileMap = new Map<string, string>();\n\n if (!fs.existsSync(mockDir)) {\n fs.ensureDirSync(mockDir);\n return mockFileMap;\n }\n\n const files = recursiveReadAllFiles(mockDir);\n\n files.forEach((filePath) => {\n if (!filePath.endsWith(\".js\")) {\n return;\n }\n\n try {\n const relativePath = path.relative(mockDir, filePath);\n const method = path.basename(filePath, \".js\");\n const dirPath = path.dirname(relativePath);\n const urlPath = \"/\" + toPosixPath(dirPath);\n const absolutePath = path.isAbsolute(filePath)\n ? filePath\n : path.resolve(process.cwd(), filePath);\n const key = `${urlPath}/${method}.js`.toLowerCase();\n\n mockFileMap.set(key, absolutePath);\n } catch (error) {\n console.error(`❌ [automock] 处理文件失败 ${filePath}:`, error);\n }\n });\n\n return mockFileMap;\n};\n\nconst parseMockModule = async (filePath: string): Promise<MockFileInfo> => {\n const absolutePath = path.isAbsolute(filePath)\n ? filePath\n : path.resolve(process.cwd(), filePath);\n\n if (!fs.existsSync(absolutePath)) {\n throw new Error(`Mock file does not exist: ${absolutePath}`);\n }\n\n const content = fs.readFileSync(absolutePath, \"utf-8\");\n const headerCommentMatch = content.match(/^(\\/\\*\\*[\\s\\S]*?\\*\\/)/);\n const headerComment = headerCommentMatch ? headerCommentMatch[1] : undefined;\n\n // 提取 @description\n let description: string | undefined;\n if (headerComment) {\n const descMatch = headerComment.match(/@description\\s+(.+?)(?:\\n|\\*\\/)/s);\n if (descMatch) {\n description = descMatch[1].trim();\n }\n }\n\n const { default: mockModule } = await import(\n `${absolutePath}?t=${Date.now()}`\n );\n\n const exportedConfig =\n typeof mockModule === \"function\" ? mockModule() : mockModule;\n const hasDynamicData = typeof exportedConfig?.data === \"function\";\n const config: MockFileConfig = {\n ...DEFAULT_CONFIG,\n ...(exportedConfig ?? {}),\n };\n\n const serializable = !hasDynamicData;\n const dataObj =\n typeof config.data === \"object\" && config.data !== null\n ? (config.data as Record<string, unknown>)\n : null;\n const isBinary = dataObj !== null && \"__binaryFile\" in dataObj;\n\n return {\n config,\n serializable,\n hasDynamicData,\n headerComment,\n description,\n dataText: isBinary\n ? `/* Binary file: ${dataObj?.__binaryFile} */`\n : serializable\n ? JSON.stringify(config.data ?? null, null, 2)\n : \"/* data is generated dynamically and cannot be edited here */\",\n isBinary,\n };\n};\n\nconst writeMockFile = async (\n filePath: string,\n mockInfo: Pick<MockFileInfo, \"config\" | \"headerComment\" | \"description\">,\n): Promise<void> => {\n const absolutePath = path.isAbsolute(filePath)\n ? filePath\n : path.resolve(process.cwd(), filePath);\n\n let header = mockInfo.headerComment || \"\";\n\n // 如果提供了 description,更新或添加到注释中\n if (mockInfo.description !== undefined) {\n if (header) {\n // 替换现有的 @description\n if (/@description/.test(header)) {\n header = header.replace(\n /@description\\s+.+?(?=\\n|\\*\\/)/s,\n `@description ${mockInfo.description}`,\n );\n } else {\n // 在最后一行之前添加 @description\n header = header.replace(\n /\\*\\//,\n ` * @description ${mockInfo.description}\\n */`,\n );\n }\n }\n }\n\n const content = header ? `${header}\\n` : \"\";\n const finalContent = `${content}export default ${JSON.stringify(mockInfo.config, null, 2)}\\n`;\n\n try {\n const formattedCode = await prettier.format(finalContent, {\n parser: \"babel\",\n });\n fs.writeFileSync(absolutePath, formattedCode, \"utf-8\");\n } catch (error) {\n console.error(\"Error formatting code with prettier:\", error);\n fs.writeFileSync(absolutePath, finalContent, \"utf-8\");\n }\n};\n\nexport { saveMockData, buildMockIndex, parseMockModule, writeMockFile };\n"],"mappings":";AAAA,OAAO,UAAU;AACjB,OAAO,QAAQ;AACf,OAAO,cAAc;AAoBd,IAAM,iBAAiC;AAAA,EAC5C,QAAQ;AAAA,EACR,MAAM;AAAA,EACN,OAAO;AAAA,EACP,QAAQ;AACV;AAGA,SAAS,YAAY,GAAmB;AACtC,SAAO,EAAE,QAAQ,OAAO,GAAG;AAC7B;AAGA,IAAM,mBAAmB,CACvB,aACA,SACY;AACZ,MAAI,CAAC,YAAa,QAAO;AAEzB,QAAM,cAAc;AAAA,IAClB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAEA,SACE,YAAY,KAAK,CAAC,SAAS,YAAY,YAAY,EAAE,SAAS,IAAI,CAAC,KACnE,CAAC,iBAAiB,IAAI;AAE1B;AAGA,IAAM,mBAAmB,CAAC,WAA4B;AACpD,MAAI;AAEF,UAAM,SAAS,OAAO,MAAM,GAAG,GAAG;AAClC,UAAM,OAAO,OAAO,SAAS,MAAM;AAGnC,UAAM,YAAY,CAAC,GAAG,MAAM,EAAE,OAAO,CAAC,MAAM,MAAM,CAAC,EAAE;AACrD,UAAM,eAAe,CAAC,GAAG,MAAM,EAAE;AAAA,MAC/B,CAAC,MAAM,IAAI,MAAM,MAAM,KAAK,MAAM,MAAM,MAAM;AAAA,IAChD,EAAE;AAEF,WAAO,cAAc,KAAK,eAAe;AAAA,EAC3C,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAGA,IAAM,mBAAmB,CACvB,aACA,QACW;AAEX,QAAM,UAAkC;AAAA,IACtC,oBAAoB;AAAA,IACpB,mBAAmB;AAAA,IACnB,mBAAmB;AAAA,IACnB,4BAA4B;AAAA,IAC5B,qEAAqE;AAAA,IACrE,sBAAsB;AAAA,IACtB,2EACE;AAAA,IACF,iCAAiC;AAAA,IACjC,6EACE;AAAA,IACF,cAAc;AAAA,IACd,aAAa;AAAA,IACb,aAAa;AAAA,IACb,cAAc;AAAA,IACd,aAAa;AAAA,IACb,YAAY;AAAA,IACZ,0BAA0B;AAAA,IAC1B,YAAY;AAAA,EACd;AAEA,MAAI,eAAe,QAAQ,YAAY,YAAY,CAAC,GAAG;AACrD,WAAO,QAAQ,YAAY,YAAY,CAAC;AAAA,EAC1C;AAGA,MAAI;AACF,UAAM,SAAS,IAAI,IAAI,KAAK,kBAAkB;AAC9C,UAAM,WAAW,OAAO,aAAa,IAAI,WAAW;AACpD,QAAI,UAAU;AACZ,YAAM,iBAAiB,SAAS,MAAM,mBAAmB;AACzD,UAAI,gBAAgB;AAClB,eAAO,eAAe,CAAC;AAAA,MACzB;AAAA,IACF;AAAA,EACF,SAAS,OAAO;AAAA,EAEhB;AAEA,SAAO;AACT;AAEA,IAAM,eAAe,OACnB,KACA,QACA,MACA,SACA,YACA,gBAC2B;AAC3B,MAAI;AACF,UAAM,kBAAkB,KAAK,WAAW,OAAO,IAC3C,UACA,KAAK,QAAQ,QAAQ,IAAI,GAAG,OAAO;AAGvC,QAAI;AACJ,QAAI;AAEJ,QAAI;AAEF,UAAI,IAAI,WAAW,MAAM,GAAG;AAC1B,cAAM,SAAS,IAAI,IAAI,GAAG;AAC1B,mBAAW,OAAO;AAClB,iBAAS,OAAO;AAAA,MAClB,OAAO;AAEL,cAAM,SAAS,IAAI,IAAI,KAAK,kBAAkB;AAC9C,mBAAW,OAAO;AAClB,iBAAS,OAAO;AAAA,MAClB;AAAA,IACF,SAAS,OAAO;AAEd,YAAM,CAAC,UAAU,GAAG,UAAU,IAAI,IAAI,MAAM,GAAG;AAC/C,iBAAW;AACX,eAAS,WAAW,SAAS,IAAI,MAAM,WAAW,KAAK,GAAG,IAAI;AAAA,IAChE;AAEA,UAAM,WAAW,KAAK;AAAA,MACpB;AAAA,MACA,SAAS,QAAQ,OAAO,EAAE;AAAA,MAC1B,OAAO,YAAY,IAAI;AAAA,IACzB;AAEA,UAAM,MAAM,KAAK,QAAQ,QAAQ;AACjC,OAAG,cAAc,GAAG;AAGpB,UAAM,WAAW,OAAO,SAAS,IAAI;AACrC,UAAM,aAAa,WAAW,OAAO,OAAO,KAAK,QAAQ,EAAE;AAC3D,UAAM,WAAW,iBAAiB,aAAa,UAAU;AAEzD,QAAI,UAAU;AAEZ,YAAM,YAAY,iBAAiB,aAAa,GAAG;AACnD,YAAM,iBAAiB,SAAS,QAAQ,SAAS,MAAM,SAAS;AAGhE,UAAI,GAAG,WAAW,cAAc,GAAG;AACjC,eAAO;AAAA,MACT;AAGA,SAAG,cAAc,gBAAgB,UAAU;AAG3C,YAAM,gBAAgB;AAAA,mBACT,QAAQ,KAAK,OAAO,YAAY,CAAC,IAAI,UAAU,EAAE;AAAA,kBAClD,QAAQ,GAAG,UAAU,EAAE,mBAAmB,SAAS;AAAA,mBACnD,oBAAI,KAAK,GAAE,YAAY,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA,qBAKrB,SAAS;AAAA,uBACP,QAAQ;AAAA,wBACP,MAAM;AAAA,sBACR,QAAQ,GAAG,UAAU,EAAE;AAAA,sBACvB,WAAW;AAAA,kBACf,WAAW,MAAM;AAAA;AAAA;AAAA,YAGvB,cAAc,GAAG;AAAA;AAGvB,UAAI;AACF,cAAM,gBAAgB,MAAM,SAAS,OAAO,eAAe;AAAA,UACzD,QAAQ;AAAA,QACV,CAAC;AACD,WAAG,cAAc,UAAU,eAAe,OAAO;AAAA,MACnD,SAAS,OAAO;AACd,WAAG,cAAc,UAAU,eAAe,OAAO;AAAA,MACnD;AAEA,aAAO;AAAA,IACT,OAAO;AAGL,UAAI,GAAG,WAAW,QAAQ,GAAG;AAC3B,eAAO;AAAA,MACT;AAEA,YAAM,UAAU,WAAW,KAAK,SAAS,MAAM,IAAI,QAAQ;AAC3D,UAAI;AAEJ,UAAI,CAAC,WAAW,QAAQ,KAAK,MAAM,IAAI;AACrC,mBAAW;AAAA,UACT,OAAO;AAAA,UACP,SAAS,mBAAmB,cAAc,gBAAgB;AAAA,UAC1D,QAAQ,cAAc;AAAA,UACtB,MAAM;AAAA,QACR;AAAA,MACF,OAAO;AACL,YAAI;AACF,qBAAW,KAAK,MAAM,OAAO;AAE7B,cAAI,cAAc,cAAc,KAAK;AACnC,gBAAI,OAAO,aAAa,YAAY,aAAa,MAAM;AACrD,yBAAW;AAAA,gBACT,GAAG;AAAA,gBACH,kBAAkB;AAAA,gBAClB,mBAAmB;AAAA,cACrB;AAAA,YACF,OAAO;AACL,yBAAW;AAAA,gBACT,cAAc;AAAA,gBACd,kBAAkB;AAAA,gBAClB,mBAAmB;AAAA,cACrB;AAAA,YACF;AAAA,UACF;AAAA,QACF,QAAQ;AAEN,qBAAW;AAAA,YACT,OAAO;AAAA,YACP,SAAS,sBAAsB,cAAc,gBAAgB;AAAA,YAC7D,QAAQ,cAAc;AAAA,YACtB,MAAM;AAAA,YACN,kBAAkB;AAAA,YAClB,mBAAmB;AAAA,UACrB;AAAA,QACF;AAAA,MACF;AAEA,YAAM,UAAU;AAAA,mBACH,QAAQ,KAAK,OAAO,YAAY,CAAC,IAAI,UAAU,EAAE;AAAA,kBAClD,QAAQ,GAAG,UAAU,EAAE;AAAA,mBACvB,oBAAI,KAAK,GAAE,YAAY,CAAC;AAAA;AAAA;AAAA;AAAA,UAIhC,KAAK,UAAU,QAAQ,CAAC;AAAA;AAAA,YAEtB,cAAc,GAAG;AAAA;AAGvB,UAAI;AACF,cAAM,gBAAgB,MAAM,SAAS,OAAO,SAAS;AAAA,UACnD,QAAQ;AAAA,QACV,CAAC;AACD,WAAG,cAAc,UAAU,eAAe,OAAO;AACjD,eAAO;AAAA,MACT,SAAS,OAAO;AACd,WAAG,cAAc,UAAU,SAAS,OAAO;AAC3C,eAAO;AAAA,MACT;AAAA,IACF;AAAA,EACF,SAAS,OAAO;AACd,YAAQ,MAAM,gCAAgC,GAAG,KAAK,KAAK;AAC3D,YAAQ;AAAA,MACN,oBAAoB,GAAG,YAAY,MAAM,gBAAgB,UAAU,iBAAiB,WAAW;AAAA,IACjG;AACA,UAAM;AAAA,EACR;AACF;AAEA,IAAM,wBAAwB,CAAC,QAA0B;AACvD,MAAI,CAAC,GAAG,WAAW,GAAG,EAAG,QAAO,CAAC;AAEjC,QAAM,QAAkB,CAAC;AACzB,MAAI;AACF,UAAM,OAAO,GAAG,YAAY,GAAG;AAC/B,SAAK,QAAQ,CAAC,SAAS;AACrB,YAAM,WAAW,KAAK,KAAK,KAAK,IAAI;AACpC,YAAM,OAAO,GAAG,SAAS,QAAQ;AACjC,UAAI,KAAK,YAAY,GAAG;AACtB,cAAM,KAAK,GAAG,sBAAsB,QAAQ,CAAC;AAAA,MAC/C,OAAO;AACL,cAAM,KAAK,QAAQ;AAAA,MACrB;AAAA,IACF,CAAC;AAAA,EACH,SAAS,OAAO;AACd,YAAQ,MAAM,2BAA2B,GAAG,KAAK,KAAK;AAAA,EACxD;AACA,SAAO;AACT;AAEA,IAAM,iBAAiB,CAAC,YAAyC;AAC/D,QAAM,cAAc,oBAAI,IAAoB;AAE5C,MAAI,CAAC,GAAG,WAAW,OAAO,GAAG;AAC3B,OAAG,cAAc,OAAO;AACxB,WAAO;AAAA,EACT;AAEA,QAAM,QAAQ,sBAAsB,OAAO;AAE3C,QAAM,QAAQ,CAAC,aAAa;AAC1B,QAAI,CAAC,SAAS,SAAS,KAAK,GAAG;AAC7B;AAAA,IACF;AAEA,QAAI;AACF,YAAM,eAAe,KAAK,SAAS,SAAS,QAAQ;AACpD,YAAM,SAAS,KAAK,SAAS,UAAU,KAAK;AAC5C,YAAM,UAAU,KAAK,QAAQ,YAAY;AACzC,YAAM,UAAU,MAAM,YAAY,OAAO;AACzC,YAAM,eAAe,KAAK,WAAW,QAAQ,IACzC,WACA,KAAK,QAAQ,QAAQ,IAAI,GAAG,QAAQ;AACxC,YAAM,MAAM,GAAG,OAAO,IAAI,MAAM,MAAM,YAAY;AAElD,kBAAY,IAAI,KAAK,YAAY;AAAA,IACnC,SAAS,OAAO;AACd,cAAQ,MAAM,0DAAuB,QAAQ,KAAK,KAAK;AAAA,IACzD;AAAA,EACF,CAAC;AAED,SAAO;AACT;AAEA,IAAM,kBAAkB,OAAO,aAA4C;AACzE,QAAM,eAAe,KAAK,WAAW,QAAQ,IACzC,WACA,KAAK,QAAQ,QAAQ,IAAI,GAAG,QAAQ;AAExC,MAAI,CAAC,GAAG,WAAW,YAAY,GAAG;AAChC,UAAM,IAAI,MAAM,6BAA6B,YAAY,EAAE;AAAA,EAC7D;AAEA,QAAM,UAAU,GAAG,aAAa,cAAc,OAAO;AACrD,QAAM,qBAAqB,QAAQ,MAAM,uBAAuB;AAChE,QAAM,gBAAgB,qBAAqB,mBAAmB,CAAC,IAAI;AAGnE,MAAI;AACJ,MAAI,eAAe;AACjB,UAAM,YAAY,cAAc,MAAM,kCAAkC;AACxE,QAAI,WAAW;AACb,oBAAc,UAAU,CAAC,EAAE,KAAK;AAAA,IAClC;AAAA,EACF;AAEA,QAAM,EAAE,SAAS,WAAW,IAAI,MAAM,OACpC,GAAG,YAAY,MAAM,KAAK,IAAI,CAAC;AAGjC,QAAM,iBACJ,OAAO,eAAe,aAAa,WAAW,IAAI;AACpD,QAAM,iBAAiB,OAAO,gBAAgB,SAAS;AACvD,QAAM,SAAyB;AAAA,IAC7B,GAAG;AAAA,IACH,GAAI,kBAAkB,CAAC;AAAA,EACzB;AAEA,QAAM,eAAe,CAAC;AACtB,QAAM,UACJ,OAAO,OAAO,SAAS,YAAY,OAAO,SAAS,OAC9C,OAAO,OACR;AACN,QAAM,WAAW,YAAY,QAAQ,kBAAkB;AAEvD,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,UAAU,WACN,mBAAmB,SAAS,YAAY,QACxC,eACE,KAAK,UAAU,OAAO,QAAQ,MAAM,MAAM,CAAC,IAC3C;AAAA,IACN;AAAA,EACF;AACF;AAEA,IAAM,gBAAgB,OACpB,UACA,aACkB;AAClB,QAAM,eAAe,KAAK,WAAW,QAAQ,IACzC,WACA,KAAK,QAAQ,QAAQ,IAAI,GAAG,QAAQ;AAExC,MAAI,SAAS,SAAS,iBAAiB;AAGvC,MAAI,SAAS,gBAAgB,QAAW;AACtC,QAAI,QAAQ;AAEV,UAAI,eAAe,KAAK,MAAM,GAAG;AAC/B,iBAAS,OAAO;AAAA,UACd;AAAA,UACA,gBAAgB,SAAS,WAAW;AAAA,QACtC;AAAA,MACF,OAAO;AAEL,iBAAS,OAAO;AAAA,UACd;AAAA,UACA,mBAAmB,SAAS,WAAW;AAAA;AAAA,QACzC;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,QAAM,UAAU,SAAS,GAAG,MAAM;AAAA,IAAO;AACzC,QAAM,eAAe,GAAG,OAAO,kBAAkB,KAAK,UAAU,SAAS,QAAQ,MAAM,CAAC,CAAC;AAAA;AAEzF,MAAI;AACF,UAAM,gBAAgB,MAAM,SAAS,OAAO,cAAc;AAAA,MACxD,QAAQ;AAAA,IACV,CAAC;AACD,OAAG,cAAc,cAAc,eAAe,OAAO;AAAA,EACvD,SAAS,OAAO;AACd,YAAQ,MAAM,wCAAwC,KAAK;AAC3D,OAAG,cAAc,cAAc,cAAc,OAAO;AAAA,EACtD;AACF;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/mockFileUtils.ts"],"sourcesContent":["import path from \"path\";\nimport fs from \"fs-extra\";\nimport prettier from \"prettier\";\n\nexport interface MockFileConfig {\n enable: boolean;\n data: unknown;\n delay: number;\n status: number;\n [key: string]: unknown;\n}\n\nexport interface MockFileInfo {\n config: MockFileConfig;\n serializable: boolean;\n hasDynamicData: boolean;\n headerComment?: string;\n description?: string;\n dataText: string;\n isBinary?: boolean;\n}\n\nexport const DEFAULT_CONFIG: MockFileConfig = {\n enable: true,\n data: null,\n delay: 0,\n status: 200,\n};\n\n// 简单实现 cross-platform 路径分隔符转换\nfunction toPosixPath(p: string): string {\n return p.replace(/\\\\/g, \"/\");\n}\n\n// 检测是否为二进制文件\nconst isBinaryResponse = (\n contentType: string | undefined,\n data: Buffer,\n): boolean => {\n if (!contentType) return false;\n\n const binaryTypes = [\n \"application/octet-stream\",\n \"application/pdf\",\n \"application/zip\",\n \"application/x-zip-compressed\",\n \"application/vnd.ms-excel\",\n \"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\",\n \"application/msword\",\n \"application/vnd.openxmlformats-officedocument.wordprocessingml.document\",\n \"application/vnd.ms-powerpoint\",\n \"application/vnd.openxmlformats-officedocument.presentationml.presentation\",\n \"image/\",\n \"video/\",\n \"audio/\",\n ];\n\n return (\n binaryTypes.some((type) => contentType.toLowerCase().includes(type)) ||\n !isBufferTextLike(data)\n );\n};\n\n// 检测Buffer是否像文本数据\nconst isBufferTextLike = (buffer: Buffer): boolean => {\n try {\n // 检查前100字节是否包含非文本字符\n const sample = buffer.slice(0, 100);\n const text = sample.toString(\"utf8\");\n\n // 如果包含null字节或过多的控制字符,可能是二进制\n const nullBytes = [...sample].filter((b) => b === 0).length;\n const controlChars = [...sample].filter(\n (b) => b < 32 && b !== 9 && b !== 10 && b !== 13,\n ).length;\n\n return nullBytes === 0 && controlChars < 5;\n } catch {\n return false;\n }\n};\n\n// 从Content-Type获取文件扩展名\nconst getFileExtension = (\n contentType: string | undefined,\n url: string,\n): string => {\n // 从Content-Type映射\n const mimeMap: Record<string, string> = {\n \"application/json\": \"json\",\n \"application/pdf\": \"pdf\",\n \"application/zip\": \"zip\",\n \"application/vnd.ms-excel\": \"xls\",\n \"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\": \"xlsx\",\n \"application/msword\": \"doc\",\n \"application/vnd.openxmlformats-officedocument.wordprocessingml.document\":\n \"docx\",\n \"application/vnd.ms-powerpoint\": \"ppt\",\n \"application/vnd.openxmlformats-officedocument.presentationml.presentation\":\n \"pptx\",\n \"image/jpeg\": \"jpg\",\n \"image/png\": \"png\",\n \"image/gif\": \"gif\",\n \"text/plain\": \"txt\",\n \"text/html\": \"html\",\n \"text/css\": \"css\",\n \"application/javascript\": \"js\",\n \"text/xml\": \"xml\",\n };\n\n if (contentType && mimeMap[contentType.toLowerCase()]) {\n return mimeMap[contentType.toLowerCase()];\n }\n\n // 尝试从URL的查询参数中解析文件名\n try {\n const urlObj = new URL(url, \"http://localhost\");\n const fileName = urlObj.searchParams.get(\"file_name\");\n if (fileName) {\n const extensionMatch = fileName.match(/\\.([a-zA-Z0-9]+)$/);\n if (extensionMatch) {\n return extensionMatch[1];\n }\n }\n } catch (error) {\n // 忽略URL解析错误\n }\n\n return \"bin\";\n};\n\nconst saveMockData = async (\n url: string,\n method: string,\n data: Buffer | string,\n rootDir: string,\n statusCode?: number,\n contentType?: string,\n): Promise<string | null> => {\n try {\n const absoluteRootDir = path.isAbsolute(rootDir)\n ? rootDir\n : path.resolve(process.cwd(), rootDir);\n\n // 正确解析URL,处理查询参数和路径\n let pathname: string;\n let search: string;\n\n try {\n // 如果url包含协议信息,直接解析\n if (url.startsWith(\"http\")) {\n const urlObj = new URL(url);\n pathname = urlObj.pathname;\n search = urlObj.search;\n } else {\n // 如果是相对路径,先补全协议\n const urlObj = new URL(url, \"http://localhost\");\n pathname = urlObj.pathname;\n search = urlObj.search;\n }\n } catch (error) {\n // 如果URL解析失败,尝试手动处理\n const [pathPart, ...searchPart] = url.split(\"?\");\n pathname = pathPart;\n search = searchPart.length > 0 ? \"?\" + searchPart.join(\"?\") : \"\";\n }\n\n const filePath = path.join(\n absoluteRootDir,\n pathname.replace(/^\\//, \"\"),\n method.toLowerCase() + \".js\",\n );\n\n const dir = path.dirname(filePath);\n fs.ensureDirSync(dir);\n\n // 检测是否为二进制文件\n const isBuffer = Buffer.isBuffer(data);\n const binaryData = isBuffer ? data : Buffer.from(data || \"\");\n const isBinary = isBinaryResponse(contentType, binaryData);\n\n if (isBinary) {\n // 二进制文件处理\n const extension = getFileExtension(contentType, url);\n const binaryFilePath = filePath.replace(/\\.js$/, \".\" + extension);\n\n // 检查文件是否已存在,如果存在则不覆盖\n if (fs.existsSync(binaryFilePath)) {\n return null;\n }\n\n // 保存二进制文件\n fs.writeFileSync(binaryFilePath, binaryData);\n\n // 创建对应的JS配置文件\n const configContent = `/**\n * Mock data for ${pathname} (${method.toUpperCase()})${search || \"\"}\n * @description ${pathname}${search || \"\"} - Binary file (${extension})\n * Generated at ${new Date().toISOString()}\n */\nexport default {\n enable: false,\n data: {\n __binaryFile: '${extension}',\n __originalPath: '${pathname}',\n __originalQuery: '${search}',\n __originalUrl: '${pathname}${search || \"\"}',\n __contentType: '${contentType}',\n __fileSize: ${binaryData.length}\n },\n delay: 0,\n status: ${statusCode || 200}\n}`;\n\n try {\n const formattedCode = await prettier.format(configContent, {\n parser: \"babel\",\n });\n fs.writeFileSync(filePath, formattedCode, \"utf-8\");\n } catch (error) {\n fs.writeFileSync(filePath, configContent, \"utf-8\");\n }\n\n return filePath;\n } else {\n // JSON文件处理\n // 检查文件是否已存在,如果存在则不覆盖\n if (fs.existsSync(filePath)) {\n return null;\n }\n\n const dataStr = isBuffer ? data.toString(\"utf8\") : data || \"\";\n let jsonData;\n // 如果响应为空或只包含空白字符\n if (!dataStr || dataStr.trim() === \"\") {\n jsonData = {\n error: true,\n message: `Empty response (${statusCode || \"unknown status\"})`,\n status: statusCode || 404,\n data: null,\n };\n } else {\n try {\n jsonData = JSON.parse(dataStr);\n // 如果解析成功且是错误状态码,添加错误标记\n if (statusCode && statusCode >= 400) {\n if (typeof jsonData === \"object\" && jsonData !== null) {\n jsonData = {\n ...jsonData,\n __mockStatusCode: statusCode,\n __isErrorResponse: true,\n };\n } else {\n jsonData = {\n originalData: jsonData,\n __mockStatusCode: statusCode,\n __isErrorResponse: true,\n };\n }\n }\n } catch {\n // 如果不是JSON格式,可能是HTML错误页面或其他格式\n jsonData = {\n error: true,\n message: `Non-JSON response (${statusCode || \"unknown status\"})`,\n status: statusCode || 404,\n data: dataStr,\n __mockStatusCode: statusCode,\n __isErrorResponse: true,\n };\n }\n }\n\n const content = `/**\n * Mock data for ${pathname} (${method.toUpperCase()})${search || \"\"}\n * @description ${pathname}${search || \"\"}\n * Generated at ${new Date().toISOString()}\n */\nexport default {\n enable: false,\n data: ${JSON.stringify(jsonData)},\n delay: 0,\n status: ${statusCode || 200}\n}`;\n\n try {\n const formattedCode = await prettier.format(content, {\n parser: \"babel\",\n });\n fs.writeFileSync(filePath, formattedCode, \"utf-8\");\n return filePath;\n } catch (error) {\n fs.writeFileSync(filePath, content, \"utf-8\");\n return filePath;\n }\n }\n } catch (error) {\n console.error(`Failed to save mock data for ${url}:`, error);\n console.error(\n `URL details: url=${url}, method=${method}, statusCode=${statusCode}, contentType=${contentType}`,\n );\n throw error;\n }\n};\n\nconst recursiveReadAllFiles = (dir: string): string[] => {\n if (!fs.existsSync(dir)) return [];\n\n const files: string[] = [];\n try {\n const list = fs.readdirSync(dir);\n list.forEach((file) => {\n const filePath = path.join(dir, file);\n const stat = fs.statSync(filePath);\n if (stat.isDirectory()) {\n files.push(...recursiveReadAllFiles(filePath));\n } else {\n files.push(filePath);\n }\n });\n } catch (error) {\n console.error(`Error reading directory ${dir}:`, error);\n }\n return files;\n};\n\nconst buildMockIndex = (mockDir: string): Map<string, string> => {\n const mockFileMap = new Map<string, string>();\n\n if (!fs.existsSync(mockDir)) {\n fs.ensureDirSync(mockDir);\n return mockFileMap;\n }\n\n const files = recursiveReadAllFiles(mockDir);\n\n files.forEach((filePath) => {\n if (!filePath.endsWith(\".js\")) {\n return;\n }\n\n try {\n const relativePath = path.relative(mockDir, filePath);\n const method = path.basename(filePath, \".js\");\n const dirPath = path.dirname(relativePath);\n const urlPath = \"/\" + toPosixPath(dirPath);\n const absolutePath = path.isAbsolute(filePath)\n ? filePath\n : path.resolve(process.cwd(), filePath);\n const key = `${urlPath}/${method}.js`.toLowerCase();\n\n mockFileMap.set(key, absolutePath);\n } catch (error) {\n console.error(`❌ [automock] 处理文件失败 ${filePath}:`, error);\n }\n });\n\n return mockFileMap;\n};\n\nconst parseMockModule = async (filePath: string): Promise<MockFileInfo> => {\n const absolutePath = path.isAbsolute(filePath)\n ? filePath\n : path.resolve(process.cwd(), filePath);\n\n if (!fs.existsSync(absolutePath)) {\n throw new Error(`Mock file does not exist: ${absolutePath}`);\n }\n\n const content = fs.readFileSync(absolutePath, \"utf-8\");\n const headerCommentMatch = content.match(/^(\\/\\*\\*[\\s\\S]*?\\*\\/)/);\n const headerComment = headerCommentMatch ? headerCommentMatch[1] : undefined;\n\n // 提取 @description\n let description: string | undefined;\n if (headerComment) {\n const descMatch = headerComment.match(/@description\\s+(.+?)(?:\\n|\\*\\/)/s);\n if (descMatch) {\n description = descMatch[1].trim();\n }\n }\n\n const { default: mockModule } = await import(\n `${absolutePath}?t=${Date.now()}`\n );\n\n const exportedConfig =\n typeof mockModule === \"function\" ? mockModule() : mockModule;\n const hasDynamicData = typeof exportedConfig?.data === \"function\";\n const config: MockFileConfig = {\n ...DEFAULT_CONFIG,\n ...(exportedConfig ?? {}),\n };\n\n const serializable = !hasDynamicData;\n const dataObj =\n typeof config.data === \"object\" && config.data !== null\n ? (config.data as Record<string, unknown>)\n : null;\n const isBinary = dataObj !== null && \"__binaryFile\" in dataObj;\n\n return {\n config,\n serializable,\n hasDynamicData,\n headerComment,\n description,\n dataText: isBinary\n ? `/* Binary file: ${dataObj?.__binaryFile} */`\n : serializable\n ? JSON.stringify(config.data ?? null, null, 2)\n : \"/* data is generated dynamically and cannot be edited here */\",\n isBinary,\n };\n};\n\nconst writeMockFile = async (\n filePath: string,\n mockInfo: Pick<MockFileInfo, \"config\" | \"headerComment\" | \"description\">,\n): Promise<void> => {\n const absolutePath = path.isAbsolute(filePath)\n ? filePath\n : path.resolve(process.cwd(), filePath);\n\n let header = mockInfo.headerComment || \"\";\n\n // 如果提供了 description,更新或添加到注释中\n if (mockInfo.description !== undefined) {\n if (header) {\n // 替换现有的 @description\n if (/@description/.test(header)) {\n header = header.replace(\n /@description\\s+.+?(?=\\n|\\*\\/)/s,\n `@description ${mockInfo.description}`,\n );\n } else {\n // 在最后一行之前添加 @description\n header = header.replace(\n /\\*\\//,\n ` * @description ${mockInfo.description}\\n */`,\n );\n }\n }\n }\n\n const content = header ? `${header}\\n` : \"\";\n const finalContent = `${content}export default ${JSON.stringify(mockInfo.config, null, 2)}\\n`;\n\n try {\n const formattedCode = await prettier.format(finalContent, {\n parser: \"babel\",\n });\n fs.writeFileSync(absolutePath, formattedCode, \"utf-8\");\n } catch (error) {\n console.error(\"Error formatting code with prettier:\", error);\n fs.writeFileSync(absolutePath, finalContent, \"utf-8\");\n }\n};\n\nexport { saveMockData, buildMockIndex, parseMockModule, writeMockFile, toPosixPath };\n"],"mappings":"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","names":[]}
|
package/dist/index.js
CHANGED
|
@@ -37,6 +37,7 @@ __export(mockFileUtils_exports, {
|
|
|
37
37
|
buildMockIndex: () => buildMockIndex,
|
|
38
38
|
parseMockModule: () => parseMockModule,
|
|
39
39
|
saveMockData: () => saveMockData,
|
|
40
|
+
toPosixPath: () => toPosixPath,
|
|
40
41
|
writeMockFile: () => writeMockFile
|
|
41
42
|
});
|
|
42
43
|
function toPosixPath(p) {
|
|
@@ -2572,7 +2573,8 @@ async function handleInspectorApi({
|
|
|
2572
2573
|
for (const [key2, value] of newMockFileMap.entries()) {
|
|
2573
2574
|
mockFileMap.set(key2, value);
|
|
2574
2575
|
}
|
|
2575
|
-
const
|
|
2576
|
+
const normalizedPath = toPosixPath(apiPath);
|
|
2577
|
+
const key = (normalizedPath.startsWith("/") ? "" : "/") + normalizedPath.toLowerCase() + "/" + method.toLowerCase() + ".js";
|
|
2576
2578
|
const filePath = mockFileMap.get(key);
|
|
2577
2579
|
if (!filePath) {
|
|
2578
2580
|
sendJson(
|
|
@@ -2702,6 +2704,20 @@ function automock(options) {
|
|
|
2702
2704
|
mockDir,
|
|
2703
2705
|
getMockFileMap: () => mockFileMap
|
|
2704
2706
|
});
|
|
2707
|
+
server.httpServer?.once("listening", () => {
|
|
2708
|
+
setTimeout(() => {
|
|
2709
|
+
const address = server.httpServer?.address();
|
|
2710
|
+
if (address && typeof address === "object") {
|
|
2711
|
+
const protocol = server.config.server.https ? "https" : "http";
|
|
2712
|
+
const host = address.address === "::" || address.address === "0.0.0.0" ? "localhost" : address.address;
|
|
2713
|
+
const port = address.port;
|
|
2714
|
+
const mockApiUrl = `${protocol}://${host}:${port}${apiPrefix}`;
|
|
2715
|
+
console.log(
|
|
2716
|
+
` \u279C \x1B[32mMock API\x1B[0m: \x1B[1m${mockApiUrl}\x1B[0m`
|
|
2717
|
+
);
|
|
2718
|
+
}
|
|
2719
|
+
}, 100);
|
|
2720
|
+
});
|
|
2705
2721
|
if (inspector) {
|
|
2706
2722
|
const inspectorConfig = normalizeInspectorConfig(inspector);
|
|
2707
2723
|
server.httpServer?.once("listening", () => {
|
|
@@ -2713,10 +2729,10 @@ function automock(options) {
|
|
|
2713
2729
|
const port = address.port;
|
|
2714
2730
|
const inspectorUrl = `${protocol}://${host}:${port}${inspectorConfig.route}`;
|
|
2715
2731
|
console.log(
|
|
2716
|
-
` \u279C \x1B[
|
|
2732
|
+
` \u279C \x1B[95mMock Inspector\x1B[0m: \x1B[1m\x1B[96m${inspectorUrl}\x1B[0m`
|
|
2717
2733
|
);
|
|
2718
2734
|
}
|
|
2719
|
-
},
|
|
2735
|
+
}, 150);
|
|
2720
2736
|
});
|
|
2721
2737
|
}
|
|
2722
2738
|
server.middlewares.use(
|
|
@@ -2912,7 +2928,9 @@ function automock(options) {
|
|
|
2912
2928
|
sendProxyRequest2(bodyStr);
|
|
2913
2929
|
});
|
|
2914
2930
|
} else {
|
|
2915
|
-
|
|
2931
|
+
req.on("end", () => {
|
|
2932
|
+
sendProxyRequest2();
|
|
2933
|
+
});
|
|
2916
2934
|
}
|
|
2917
2935
|
} catch (error) {
|
|
2918
2936
|
console.error("\u274C [automock] \u4EE3\u7406\u8BF7\u6C42\u5F02\u5E38:", error);
|