apifox-mock-generator 1.0.0
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/CHANGELOG.md +131 -0
- package/LICENSE +22 -0
- package/README.md +788 -0
- package/dist/package.json +61 -0
- package/dist/src/core/apifox-client.d.ts +6 -0
- package/dist/src/core/apifox-client.d.ts.map +1 -0
- package/dist/src/core/apifox-client.js +114 -0
- package/dist/src/core/apifox-client.js.map +1 -0
- package/dist/src/core/config-loader.d.ts +6 -0
- package/dist/src/core/config-loader.d.ts.map +1 -0
- package/dist/src/core/config-loader.js +16 -0
- package/dist/src/core/config-loader.js.map +1 -0
- package/dist/src/core/endpoint-filter.d.ts +12 -0
- package/dist/src/core/endpoint-filter.d.ts.map +1 -0
- package/dist/src/core/endpoint-filter.js +77 -0
- package/dist/src/core/endpoint-filter.js.map +1 -0
- package/dist/src/core/openapi-converter.d.ts +6 -0
- package/dist/src/core/openapi-converter.d.ts.map +1 -0
- package/dist/src/core/openapi-converter.js +35 -0
- package/dist/src/core/openapi-converter.js.map +1 -0
- package/dist/src/generators/mock-generator.d.ts +6 -0
- package/dist/src/generators/mock-generator.d.ts.map +1 -0
- package/dist/src/generators/mock-generator.js +30 -0
- package/dist/src/generators/mock-generator.js.map +1 -0
- package/dist/src/generators/templates/mock-template.d.ts +6 -0
- package/dist/src/generators/templates/mock-template.d.ts.map +1 -0
- package/dist/src/generators/templates/mock-template.js +283 -0
- package/dist/src/generators/templates/mock-template.js.map +1 -0
- package/dist/src/generators/templates/type-template.d.ts +18 -0
- package/dist/src/generators/templates/type-template.d.ts.map +1 -0
- package/dist/src/generators/templates/type-template.js +201 -0
- package/dist/src/generators/templates/type-template.js.map +1 -0
- package/dist/src/generators/type-generator.d.ts +6 -0
- package/dist/src/generators/type-generator.d.ts.map +1 -0
- package/dist/src/generators/type-generator.js +31 -0
- package/dist/src/generators/type-generator.js.map +1 -0
- package/dist/src/index.d.ts +4 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +9 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/scripts/cli.d.ts +3 -0
- package/dist/src/scripts/cli.d.ts.map +1 -0
- package/dist/src/scripts/cli.js +28 -0
- package/dist/src/scripts/cli.js.map +1 -0
- package/dist/src/scripts/generate-mock.d.ts +2 -0
- package/dist/src/scripts/generate-mock.d.ts.map +1 -0
- package/dist/src/scripts/generate-mock.js +49 -0
- package/dist/src/scripts/generate-mock.js.map +1 -0
- package/dist/src/scripts/serve-mock.d.ts +2 -0
- package/dist/src/scripts/serve-mock.d.ts.map +1 -0
- package/dist/src/scripts/serve-mock.js +49 -0
- package/dist/src/scripts/serve-mock.js.map +1 -0
- package/dist/src/server/express-server.d.ts +7 -0
- package/dist/src/server/express-server.d.ts.map +1 -0
- package/dist/src/server/express-server.js +85 -0
- package/dist/src/server/express-server.js.map +1 -0
- package/dist/src/server/hot-reload.d.ts +7 -0
- package/dist/src/server/hot-reload.d.ts.map +1 -0
- package/dist/src/server/hot-reload.js +57 -0
- package/dist/src/server/hot-reload.js.map +1 -0
- package/dist/src/server/route-loader.d.ts +13 -0
- package/dist/src/server/route-loader.d.ts.map +1 -0
- package/dist/src/server/route-loader.js +147 -0
- package/dist/src/server/route-loader.js.map +1 -0
- package/dist/src/server/route-manager.d.ts +13 -0
- package/dist/src/server/route-manager.d.ts.map +1 -0
- package/dist/src/server/route-manager.js +25 -0
- package/dist/src/server/route-manager.js.map +1 -0
- package/dist/src/server/route-matcher.d.ts +10 -0
- package/dist/src/server/route-matcher.d.ts.map +1 -0
- package/dist/src/server/route-matcher.js +35 -0
- package/dist/src/server/route-matcher.js.map +1 -0
- package/dist/src/server/validation.d.ts +6 -0
- package/dist/src/server/validation.d.ts.map +1 -0
- package/dist/src/server/validation.js +119 -0
- package/dist/src/server/validation.js.map +1 -0
- package/dist/src/types/index.d.ts +167 -0
- package/dist/src/types/index.d.ts.map +1 -0
- package/dist/src/types/index.js +2 -0
- package/dist/src/types/index.js.map +1 -0
- package/dist/src/utils/block-updater.d.ts +6 -0
- package/dist/src/utils/block-updater.d.ts.map +1 -0
- package/dist/src/utils/block-updater.js +73 -0
- package/dist/src/utils/block-updater.js.map +1 -0
- package/dist/src/utils/code-formatter.d.ts +5 -0
- package/dist/src/utils/code-formatter.d.ts.map +1 -0
- package/dist/src/utils/code-formatter.js +43 -0
- package/dist/src/utils/code-formatter.js.map +1 -0
- package/dist/src/utils/file-helper.d.ts +21 -0
- package/dist/src/utils/file-helper.d.ts.map +1 -0
- package/dist/src/utils/file-helper.js +25 -0
- package/dist/src/utils/file-helper.js.map +1 -0
- package/dist/src/utils/file-operations.d.ts +29 -0
- package/dist/src/utils/file-operations.d.ts.map +1 -0
- package/dist/src/utils/file-operations.js +62 -0
- package/dist/src/utils/file-operations.js.map +1 -0
- package/dist/src/utils/logger.d.ts +10 -0
- package/dist/src/utils/logger.d.ts.map +1 -0
- package/dist/src/utils/logger.js +27 -0
- package/dist/src/utils/logger.js.map +1 -0
- package/dist/src/utils/path-utils.d.ts +13 -0
- package/dist/src/utils/path-utils.d.ts.map +1 -0
- package/dist/src/utils/path-utils.js +64 -0
- package/dist/src/utils/path-utils.js.map +1 -0
- package/dist/src/utils/type-mapping.d.ts +17 -0
- package/dist/src/utils/type-mapping.d.ts.map +1 -0
- package/dist/src/utils/type-mapping.js +75 -0
- package/dist/src/utils/type-mapping.js.map +1 -0
- package/package.json +61 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { logger } from '../utils/logger.js';
|
|
3
|
+
const command = process.argv[2];
|
|
4
|
+
switch (command) {
|
|
5
|
+
case 'generate':
|
|
6
|
+
await import('./generate-mock.js');
|
|
7
|
+
break;
|
|
8
|
+
case 'serve':
|
|
9
|
+
await import('./serve-mock.js');
|
|
10
|
+
break;
|
|
11
|
+
case 'dev':
|
|
12
|
+
logger.info('启动开发模式...');
|
|
13
|
+
await import('./generate-mock.js');
|
|
14
|
+
await import('./serve-mock.js');
|
|
15
|
+
break;
|
|
16
|
+
default:
|
|
17
|
+
console.log(`
|
|
18
|
+
Apifox Mock Generator v1.0.0
|
|
19
|
+
|
|
20
|
+
用法:
|
|
21
|
+
apifox-mock generate 生成 Mock 和类型文件
|
|
22
|
+
apifox-mock serve 启动 Mock 服务器
|
|
23
|
+
apifox-mock dev 开发模式(生成 + 服务器)
|
|
24
|
+
|
|
25
|
+
`);
|
|
26
|
+
process.exit(command ? 1 : 0);
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=cli.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../../../src/scripts/cli.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAA;AAE3C,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;AAE/B,QAAQ,OAAO,EAAE,CAAC;IAChB,KAAK,UAAU;QACb,MAAM,MAAM,CAAC,oBAAoB,CAAC,CAAA;QAClC,MAAK;IACP,KAAK,OAAO;QACV,MAAM,MAAM,CAAC,iBAAiB,CAAC,CAAA;QAC/B,MAAK;IACP,KAAK,KAAK;QACR,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAA;QACxB,MAAM,MAAM,CAAC,oBAAoB,CAAC,CAAA;QAClC,MAAM,MAAM,CAAC,iBAAiB,CAAC,CAAA;QAC/B,MAAK;IACP;QACE,OAAO,CAAC,GAAG,CAAC;;;;;;;;CAQf,CAAC,CAAA;QACE,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;AACjC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate-mock.d.ts","sourceRoot":"","sources":["../../../src/scripts/generate-mock.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { logger } from '../utils/logger.js';
|
|
2
|
+
import { loadConfig } from '../core/config-loader.js';
|
|
3
|
+
import { fetchOpenAPIFromApifox } from '../core/apifox-client.js';
|
|
4
|
+
import { convertOpenAPIToEndpoints } from '../core/openapi-converter.js';
|
|
5
|
+
import { filterEndpoints } from '../core/endpoint-filter.js';
|
|
6
|
+
import { generateMockFiles } from '../generators/mock-generator.js';
|
|
7
|
+
import { generateTypeFiles } from '../generators/type-generator.js';
|
|
8
|
+
/**
|
|
9
|
+
* 主函数
|
|
10
|
+
*/
|
|
11
|
+
async function main() {
|
|
12
|
+
try {
|
|
13
|
+
logger.title('🚀 开始生成 Mock 数据和 TypeScript 类型...');
|
|
14
|
+
const config = await loadConfig();
|
|
15
|
+
// 从 Apifox 拉取 OpenAPI 数据(直接在内存中处理)
|
|
16
|
+
const openapi = await fetchOpenAPIFromApifox(config);
|
|
17
|
+
// 转换为端点数据
|
|
18
|
+
const allEndpoints = convertOpenAPIToEndpoints(openapi);
|
|
19
|
+
logger.success(`✓ 解析到 ${allEndpoints.length} 个 API 接口`);
|
|
20
|
+
// 应用客户端筛选
|
|
21
|
+
const endpoints = filterEndpoints(allEndpoints, config.apiFilter);
|
|
22
|
+
if (config.apiFilter) {
|
|
23
|
+
const filteredCount = allEndpoints.length - endpoints.length;
|
|
24
|
+
if (filteredCount > 0) {
|
|
25
|
+
logger.info(` 应用客户端筛选规则,过滤掉 ${filteredCount} 个接口`);
|
|
26
|
+
}
|
|
27
|
+
logger.success(`✓ 保留 ${endpoints.length} 个接口用于生成`);
|
|
28
|
+
}
|
|
29
|
+
if (endpoints.length === 0) {
|
|
30
|
+
logger.warn('没有匹配的 API 接口,请检查筛选规则配置');
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
// 生成 Mock 文件
|
|
34
|
+
await generateMockFiles(config, endpoints, openapi.components?.schemas);
|
|
35
|
+
// 生成类型文件
|
|
36
|
+
await generateTypeFiles(config, openapi, endpoints);
|
|
37
|
+
logger.success('\n✨ 所有文件生成完成!');
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
// 避免重复显示错误信息
|
|
41
|
+
if (error instanceof Error && !error.message.includes('网络连接失败') && !error.message.includes('API 请求失败')) {
|
|
42
|
+
logger.error('生成失败');
|
|
43
|
+
console.error(error);
|
|
44
|
+
}
|
|
45
|
+
process.exit(1);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
main();
|
|
49
|
+
//# sourceMappingURL=generate-mock.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate-mock.js","sourceRoot":"","sources":["../../../src/scripts/generate-mock.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAA;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAA;AACrD,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAA;AACjE,OAAO,EAAE,yBAAyB,EAAE,MAAM,8BAA8B,CAAA;AACxE,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAA;AAC5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAA;AACnE,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAA;AAEnE;;GAEG;AACH,KAAK,UAAU,IAAI;IACjB,IAAI,CAAC;QACH,MAAM,CAAC,KAAK,CAAC,mCAAmC,CAAC,CAAA;QAEjD,MAAM,MAAM,GAAG,MAAM,UAAU,EAAE,CAAA;QAEjC,mCAAmC;QACnC,MAAM,OAAO,GAAG,MAAM,sBAAsB,CAAC,MAAM,CAAC,CAAA;QAEpD,UAAU;QACV,MAAM,YAAY,GAAG,yBAAyB,CAAC,OAAO,CAAC,CAAA;QACvD,MAAM,CAAC,OAAO,CAAC,SAAS,YAAY,CAAC,MAAM,WAAW,CAAC,CAAA;QAEvD,UAAU;QACV,MAAM,SAAS,GAAG,eAAe,CAAC,YAAY,EAAE,MAAM,CAAC,SAAS,CAAC,CAAA;QAEjE,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;YACrB,MAAM,aAAa,GAAG,YAAY,CAAC,MAAM,GAAG,SAAS,CAAC,MAAM,CAAA;YAC5D,IAAI,aAAa,GAAG,CAAC,EAAE,CAAC;gBACtB,MAAM,CAAC,IAAI,CAAC,mBAAmB,aAAa,MAAM,CAAC,CAAA;YACrD,CAAC;YACD,MAAM,CAAC,OAAO,CAAC,QAAQ,SAAS,CAAC,MAAM,UAAU,CAAC,CAAA;QACpD,CAAC;QAED,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC3B,MAAM,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAA;YACrC,OAAM;QACR,CAAC;QAED,aAAa;QACb,MAAM,iBAAiB,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,CAAC,UAAU,EAAE,OAAO,CAAC,CAAA;QAEvE,SAAS;QACT,MAAM,iBAAiB,CAAC,MAAM,EAAE,OAAO,EAAE,SAAS,CAAC,CAAA;QAEnD,MAAM,CAAC,OAAO,CAAC,eAAe,CAAC,CAAA;IAEjC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,aAAa;QACb,IAAI,KAAK,YAAY,KAAK,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;YACvG,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAA;YACpB,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;QACtB,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC;AACH,CAAC;AAED,IAAI,EAAE,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serve-mock.d.ts","sourceRoot":"","sources":["../../../src/scripts/serve-mock.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { logger } from '../utils/logger.js';
|
|
2
|
+
import { loadConfig } from '../core/config-loader.js';
|
|
3
|
+
import { RouteManager } from '../server/route-manager.js';
|
|
4
|
+
import { loadMockRoutes } from '../server/route-loader.js';
|
|
5
|
+
import { setupMockServer } from '../server/express-server.js';
|
|
6
|
+
import { setupHotReload } from '../server/hot-reload.js';
|
|
7
|
+
/**
|
|
8
|
+
* 主函数
|
|
9
|
+
*/
|
|
10
|
+
async function main() {
|
|
11
|
+
try {
|
|
12
|
+
const config = await loadConfig();
|
|
13
|
+
const routeManager = new RouteManager();
|
|
14
|
+
logger.title('启动 Mock 服务器...');
|
|
15
|
+
// 初始加载所有 Mock 路由
|
|
16
|
+
const routes = await loadMockRoutes(config);
|
|
17
|
+
routes.forEach(route => {
|
|
18
|
+
const key = `${route.method} ${route.path}`;
|
|
19
|
+
routeManager.setRoute(key, route);
|
|
20
|
+
});
|
|
21
|
+
logger.success(`加载了 ${routes.length} 个 Mock 路由`);
|
|
22
|
+
// 创建并启动服务器
|
|
23
|
+
const app = setupMockServer(routeManager);
|
|
24
|
+
app.listen(config.mockPort, () => {
|
|
25
|
+
logger.success(`\n🚀 Mock 服务器已启动!`);
|
|
26
|
+
logger.info(` 地址: http://localhost:${config.mockPort}`);
|
|
27
|
+
logger.info(` 路由数: ${routes.length}`);
|
|
28
|
+
logger.info('\n可用的 API 接口:');
|
|
29
|
+
routes.forEach(route => {
|
|
30
|
+
const method = route.method.padEnd(6);
|
|
31
|
+
console.log(` ${method} http://localhost:${config.mockPort}${route.path}`);
|
|
32
|
+
});
|
|
33
|
+
logger.info('\n提示:');
|
|
34
|
+
logger.info(' - 🔥 热重载已启用,修改 Mock 文件将自动生效');
|
|
35
|
+
logger.info(' - 按 Ctrl+C 停止服务器\n');
|
|
36
|
+
// 启动文件监听(热重载)
|
|
37
|
+
setupHotReload(config, routeManager);
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
logger.error('启动失败');
|
|
42
|
+
if (error instanceof Error) {
|
|
43
|
+
console.error(error);
|
|
44
|
+
}
|
|
45
|
+
process.exit(1);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
main();
|
|
49
|
+
//# sourceMappingURL=serve-mock.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serve-mock.js","sourceRoot":"","sources":["../../../src/scripts/serve-mock.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAA;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAA;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAA;AACzD,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAA;AAC1D,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAA;AAC7D,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAA;AAExD;;GAEG;AACH,KAAK,UAAU,IAAI;IACjB,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,UAAU,EAAE,CAAA;QACjC,MAAM,YAAY,GAAG,IAAI,YAAY,EAAE,CAAA;QAEvC,MAAM,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAA;QAE9B,iBAAiB;QACjB,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,MAAM,CAAC,CAAA;QAC3C,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE;YACrB,MAAM,GAAG,GAAG,GAAG,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,IAAI,EAAE,CAAA;YAC3C,YAAY,CAAC,QAAQ,CAAC,GAAG,EAAE,KAAK,CAAC,CAAA;QACnC,CAAC,CAAC,CAAA;QACF,MAAM,CAAC,OAAO,CAAC,OAAO,MAAM,CAAC,MAAM,YAAY,CAAC,CAAA;QAEhD,WAAW;QACX,MAAM,GAAG,GAAG,eAAe,CAAC,YAAY,CAAC,CAAA;QAEzC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,GAAG,EAAE;YAC/B,MAAM,CAAC,OAAO,CAAC,mBAAmB,CAAC,CAAA;YACnC,MAAM,CAAC,IAAI,CAAC,2BAA2B,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAA;YACzD,MAAM,CAAC,IAAI,CAAC,WAAW,MAAM,CAAC,MAAM,EAAE,CAAC,CAAA;YACvC,MAAM,CAAC,IAAI,CAAC,eAAe,CAAC,CAAA;YAE5B,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE;gBACrB,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAA;gBACrC,OAAO,CAAC,GAAG,CAAC,MAAM,MAAM,qBAAqB,MAAM,CAAC,QAAQ,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,CAAA;YAC9E,CAAC,CAAC,CAAA;YAEF,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;YACpB,MAAM,CAAC,IAAI,CAAC,+BAA+B,CAAC,CAAA;YAC5C,MAAM,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAA;YAEnC,cAAc;YACd,cAAc,CAAC,MAAM,EAAE,YAAY,CAAC,CAAA;QACtC,CAAC,CAAC,CAAA;IAEJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAA;QACpB,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;YAC3B,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;QACtB,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC;AACH,CAAC;AAED,IAAI,EAAE,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"express-server.d.ts","sourceRoot":"","sources":["../../../src/server/express-server.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,SAAS,CAAA;AAK7B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAEtD;;GAEG;AACH,wBAAgB,eAAe,CAAC,YAAY,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAuF/E"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import express from 'express';
|
|
2
|
+
import cors from 'cors';
|
|
3
|
+
import { logger } from '../utils/logger.js';
|
|
4
|
+
import { findMatchingRoute, extractPathParams } from './route-matcher.js';
|
|
5
|
+
import { validateRequest } from './validation.js';
|
|
6
|
+
/**
|
|
7
|
+
* 设置 Mock 服务器
|
|
8
|
+
*/
|
|
9
|
+
export function setupMockServer(routeManager) {
|
|
10
|
+
const app = express();
|
|
11
|
+
// 中间件
|
|
12
|
+
app.use(cors());
|
|
13
|
+
app.use(express.json());
|
|
14
|
+
app.use(express.urlencoded({ extended: true }));
|
|
15
|
+
// 请求日志中间件
|
|
16
|
+
app.use((req, res, next) => {
|
|
17
|
+
const timestamp = new Date().toLocaleTimeString();
|
|
18
|
+
logger.info(`[${timestamp}] ${req.method} ${req.path}`);
|
|
19
|
+
next();
|
|
20
|
+
});
|
|
21
|
+
// 动态路由处理中间件
|
|
22
|
+
app.use(async (req, res, next) => {
|
|
23
|
+
// 尝试匹配路由
|
|
24
|
+
const route = findMatchingRoute(routeManager.getAllRoutes(), req.method, req.path);
|
|
25
|
+
if (!route) {
|
|
26
|
+
return next(); // 继续到 404 处理
|
|
27
|
+
}
|
|
28
|
+
// 提取路径参数
|
|
29
|
+
const params = extractPathParams(route.path, req.path);
|
|
30
|
+
req.params = params;
|
|
31
|
+
// 参数校验
|
|
32
|
+
if (route.validation) {
|
|
33
|
+
const validationError = validateRequest(req, route.validation);
|
|
34
|
+
if (validationError) {
|
|
35
|
+
res.status(400).json({
|
|
36
|
+
code: 400,
|
|
37
|
+
message: '参数校验失败',
|
|
38
|
+
error: validationError
|
|
39
|
+
});
|
|
40
|
+
logger.error(`${route.method} ${route.path} -> 400 (参数校验失败: ${validationError})`);
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
try {
|
|
45
|
+
// 判断 response 是函数还是静态数据
|
|
46
|
+
let responseData = typeof route.response === 'function'
|
|
47
|
+
? route.response(req) // 动态生成数据
|
|
48
|
+
: route.response; // 静态数据
|
|
49
|
+
// 处理 Promise
|
|
50
|
+
if (responseData && typeof responseData.then === 'function') {
|
|
51
|
+
responseData = await responseData;
|
|
52
|
+
}
|
|
53
|
+
// 返回 Mock 数据
|
|
54
|
+
res.status(route.status || 200).json(responseData);
|
|
55
|
+
logger.success(`${route.method} ${route.path} -> ${route.status || 200}`);
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
logger.error(`${route.method} ${route.path} -> 500 (${error instanceof Error ? error.message : '未知错误'})`);
|
|
59
|
+
res.status(500).json({
|
|
60
|
+
code: 500,
|
|
61
|
+
message: 'Internal server error',
|
|
62
|
+
error: error instanceof Error ? error.message : '未知错误'
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
// 404 处理
|
|
67
|
+
app.use((req, res) => {
|
|
68
|
+
res.status(404).json({
|
|
69
|
+
code: 404,
|
|
70
|
+
message: 'API not found',
|
|
71
|
+
data: null
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
// 错误处理
|
|
75
|
+
app.use((err, req, res, next) => {
|
|
76
|
+
logger.error(`服务器错误: ${err.message}`);
|
|
77
|
+
res.status(500).json({
|
|
78
|
+
code: 500,
|
|
79
|
+
message: 'Internal server error',
|
|
80
|
+
data: null
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
return app;
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=express-server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"express-server.js","sourceRoot":"","sources":["../../../src/server/express-server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { RouteManager } from './route-manager.js';
|
|
2
|
+
import type { ApifoxConfig } from '../types/index.js';
|
|
3
|
+
/**
|
|
4
|
+
* 设置热重载
|
|
5
|
+
*/
|
|
6
|
+
export declare function setupHotReload(config: ApifoxConfig, routeManager: RouteManager): void;
|
|
7
|
+
//# sourceMappingURL=hot-reload.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hot-reload.d.ts","sourceRoot":"","sources":["../../../src/server/hot-reload.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACtD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAErD;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,YAAY,EAAE,YAAY,EAAE,YAAY,GAAG,IAAI,CAsDrF"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import chokidar from 'chokidar';
|
|
3
|
+
import { logger } from '../utils/logger.js';
|
|
4
|
+
import { loadRouteFromFile } from './route-loader.js';
|
|
5
|
+
/**
|
|
6
|
+
* 设置热重载
|
|
7
|
+
*/
|
|
8
|
+
export function setupHotReload(config, routeManager) {
|
|
9
|
+
const mockDir = path.resolve(config.mockDir);
|
|
10
|
+
logger.info('🔥 监听 Mock 文件变化...');
|
|
11
|
+
logger.info(` 监听目录: ${mockDir}`);
|
|
12
|
+
logger.info('');
|
|
13
|
+
// 使用标准化的路径格式
|
|
14
|
+
const watchPattern = path.join(mockDir, '**', '*.js').replace(/\\/g, '/');
|
|
15
|
+
const watcher = chokidar.watch(watchPattern, {
|
|
16
|
+
ignored: ['**/index.js', '**/node_modules/**'],
|
|
17
|
+
persistent: true,
|
|
18
|
+
ignoreInitial: true, // 忽略初始扫描
|
|
19
|
+
awaitWriteFinish: {
|
|
20
|
+
stabilityThreshold: 300,
|
|
21
|
+
pollInterval: 100
|
|
22
|
+
},
|
|
23
|
+
usePolling: false,
|
|
24
|
+
atomic: true
|
|
25
|
+
});
|
|
26
|
+
watcher
|
|
27
|
+
.on('add', async (filePath) => {
|
|
28
|
+
logger.info(`📝 检测到新文件: ${path.relative(mockDir, filePath)}`);
|
|
29
|
+
const result = await loadRouteFromFile(filePath, mockDir);
|
|
30
|
+
if (result) {
|
|
31
|
+
routeManager.setRoute(result.key, result.route);
|
|
32
|
+
logger.success(`✓ 已加载路由: ${result.key}`);
|
|
33
|
+
}
|
|
34
|
+
})
|
|
35
|
+
.on('change', async (filePath) => {
|
|
36
|
+
logger.info(`📝 文件已修改: ${path.relative(mockDir, filePath)}`);
|
|
37
|
+
const result = await loadRouteFromFile(filePath, mockDir);
|
|
38
|
+
if (result) {
|
|
39
|
+
routeManager.setRoute(result.key, result.route);
|
|
40
|
+
logger.success(`✓ 已更新路由: ${result.key}`);
|
|
41
|
+
}
|
|
42
|
+
})
|
|
43
|
+
.on('unlink', async (filePath) => {
|
|
44
|
+
logger.info(`🗑️ 文件已删除: ${path.relative(mockDir, filePath)}`);
|
|
45
|
+
// 尝试从文件路径推断路由信息
|
|
46
|
+
// 这里简化处理,实际应该存储文件路径到路由的映射
|
|
47
|
+
const allRoutes = routeManager.getAllRoutes();
|
|
48
|
+
allRoutes.forEach(route => {
|
|
49
|
+
const key = `${route.method} ${route.path}`;
|
|
50
|
+
// 简单判断:如果找不到对应的物理文件,则移除
|
|
51
|
+
routeManager.removeRoute(key);
|
|
52
|
+
});
|
|
53
|
+
logger.warn(`⚠️ 已移除相关路由`);
|
|
54
|
+
})
|
|
55
|
+
.on('error', error => logger.error(`监听错误: ${error}`));
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=hot-reload.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hot-reload.js","sourceRoot":"","sources":["../../../src/server/hot-reload.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { ApifoxConfig, MockRoute } from '../types/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* 动态扫描并加载所有 Mock 文件
|
|
4
|
+
*/
|
|
5
|
+
export declare function loadMockRoutes(config: ApifoxConfig): Promise<MockRoute[]>;
|
|
6
|
+
/**
|
|
7
|
+
* 加载单个 Mock 文件的路由
|
|
8
|
+
*/
|
|
9
|
+
export declare function loadRouteFromFile(filePath: string, mockDir: string): Promise<{
|
|
10
|
+
key: string;
|
|
11
|
+
route: MockRoute;
|
|
12
|
+
} | null>;
|
|
13
|
+
//# sourceMappingURL=route-loader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"route-loader.d.ts","sourceRoot":"","sources":["../../../src/server/route-loader.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAA;AAOhE;;GAEG;AACH,wBAAsB,cAAc,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAkE/E;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,SAAS,CAAA;CAAE,GAAG,IAAI,CAAC,CA2D5H"}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import { pathToFileURL } from 'url';
|
|
3
|
+
import { glob } from 'glob';
|
|
4
|
+
import { fileHelper } from '../utils/file-helper.js';
|
|
5
|
+
import { logger } from '../utils/logger.js';
|
|
6
|
+
/**
|
|
7
|
+
* 模块缓存映射
|
|
8
|
+
*/
|
|
9
|
+
const moduleCache = new Map();
|
|
10
|
+
/**
|
|
11
|
+
* 动态扫描并加载所有 Mock 文件
|
|
12
|
+
*/
|
|
13
|
+
export async function loadMockRoutes(config) {
|
|
14
|
+
const mockDir = path.resolve(config.mockDir);
|
|
15
|
+
// 检查 mock 目录是否存在
|
|
16
|
+
if (!await fileHelper.exists(mockDir)) {
|
|
17
|
+
logger.error('未找到 Mock 目录');
|
|
18
|
+
logger.info('请先运行 npm run generate 生成 Mock 文件');
|
|
19
|
+
process.exit(1);
|
|
20
|
+
}
|
|
21
|
+
// 扫描所有 mock 文件(排除 index.js)
|
|
22
|
+
const pattern = path.join(mockDir, '**', '*.js').replace(/\\/g, '/');
|
|
23
|
+
const mockFiles = await glob(pattern, {
|
|
24
|
+
ignore: ['**/index.js', '**/node_modules/**']
|
|
25
|
+
});
|
|
26
|
+
if (mockFiles.length === 0) {
|
|
27
|
+
logger.error('未找到任何 Mock 文件');
|
|
28
|
+
logger.info('请先运行 npm run generate 生成 Mock 文件');
|
|
29
|
+
process.exit(1);
|
|
30
|
+
}
|
|
31
|
+
const routes = [];
|
|
32
|
+
// 逐个加载 mock 文件
|
|
33
|
+
for (const filePath of mockFiles) {
|
|
34
|
+
try {
|
|
35
|
+
// 将路径转换为 file:// URL 格式
|
|
36
|
+
const fileUrl = pathToFileURL(filePath).href;
|
|
37
|
+
const mockModule = await import(fileUrl);
|
|
38
|
+
// 读取文件内容,提取路由信息
|
|
39
|
+
const fileContent = await fileHelper.readFile(filePath);
|
|
40
|
+
const routeInfo = extractRouteInfo(fileContent);
|
|
41
|
+
if (!routeInfo) {
|
|
42
|
+
logger.warn(`无法从 ${path.relative(mockDir, filePath)} 提取路由信息,跳过`);
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
// 获取导出的函数(尝试不同的导出方式)
|
|
46
|
+
const handlerFunction = mockModule.default ||
|
|
47
|
+
Object.values(mockModule).find(exp => typeof exp === 'function' && exp.name);
|
|
48
|
+
if (!handlerFunction || typeof handlerFunction !== 'function') {
|
|
49
|
+
logger.warn(`${path.relative(mockDir, filePath)} 未找到有效的处理函数,跳过`);
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
routes.push({
|
|
53
|
+
path: routeInfo.path,
|
|
54
|
+
method: routeInfo.method,
|
|
55
|
+
response: (req) => {
|
|
56
|
+
// 调用 mock 函数,传递 query, body, ctx
|
|
57
|
+
return handlerFunction(req.query, req.body, { req });
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
logger.debug(`加载路由: ${routeInfo.method} ${routeInfo.path}`);
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
logger.error(`加载 Mock 文件失败: ${filePath}`);
|
|
64
|
+
console.error(error);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return routes;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* 加载单个 Mock 文件的路由
|
|
71
|
+
*/
|
|
72
|
+
export async function loadRouteFromFile(filePath, mockDir) {
|
|
73
|
+
try {
|
|
74
|
+
const fileUrl = pathToFileURL(path.resolve(filePath)).href;
|
|
75
|
+
// 读取文件内容,提取路由信息
|
|
76
|
+
const fileContent = await fileHelper.readFile(filePath);
|
|
77
|
+
const routeInfo = extractRouteInfo(fileContent);
|
|
78
|
+
if (!routeInfo) {
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
// 使用版本号破坏缓存
|
|
82
|
+
const version = (moduleCache.get(filePath) || 0) + 1;
|
|
83
|
+
moduleCache.set(filePath, version);
|
|
84
|
+
// 动态导入模块(带版本号避免缓存)
|
|
85
|
+
const mockModule = await import(fileUrl + `?v=${version}&t=${Date.now()}`);
|
|
86
|
+
// 获取导出的函数
|
|
87
|
+
const handlerFunction = mockModule.default ||
|
|
88
|
+
Object.values(mockModule).find(exp => typeof exp === 'function' && exp.name);
|
|
89
|
+
if (!handlerFunction || typeof handlerFunction !== 'function') {
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
const key = `${routeInfo.method} ${routeInfo.path}`;
|
|
93
|
+
const route = {
|
|
94
|
+
path: routeInfo.path,
|
|
95
|
+
method: routeInfo.method,
|
|
96
|
+
response: (req) => {
|
|
97
|
+
// 每次请求时都重新读取文件并导入最新版本
|
|
98
|
+
return (async () => {
|
|
99
|
+
try {
|
|
100
|
+
const latestVersion = moduleCache.get(filePath) || version;
|
|
101
|
+
const latestModule = await import(fileUrl + `?v=${latestVersion}&t=${Date.now()}`);
|
|
102
|
+
const latestHandler = latestModule.default ||
|
|
103
|
+
Object.values(latestModule).find(exp => typeof exp === 'function' && exp.name);
|
|
104
|
+
if (latestHandler && typeof latestHandler === 'function') {
|
|
105
|
+
return latestHandler(req.query, req.body, { req });
|
|
106
|
+
}
|
|
107
|
+
return handlerFunction(req.query, req.body, { req });
|
|
108
|
+
}
|
|
109
|
+
catch (err) {
|
|
110
|
+
// 失败时使用原始函数
|
|
111
|
+
return handlerFunction(req.query, req.body, { req });
|
|
112
|
+
}
|
|
113
|
+
})();
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
return { key, route };
|
|
117
|
+
}
|
|
118
|
+
catch (error) {
|
|
119
|
+
logger.error(`加载 Mock 文件失败: ${filePath}`);
|
|
120
|
+
console.error(error);
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* 从文件内容中提取路由信息
|
|
126
|
+
*/
|
|
127
|
+
function extractRouteInfo(fileContent) {
|
|
128
|
+
// 匹配 //[start]/path[METHOD] 格式
|
|
129
|
+
const startMatch = fileContent.match(/\/\/\[start\](.+?)\[(\w+)\]/);
|
|
130
|
+
if (startMatch) {
|
|
131
|
+
return {
|
|
132
|
+
path: startMatch[1],
|
|
133
|
+
method: startMatch[2]
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
// 匹配注释中的 @apiURI 和 @apiRequestType
|
|
137
|
+
const pathMatch = fileContent.match(/@apiURI\s+(.+)/m);
|
|
138
|
+
const methodMatch = fileContent.match(/@apiRequestType\s+(\w+)/m);
|
|
139
|
+
if (pathMatch && methodMatch) {
|
|
140
|
+
return {
|
|
141
|
+
path: pathMatch[1].trim(),
|
|
142
|
+
method: methodMatch[1].trim()
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
return null;
|
|
146
|
+
}
|
|
147
|
+
//# sourceMappingURL=route-loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"route-loader.js","sourceRoot":"","sources":["../../../src/server/route-loader.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { MockRoute } from '../types/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* 路由存储,支持动态更新
|
|
4
|
+
*/
|
|
5
|
+
export declare class RouteManager {
|
|
6
|
+
private routes;
|
|
7
|
+
setRoute(key: string, route: MockRoute): void;
|
|
8
|
+
removeRoute(key: string): void;
|
|
9
|
+
getRoute(method: string, path: string): MockRoute | undefined;
|
|
10
|
+
getAllRoutes(): MockRoute[];
|
|
11
|
+
clear(): void;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=route-manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"route-manager.d.ts","sourceRoot":"","sources":["../../../src/server/route-manager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAA;AAElD;;GAEG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,MAAM,CAAoC;IAElD,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS;IAItC,WAAW,CAAC,GAAG,EAAE,MAAM;IAIvB,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS;IAK7D,YAAY,IAAI,SAAS,EAAE;IAI3B,KAAK;CAGN"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 路由存储,支持动态更新
|
|
3
|
+
*/
|
|
4
|
+
export class RouteManager {
|
|
5
|
+
constructor() {
|
|
6
|
+
this.routes = new Map();
|
|
7
|
+
}
|
|
8
|
+
setRoute(key, route) {
|
|
9
|
+
this.routes.set(key, route);
|
|
10
|
+
}
|
|
11
|
+
removeRoute(key) {
|
|
12
|
+
this.routes.delete(key);
|
|
13
|
+
}
|
|
14
|
+
getRoute(method, path) {
|
|
15
|
+
const key = `${method.toUpperCase()} ${path}`;
|
|
16
|
+
return this.routes.get(key);
|
|
17
|
+
}
|
|
18
|
+
getAllRoutes() {
|
|
19
|
+
return Array.from(this.routes.values());
|
|
20
|
+
}
|
|
21
|
+
clear() {
|
|
22
|
+
this.routes.clear();
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=route-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"route-manager.js","sourceRoot":"","sources":["../../../src/server/route-manager.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,MAAM,OAAO,YAAY;IAAzB;QACU,WAAM,GAA2B,IAAI,GAAG,EAAE,CAAA;IAsBpD,CAAC;IApBC,QAAQ,CAAC,GAAW,EAAE,KAAgB;QACpC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAA;IAC7B,CAAC;IAED,WAAW,CAAC,GAAW;QACrB,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;IACzB,CAAC;IAED,QAAQ,CAAC,MAAc,EAAE,IAAY;QACnC,MAAM,GAAG,GAAG,GAAG,MAAM,CAAC,WAAW,EAAE,IAAI,IAAI,EAAE,CAAA;QAC7C,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;IAC7B,CAAC;IAED,YAAY;QACV,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAA;IACzC,CAAC;IAED,KAAK;QACH,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAA;IACrB,CAAC;CACF"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { MockRoute } from '../types/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* 查找匹配的路由
|
|
4
|
+
*/
|
|
5
|
+
export declare function findMatchingRoute(routes: MockRoute[], method: string, path: string): MockRoute | undefined;
|
|
6
|
+
/**
|
|
7
|
+
* 提取路径参数
|
|
8
|
+
*/
|
|
9
|
+
export declare function extractPathParams(routePath: string, actualPath: string): Record<string, string>;
|
|
10
|
+
//# sourceMappingURL=route-matcher.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"route-matcher.d.ts","sourceRoot":"","sources":["../../../src/server/route-matcher.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAA;AAElD;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,CAY1G;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAoB/F"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 查找匹配的路由
|
|
3
|
+
*/
|
|
4
|
+
export function findMatchingRoute(routes, method, path) {
|
|
5
|
+
return routes.find(route => {
|
|
6
|
+
if (route.method.toUpperCase() !== method.toUpperCase()) {
|
|
7
|
+
return false;
|
|
8
|
+
}
|
|
9
|
+
// 将 OpenAPI 路径格式转换为正则表达式
|
|
10
|
+
const pattern = route.path.replace(/\{(\w+)\}/g, '([^/]+)');
|
|
11
|
+
const regex = new RegExp(`^${pattern}$`);
|
|
12
|
+
return regex.test(path);
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* 提取路径参数
|
|
17
|
+
*/
|
|
18
|
+
export function extractPathParams(routePath, actualPath) {
|
|
19
|
+
const params = {};
|
|
20
|
+
// 提取参数名
|
|
21
|
+
const paramNames = [];
|
|
22
|
+
const pattern = routePath.replace(/\{(\w+)\}/g, (_, name) => {
|
|
23
|
+
paramNames.push(name);
|
|
24
|
+
return '([^/]+)';
|
|
25
|
+
});
|
|
26
|
+
const regex = new RegExp(`^${pattern}$`);
|
|
27
|
+
const match = actualPath.match(regex);
|
|
28
|
+
if (match) {
|
|
29
|
+
paramNames.forEach((name, index) => {
|
|
30
|
+
params[name] = match[index + 1];
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
return params;
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=route-matcher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"route-matcher.js","sourceRoot":"","sources":["../../../src/server/route-matcher.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAAC,MAAmB,EAAE,MAAc,EAAE,IAAY;IACjF,OAAO,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE;QACzB,IAAI,KAAK,CAAC,MAAM,CAAC,WAAW,EAAE,KAAK,MAAM,CAAC,WAAW,EAAE,EAAE,CAAC;YACxD,OAAO,KAAK,CAAA;QACd,CAAC;QAED,yBAAyB;QACzB,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE,SAAS,CAAC,CAAA;QAC3D,MAAM,KAAK,GAAG,IAAI,MAAM,CAAC,IAAI,OAAO,GAAG,CAAC,CAAA;QAExC,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACzB,CAAC,CAAC,CAAA;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAAC,SAAiB,EAAE,UAAkB;IACrE,MAAM,MAAM,GAA2B,EAAE,CAAA;IAEzC,QAAQ;IACR,MAAM,UAAU,GAAa,EAAE,CAAA;IAC/B,MAAM,OAAO,GAAG,SAAS,CAAC,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE;QAC1D,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QACrB,OAAO,SAAS,CAAA;IAClB,CAAC,CAAC,CAAA;IAEF,MAAM,KAAK,GAAG,IAAI,MAAM,CAAC,IAAI,OAAO,GAAG,CAAC,CAAA;IACxC,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;IAErC,IAAI,KAAK,EAAE,CAAC;QACV,UAAU,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;YACjC,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAA;QACjC,CAAC,CAAC,CAAA;IACJ,CAAC;IAED,OAAO,MAAM,CAAA;AACf,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../../src/server/validation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,SAAS,CAAA;AAElC;;GAEG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,OAAO,CAAC,OAAO,EAAE,UAAU,EAAE,GAAG,GAAG,MAAM,GAAG,IAAI,CA0CpF"}
|