mnehmos.trace.mcp 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/LICENSE +21 -0
- package/README.md +1662 -0
- package/dist/adapters/bootstrap.d.ts +29 -0
- package/dist/adapters/bootstrap.d.ts.map +1 -0
- package/dist/adapters/bootstrap.js +46 -0
- package/dist/adapters/bootstrap.js.map +1 -0
- package/dist/adapters/errors.d.ts +94 -0
- package/dist/adapters/errors.d.ts.map +1 -0
- package/dist/adapters/errors.js +107 -0
- package/dist/adapters/errors.js.map +1 -0
- package/dist/adapters/graphql/index.d.ts +9 -0
- package/dist/adapters/graphql/index.d.ts.map +1 -0
- package/dist/adapters/graphql/index.js +9 -0
- package/dist/adapters/graphql/index.js.map +1 -0
- package/dist/adapters/graphql/sdl-parser.d.ts +74 -0
- package/dist/adapters/graphql/sdl-parser.d.ts.map +1 -0
- package/dist/adapters/graphql/sdl-parser.js +559 -0
- package/dist/adapters/graphql/sdl-parser.js.map +1 -0
- package/dist/adapters/grpc/adapter.d.ts +76 -0
- package/dist/adapters/grpc/adapter.d.ts.map +1 -0
- package/dist/adapters/grpc/adapter.js +362 -0
- package/dist/adapters/grpc/adapter.js.map +1 -0
- package/dist/adapters/grpc/index.d.ts +10 -0
- package/dist/adapters/grpc/index.d.ts.map +1 -0
- package/dist/adapters/grpc/index.js +12 -0
- package/dist/adapters/grpc/index.js.map +1 -0
- package/dist/adapters/grpc/proto-parser.d.ts +76 -0
- package/dist/adapters/grpc/proto-parser.d.ts.map +1 -0
- package/dist/adapters/grpc/proto-parser.js +523 -0
- package/dist/adapters/grpc/proto-parser.js.map +1 -0
- package/dist/adapters/grpc/type-converter.d.ts +43 -0
- package/dist/adapters/grpc/type-converter.d.ts.map +1 -0
- package/dist/adapters/grpc/type-converter.js +270 -0
- package/dist/adapters/grpc/type-converter.js.map +1 -0
- package/dist/adapters/grpc/types.d.ts +85 -0
- package/dist/adapters/grpc/types.d.ts.map +1 -0
- package/dist/adapters/grpc/types.js +7 -0
- package/dist/adapters/grpc/types.js.map +1 -0
- package/dist/adapters/index.d.ts +39 -0
- package/dist/adapters/index.d.ts.map +1 -0
- package/dist/adapters/index.js +50 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/adapters/mcp.d.ts +23 -0
- package/dist/adapters/mcp.d.ts.map +1 -0
- package/dist/adapters/mcp.js +293 -0
- package/dist/adapters/mcp.js.map +1 -0
- package/dist/adapters/openapi/adapter.d.ts +213 -0
- package/dist/adapters/openapi/adapter.d.ts.map +1 -0
- package/dist/adapters/openapi/adapter.js +557 -0
- package/dist/adapters/openapi/adapter.js.map +1 -0
- package/dist/adapters/openapi/convert.d.ts +120 -0
- package/dist/adapters/openapi/convert.d.ts.map +1 -0
- package/dist/adapters/openapi/convert.js +363 -0
- package/dist/adapters/openapi/convert.js.map +1 -0
- package/dist/adapters/openapi/index.d.ts +39 -0
- package/dist/adapters/openapi/index.d.ts.map +1 -0
- package/dist/adapters/openapi/index.js +48 -0
- package/dist/adapters/openapi/index.js.map +1 -0
- package/dist/adapters/openapi/parser.d.ts +95 -0
- package/dist/adapters/openapi/parser.d.ts.map +1 -0
- package/dist/adapters/openapi/parser.js +171 -0
- package/dist/adapters/openapi/parser.js.map +1 -0
- package/dist/adapters/registry.d.ts +116 -0
- package/dist/adapters/registry.d.ts.map +1 -0
- package/dist/adapters/registry.js +246 -0
- package/dist/adapters/registry.js.map +1 -0
- package/dist/adapters/trpc/adapter.d.ts +159 -0
- package/dist/adapters/trpc/adapter.d.ts.map +1 -0
- package/dist/adapters/trpc/adapter.js +223 -0
- package/dist/adapters/trpc/adapter.js.map +1 -0
- package/dist/adapters/trpc/extractor.d.ts +218 -0
- package/dist/adapters/trpc/extractor.d.ts.map +1 -0
- package/dist/adapters/trpc/extractor.js +708 -0
- package/dist/adapters/trpc/extractor.js.map +1 -0
- package/dist/adapters/trpc/index.d.ts +31 -0
- package/dist/adapters/trpc/index.d.ts.map +1 -0
- package/dist/adapters/trpc/index.js +40 -0
- package/dist/adapters/trpc/index.js.map +1 -0
- package/dist/adapters/trpc/parser.d.ts +119 -0
- package/dist/adapters/trpc/parser.d.ts.map +1 -0
- package/dist/adapters/trpc/parser.js +128 -0
- package/dist/adapters/trpc/parser.js.map +1 -0
- package/dist/compare/index.d.ts +33 -0
- package/dist/compare/index.d.ts.map +1 -0
- package/dist/compare/index.js +261 -0
- package/dist/compare/index.js.map +1 -0
- package/dist/core/types.d.ts +188 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +9 -0
- package/dist/core/types.js.map +1 -0
- package/dist/extract/index.d.ts +26 -0
- package/dist/extract/index.d.ts.map +1 -0
- package/dist/extract/index.js +44 -0
- package/dist/extract/index.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +674 -0
- package/dist/index.js.map +1 -0
- package/dist/languages/base.d.ts +57 -0
- package/dist/languages/base.d.ts.map +1 -0
- package/dist/languages/base.js +6 -0
- package/dist/languages/base.js.map +1 -0
- package/dist/languages/bootstrap.d.ts +10 -0
- package/dist/languages/bootstrap.d.ts.map +1 -0
- package/dist/languages/bootstrap.js +25 -0
- package/dist/languages/bootstrap.js.map +1 -0
- package/dist/languages/go/handlers/chi.d.ts +24 -0
- package/dist/languages/go/handlers/chi.d.ts.map +1 -0
- package/dist/languages/go/handlers/chi.js +205 -0
- package/dist/languages/go/handlers/chi.js.map +1 -0
- package/dist/languages/go/handlers/gin.d.ts +24 -0
- package/dist/languages/go/handlers/gin.d.ts.map +1 -0
- package/dist/languages/go/handlers/gin.js +156 -0
- package/dist/languages/go/handlers/gin.js.map +1 -0
- package/dist/languages/go/handlers/stdlib.d.ts +19 -0
- package/dist/languages/go/handlers/stdlib.d.ts.map +1 -0
- package/dist/languages/go/handlers/stdlib.js +112 -0
- package/dist/languages/go/handlers/stdlib.js.map +1 -0
- package/dist/languages/go/index.d.ts +18 -0
- package/dist/languages/go/index.d.ts.map +1 -0
- package/dist/languages/go/index.js +20 -0
- package/dist/languages/go/index.js.map +1 -0
- package/dist/languages/go/parser.d.ts +33 -0
- package/dist/languages/go/parser.d.ts.map +1 -0
- package/dist/languages/go/parser.js +95 -0
- package/dist/languages/go/parser.js.map +1 -0
- package/dist/languages/go/struct-extractor.d.ts +59 -0
- package/dist/languages/go/struct-extractor.d.ts.map +1 -0
- package/dist/languages/go/struct-extractor.js +483 -0
- package/dist/languages/go/struct-extractor.js.map +1 -0
- package/dist/languages/go/tag-parser.d.ts +62 -0
- package/dist/languages/go/tag-parser.d.ts.map +1 -0
- package/dist/languages/go/tag-parser.js +108 -0
- package/dist/languages/go/tag-parser.js.map +1 -0
- package/dist/languages/go/type-converter.d.ts +32 -0
- package/dist/languages/go/type-converter.d.ts.map +1 -0
- package/dist/languages/go/type-converter.js +226 -0
- package/dist/languages/go/type-converter.js.map +1 -0
- package/dist/languages/go/types.d.ts +153 -0
- package/dist/languages/go/types.d.ts.map +1 -0
- package/dist/languages/go/types.js +6 -0
- package/dist/languages/go/types.js.map +1 -0
- package/dist/languages/import-resolver.d.ts +645 -0
- package/dist/languages/import-resolver.d.ts.map +1 -0
- package/dist/languages/import-resolver.js +1278 -0
- package/dist/languages/import-resolver.js.map +1 -0
- package/dist/languages/index.d.ts +34 -0
- package/dist/languages/index.d.ts.map +1 -0
- package/dist/languages/index.js +93 -0
- package/dist/languages/index.js.map +1 -0
- package/dist/languages/json-schema.d.ts +40 -0
- package/dist/languages/json-schema.d.ts.map +1 -0
- package/dist/languages/json-schema.js +188 -0
- package/dist/languages/json-schema.js.map +1 -0
- package/dist/languages/python-ast/index.d.ts +8 -0
- package/dist/languages/python-ast/index.d.ts.map +1 -0
- package/dist/languages/python-ast/index.js +7 -0
- package/dist/languages/python-ast/index.js.map +1 -0
- package/dist/languages/python-ast/parser.d.ts +174 -0
- package/dist/languages/python-ast/parser.d.ts.map +1 -0
- package/dist/languages/python-ast/parser.js +1205 -0
- package/dist/languages/python-ast/parser.js.map +1 -0
- package/dist/languages/python-ast/type-resolver.d.ts +75 -0
- package/dist/languages/python-ast/type-resolver.d.ts.map +1 -0
- package/dist/languages/python-ast/type-resolver.js +421 -0
- package/dist/languages/python-ast/type-resolver.js.map +1 -0
- package/dist/languages/python-ast/types.d.ts +216 -0
- package/dist/languages/python-ast/types.d.ts.map +1 -0
- package/dist/languages/python-ast/types.js +6 -0
- package/dist/languages/python-ast/types.js.map +1 -0
- package/dist/languages/python.d.ts +55 -0
- package/dist/languages/python.d.ts.map +1 -0
- package/dist/languages/python.js +311 -0
- package/dist/languages/python.js.map +1 -0
- package/dist/languages/typescript.d.ts +272 -0
- package/dist/languages/typescript.d.ts.map +1 -0
- package/dist/languages/typescript.js +1381 -0
- package/dist/languages/typescript.js.map +1 -0
- package/dist/patterns/base.d.ts +146 -0
- package/dist/patterns/base.d.ts.map +1 -0
- package/dist/patterns/base.js +89 -0
- package/dist/patterns/base.js.map +1 -0
- package/dist/patterns/errors.d.ts +172 -0
- package/dist/patterns/errors.d.ts.map +1 -0
- package/dist/patterns/errors.js +185 -0
- package/dist/patterns/errors.js.map +1 -0
- package/dist/patterns/extractors.d.ts +170 -0
- package/dist/patterns/extractors.d.ts.map +1 -0
- package/dist/patterns/extractors.js +305 -0
- package/dist/patterns/extractors.js.map +1 -0
- package/dist/patterns/graphql/apollo-client.d.ts +80 -0
- package/dist/patterns/graphql/apollo-client.d.ts.map +1 -0
- package/dist/patterns/graphql/apollo-client.js +800 -0
- package/dist/patterns/graphql/apollo-client.js.map +1 -0
- package/dist/patterns/graphql/apollo-server.d.ts +55 -0
- package/dist/patterns/graphql/apollo-server.d.ts.map +1 -0
- package/dist/patterns/graphql/apollo-server.js +523 -0
- package/dist/patterns/graphql/apollo-server.js.map +1 -0
- package/dist/patterns/graphql/index.d.ts +11 -0
- package/dist/patterns/graphql/index.d.ts.map +1 -0
- package/dist/patterns/graphql/index.js +12 -0
- package/dist/patterns/graphql/index.js.map +1 -0
- package/dist/patterns/graphql/types.d.ts +213 -0
- package/dist/patterns/graphql/types.d.ts.map +1 -0
- package/dist/patterns/graphql/types.js +16 -0
- package/dist/patterns/graphql/types.js.map +1 -0
- package/dist/patterns/http-clients/axios.d.ts +148 -0
- package/dist/patterns/http-clients/axios.d.ts.map +1 -0
- package/dist/patterns/http-clients/axios.js +652 -0
- package/dist/patterns/http-clients/axios.js.map +1 -0
- package/dist/patterns/http-clients/fetch.d.ts +88 -0
- package/dist/patterns/http-clients/fetch.d.ts.map +1 -0
- package/dist/patterns/http-clients/fetch.js +364 -0
- package/dist/patterns/http-clients/fetch.js.map +1 -0
- package/dist/patterns/http-clients/index.d.ts +36 -0
- package/dist/patterns/http-clients/index.d.ts.map +1 -0
- package/dist/patterns/http-clients/index.js +50 -0
- package/dist/patterns/http-clients/index.js.map +1 -0
- package/dist/patterns/http-clients/property-access.d.ts +46 -0
- package/dist/patterns/http-clients/property-access.d.ts.map +1 -0
- package/dist/patterns/http-clients/property-access.js +818 -0
- package/dist/patterns/http-clients/property-access.js.map +1 -0
- package/dist/patterns/http-clients/type-inference.d.ts +48 -0
- package/dist/patterns/http-clients/type-inference.d.ts.map +1 -0
- package/dist/patterns/http-clients/type-inference.js +293 -0
- package/dist/patterns/http-clients/type-inference.js.map +1 -0
- package/dist/patterns/http-clients/types.d.ts +168 -0
- package/dist/patterns/http-clients/types.d.ts.map +1 -0
- package/dist/patterns/http-clients/types.js +10 -0
- package/dist/patterns/http-clients/types.js.map +1 -0
- package/dist/patterns/http-clients/url-extractor.d.ts +53 -0
- package/dist/patterns/http-clients/url-extractor.d.ts.map +1 -0
- package/dist/patterns/http-clients/url-extractor.js +338 -0
- package/dist/patterns/http-clients/url-extractor.js.map +1 -0
- package/dist/patterns/index.d.ts +44 -0
- package/dist/patterns/index.d.ts.map +1 -0
- package/dist/patterns/index.js +49 -0
- package/dist/patterns/index.js.map +1 -0
- package/dist/patterns/python/aiohttp.d.ts +21 -0
- package/dist/patterns/python/aiohttp.d.ts.map +1 -0
- package/dist/patterns/python/aiohttp.js +188 -0
- package/dist/patterns/python/aiohttp.js.map +1 -0
- package/dist/patterns/python/httpx.d.ts +20 -0
- package/dist/patterns/python/httpx.d.ts.map +1 -0
- package/dist/patterns/python/httpx.js +183 -0
- package/dist/patterns/python/httpx.js.map +1 -0
- package/dist/patterns/python/index.d.ts +32 -0
- package/dist/patterns/python/index.d.ts.map +1 -0
- package/dist/patterns/python/index.js +63 -0
- package/dist/patterns/python/index.js.map +1 -0
- package/dist/patterns/python/property-access.d.ts +27 -0
- package/dist/patterns/python/property-access.d.ts.map +1 -0
- package/dist/patterns/python/property-access.js +132 -0
- package/dist/patterns/python/property-access.js.map +1 -0
- package/dist/patterns/python/requests.d.ts +19 -0
- package/dist/patterns/python/requests.d.ts.map +1 -0
- package/dist/patterns/python/requests.js +239 -0
- package/dist/patterns/python/requests.js.map +1 -0
- package/dist/patterns/python/types.d.ts +95 -0
- package/dist/patterns/python/types.d.ts.map +1 -0
- package/dist/patterns/python/types.js +43 -0
- package/dist/patterns/python/types.js.map +1 -0
- package/dist/patterns/registry.d.ts +181 -0
- package/dist/patterns/registry.d.ts.map +1 -0
- package/dist/patterns/registry.js +304 -0
- package/dist/patterns/registry.js.map +1 -0
- package/dist/patterns/rest/express.d.ts +78 -0
- package/dist/patterns/rest/express.d.ts.map +1 -0
- package/dist/patterns/rest/express.js +289 -0
- package/dist/patterns/rest/express.js.map +1 -0
- package/dist/patterns/rest/fastify.d.ts +93 -0
- package/dist/patterns/rest/fastify.d.ts.map +1 -0
- package/dist/patterns/rest/fastify.js +420 -0
- package/dist/patterns/rest/fastify.js.map +1 -0
- package/dist/patterns/rest/index.d.ts +31 -0
- package/dist/patterns/rest/index.d.ts.map +1 -0
- package/dist/patterns/rest/index.js +45 -0
- package/dist/patterns/rest/index.js.map +1 -0
- package/dist/patterns/rest/middleware.d.ts +25 -0
- package/dist/patterns/rest/middleware.d.ts.map +1 -0
- package/dist/patterns/rest/middleware.js +219 -0
- package/dist/patterns/rest/middleware.js.map +1 -0
- package/dist/patterns/rest/path-parser.d.ts +50 -0
- package/dist/patterns/rest/path-parser.d.ts.map +1 -0
- package/dist/patterns/rest/path-parser.js +137 -0
- package/dist/patterns/rest/path-parser.js.map +1 -0
- package/dist/patterns/rest/response-inference.d.ts +44 -0
- package/dist/patterns/rest/response-inference.d.ts.map +1 -0
- package/dist/patterns/rest/response-inference.js +218 -0
- package/dist/patterns/rest/response-inference.js.map +1 -0
- package/dist/patterns/rest/types.d.ts +102 -0
- package/dist/patterns/rest/types.d.ts.map +1 -0
- package/dist/patterns/rest/types.js +10 -0
- package/dist/patterns/rest/types.js.map +1 -0
- package/dist/patterns/types.d.ts +105 -0
- package/dist/patterns/types.d.ts.map +1 -0
- package/dist/patterns/types.js +11 -0
- package/dist/patterns/types.js.map +1 -0
- package/dist/report/index.d.ts +11 -0
- package/dist/report/index.d.ts.map +1 -0
- package/dist/report/index.js +55 -0
- package/dist/report/index.js.map +1 -0
- package/dist/tools/contract-comments.d.ts +48 -0
- package/dist/tools/contract-comments.d.ts.map +1 -0
- package/dist/tools/contract-comments.js +130 -0
- package/dist/tools/contract-comments.js.map +1 -0
- package/dist/tools/index.d.ts +6 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +6 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/scaffold.d.ts +38 -0
- package/dist/tools/scaffold.d.ts.map +1 -0
- package/dist/tools/scaffold.js +373 -0
- package/dist/tools/scaffold.js.map +1 -0
- package/dist/trace/index.d.ts +28 -0
- package/dist/trace/index.d.ts.map +1 -0
- package/dist/trace/index.js +45 -0
- package/dist/trace/index.js.map +1 -0
- package/dist/types.d.ts +135 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +22 -0
- package/dist/types.js.map +1 -0
- package/dist/watch/cache.d.ts +41 -0
- package/dist/watch/cache.d.ts.map +1 -0
- package/dist/watch/cache.js +230 -0
- package/dist/watch/cache.js.map +1 -0
- package/dist/watch/index.d.ts +9 -0
- package/dist/watch/index.d.ts.map +1 -0
- package/dist/watch/index.js +7 -0
- package/dist/watch/index.js.map +1 -0
- package/dist/watch/project.d.ts +128 -0
- package/dist/watch/project.d.ts.map +1 -0
- package/dist/watch/project.js +152 -0
- package/dist/watch/project.js.map +1 -0
- package/dist/watch/watcher.d.ts +76 -0
- package/dist/watch/watcher.d.ts.map +1 -0
- package/dist/watch/watcher.js +235 -0
- package/dist/watch/watcher.js.map +1 -0
- package/package.json +70 -0
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Middleware Detection
|
|
3
|
+
*
|
|
4
|
+
* Detects validation middleware in Express route handlers.
|
|
5
|
+
*
|
|
6
|
+
* @module patterns/rest/middleware
|
|
7
|
+
* @see .context/ADR-P2-2-REST-DETECTION.md
|
|
8
|
+
*/
|
|
9
|
+
import { Node } from 'ts-morph';
|
|
10
|
+
/**
|
|
11
|
+
* Known validation middleware patterns for different libraries
|
|
12
|
+
*/
|
|
13
|
+
const MIDDLEWARE_PATTERNS = [
|
|
14
|
+
// Zod-based validation
|
|
15
|
+
{
|
|
16
|
+
names: ['validateBody', 'zodValidate', 'zValidator'],
|
|
17
|
+
library: 'zod',
|
|
18
|
+
defaultTarget: 'body',
|
|
19
|
+
targetExtractor: extractTargetFromName,
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
names: ['validateQuery'],
|
|
23
|
+
library: 'zod',
|
|
24
|
+
defaultTarget: 'query',
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
names: ['validateParams'],
|
|
28
|
+
library: 'zod',
|
|
29
|
+
defaultTarget: 'params',
|
|
30
|
+
},
|
|
31
|
+
// Celebrate/Joi patterns
|
|
32
|
+
{
|
|
33
|
+
names: ['celebrate'],
|
|
34
|
+
library: 'celebrate',
|
|
35
|
+
defaultTarget: 'body',
|
|
36
|
+
targetExtractor: extractCelebrateTarget,
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
names: ['joiValidate', 'validateJoi'],
|
|
40
|
+
library: 'joi',
|
|
41
|
+
defaultTarget: 'body',
|
|
42
|
+
targetExtractor: extractTargetFromName,
|
|
43
|
+
},
|
|
44
|
+
// Express-validator
|
|
45
|
+
{
|
|
46
|
+
names: ['body', 'check'],
|
|
47
|
+
library: 'express-validator',
|
|
48
|
+
defaultTarget: 'body',
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
names: ['query'],
|
|
52
|
+
library: 'express-validator',
|
|
53
|
+
defaultTarget: 'query',
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
names: ['param'],
|
|
57
|
+
library: 'express-validator',
|
|
58
|
+
defaultTarget: 'params',
|
|
59
|
+
},
|
|
60
|
+
// Yup validation
|
|
61
|
+
{
|
|
62
|
+
names: ['yupValidate', 'validateYup'],
|
|
63
|
+
library: 'yup',
|
|
64
|
+
defaultTarget: 'body',
|
|
65
|
+
targetExtractor: extractTargetFromName,
|
|
66
|
+
},
|
|
67
|
+
];
|
|
68
|
+
/* ═══════════════════════════════════════════════════════════════════════════
|
|
69
|
+
* 🔍 Public API
|
|
70
|
+
* ═══════════════════════════════════════════════════════════════════════════ */
|
|
71
|
+
/**
|
|
72
|
+
* Detect validation middleware from a list of route handler arguments.
|
|
73
|
+
*
|
|
74
|
+
* @param args - Array of AST nodes representing route handler arguments
|
|
75
|
+
* @returns Array of detected validation middleware
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* ```typescript
|
|
79
|
+
* // For: app.post('/users', validateBody(CreateUserSchema), handler)
|
|
80
|
+
* const middleware = detectExpressMiddleware(args);
|
|
81
|
+
* // [{ library: 'zod', target: 'body', schemaNode: <node>, middlewareIndex: 1 }]
|
|
82
|
+
* ```
|
|
83
|
+
*/
|
|
84
|
+
export function detectExpressMiddleware(args) {
|
|
85
|
+
const middleware = [];
|
|
86
|
+
for (let i = 0; i < args.length; i++) {
|
|
87
|
+
const arg = args[i];
|
|
88
|
+
// Skip if not a call expression or identifier reference
|
|
89
|
+
if (!arg)
|
|
90
|
+
continue;
|
|
91
|
+
// Try to detect middleware from this argument
|
|
92
|
+
const detected = detectMiddlewareFromNode(arg, i);
|
|
93
|
+
if (detected) {
|
|
94
|
+
middleware.push(detected);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return middleware;
|
|
98
|
+
}
|
|
99
|
+
/* ═══════════════════════════════════════════════════════════════════════════
|
|
100
|
+
* 🔧 Detection Helpers
|
|
101
|
+
* ═══════════════════════════════════════════════════════════════════════════ */
|
|
102
|
+
/**
|
|
103
|
+
* Detect middleware from a single node.
|
|
104
|
+
*
|
|
105
|
+
* @param node - AST node to analyze
|
|
106
|
+
* @param index - Position in middleware chain
|
|
107
|
+
* @returns Detected middleware or null
|
|
108
|
+
*/
|
|
109
|
+
function detectMiddlewareFromNode(node, index) {
|
|
110
|
+
// Check for call expression: validateBody(schema)
|
|
111
|
+
if (Node.isCallExpression(node)) {
|
|
112
|
+
return detectFromCallExpression(node, index);
|
|
113
|
+
}
|
|
114
|
+
// Check for identifier that might be a pre-configured middleware
|
|
115
|
+
if (Node.isIdentifier(node)) {
|
|
116
|
+
// Could be a variable holding middleware, but we can't easily detect the library
|
|
117
|
+
return null;
|
|
118
|
+
}
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Detect middleware from a call expression
|
|
123
|
+
*/
|
|
124
|
+
function detectFromCallExpression(call, index) {
|
|
125
|
+
const expression = call.getExpression();
|
|
126
|
+
// Get the function name
|
|
127
|
+
let functionName;
|
|
128
|
+
if (Node.isIdentifier(expression)) {
|
|
129
|
+
functionName = expression.getText();
|
|
130
|
+
}
|
|
131
|
+
else if (Node.isPropertyAccessExpression(expression)) {
|
|
132
|
+
// For patterns like validators.body() or z.validate()
|
|
133
|
+
functionName = expression.getName();
|
|
134
|
+
}
|
|
135
|
+
if (!functionName) {
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
138
|
+
// Find matching pattern
|
|
139
|
+
for (const pattern of MIDDLEWARE_PATTERNS) {
|
|
140
|
+
if (pattern.names.some(name => functionName?.toLowerCase().includes(name.toLowerCase()) ||
|
|
141
|
+
name.toLowerCase() === functionName?.toLowerCase())) {
|
|
142
|
+
// Extract target using pattern-specific extractor or use default
|
|
143
|
+
let target = pattern.defaultTarget;
|
|
144
|
+
if (pattern.targetExtractor) {
|
|
145
|
+
const extracted = pattern.targetExtractor(call);
|
|
146
|
+
if (extracted) {
|
|
147
|
+
target = extracted;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
// Get the schema node (usually the first argument)
|
|
151
|
+
const schemaArg = call.getArguments()[0];
|
|
152
|
+
if (schemaArg) {
|
|
153
|
+
return {
|
|
154
|
+
library: pattern.library,
|
|
155
|
+
target,
|
|
156
|
+
schemaNode: schemaArg,
|
|
157
|
+
middlewareIndex: index,
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
// Check for inline zod schema detection (z.object())
|
|
163
|
+
const text = call.getText();
|
|
164
|
+
if (text.includes('z.object') || text.includes('z.array') || text.includes('z.string')) {
|
|
165
|
+
return {
|
|
166
|
+
library: 'zod',
|
|
167
|
+
target: 'body', // Default, would need context to determine
|
|
168
|
+
schemaNode: call,
|
|
169
|
+
middlewareIndex: index,
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
return null;
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Extract target from function name suffix
|
|
176
|
+
* e.g., validateBody -> body, validateQuery -> query
|
|
177
|
+
*/
|
|
178
|
+
function extractTargetFromName(call) {
|
|
179
|
+
const expression = call.getExpression();
|
|
180
|
+
const name = Node.isIdentifier(expression)
|
|
181
|
+
? expression.getText().toLowerCase()
|
|
182
|
+
: Node.isPropertyAccessExpression(expression)
|
|
183
|
+
? expression.getName().toLowerCase()
|
|
184
|
+
: '';
|
|
185
|
+
if (name.includes('body'))
|
|
186
|
+
return 'body';
|
|
187
|
+
if (name.includes('query'))
|
|
188
|
+
return 'query';
|
|
189
|
+
if (name.includes('param'))
|
|
190
|
+
return 'params';
|
|
191
|
+
if (name.includes('header'))
|
|
192
|
+
return 'headers';
|
|
193
|
+
return undefined;
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Extract target from celebrate() configuration
|
|
197
|
+
* celebrate({ [Segments.BODY]: schema, [Segments.QUERY]: schema })
|
|
198
|
+
*/
|
|
199
|
+
function extractCelebrateTarget(call) {
|
|
200
|
+
const args = call.getArguments();
|
|
201
|
+
if (args.length === 0)
|
|
202
|
+
return undefined;
|
|
203
|
+
const configArg = args[0];
|
|
204
|
+
if (!Node.isObjectLiteralExpression(configArg))
|
|
205
|
+
return undefined;
|
|
206
|
+
// Check which segment is being validated
|
|
207
|
+
const text = configArg.getText();
|
|
208
|
+
// Look for Segments enum usage
|
|
209
|
+
if (text.includes('BODY') || text.includes('body'))
|
|
210
|
+
return 'body';
|
|
211
|
+
if (text.includes('QUERY') || text.includes('query'))
|
|
212
|
+
return 'query';
|
|
213
|
+
if (text.includes('PARAMS') || text.includes('params'))
|
|
214
|
+
return 'params';
|
|
215
|
+
if (text.includes('HEADERS') || text.includes('headers'))
|
|
216
|
+
return 'headers';
|
|
217
|
+
return 'body'; // Default to body for celebrate
|
|
218
|
+
}
|
|
219
|
+
//# sourceMappingURL=middleware.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"middleware.js","sourceRoot":"","sources":["../../../src/patterns/rest/middleware.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Path Parser
|
|
3
|
+
*
|
|
4
|
+
* Parses Express/Fastify route paths and extracts path parameters.
|
|
5
|
+
*
|
|
6
|
+
* @module patterns/rest/path-parser
|
|
7
|
+
* @see .context/ADR-P2-2-REST-DETECTION.md
|
|
8
|
+
*/
|
|
9
|
+
import type { PropertyDef } from '../../core/types.js';
|
|
10
|
+
import type { PathParameter } from './types.js';
|
|
11
|
+
/**
|
|
12
|
+
* Parse a route path and extract all path parameters.
|
|
13
|
+
*
|
|
14
|
+
* @param path - Route path like '/users/:id' or '/users/:userId/posts/:postId'
|
|
15
|
+
* @returns Array of parsed path parameters
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```typescript
|
|
19
|
+
* parsePath('/users/:id');
|
|
20
|
+
* // [{ name: 'id', position: 1, optional: false, inferredType: 'string' }]
|
|
21
|
+
*
|
|
22
|
+
* parsePath('/users/:id(\\d+)?');
|
|
23
|
+
* // [{ name: 'id', position: 1, optional: true, pattern: '\\d+', inferredType: 'number' }]
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export declare function parsePath(path: string): PathParameter[];
|
|
27
|
+
/**
|
|
28
|
+
* Convert path parameters to a schema properties object.
|
|
29
|
+
*
|
|
30
|
+
* @param params - Array of path parameters
|
|
31
|
+
* @returns Record of property definitions suitable for NormalizedSchema
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```typescript
|
|
35
|
+
* const params = parsePath('/users/:id(\\d+)');
|
|
36
|
+
* const properties = pathParametersToSchema(params);
|
|
37
|
+
* // {
|
|
38
|
+
* // id: {
|
|
39
|
+
* // type: { kind: 'primitive', value: 'number' },
|
|
40
|
+
* // optional: false,
|
|
41
|
+
* // nullable: false,
|
|
42
|
+
* // readonly: false,
|
|
43
|
+
* // deprecated: false,
|
|
44
|
+
* // constraints: { pattern: '\\d+' }
|
|
45
|
+
* // }
|
|
46
|
+
* // }
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
49
|
+
export declare function pathParametersToSchema(params: PathParameter[]): Record<string, PropertyDef>;
|
|
50
|
+
//# sourceMappingURL=path-parser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"path-parser.d.ts","sourceRoot":"","sources":["../../../src/patterns/rest/path-parser.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAkB,WAAW,EAAE,MAAM,qBAAqB,CAAC;AACvE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAqBhD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,EAAE,CA6BvD;AAmCD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,aAAa,EAAE,GACtB,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CA4B7B"}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Path Parser
|
|
3
|
+
*
|
|
4
|
+
* Parses Express/Fastify route paths and extracts path parameters.
|
|
5
|
+
*
|
|
6
|
+
* @module patterns/rest/path-parser
|
|
7
|
+
* @see .context/ADR-P2-2-REST-DETECTION.md
|
|
8
|
+
*/
|
|
9
|
+
/* ═══════════════════════════════════════════════════════════════════════════
|
|
10
|
+
* 📋 Constants
|
|
11
|
+
* ═══════════════════════════════════════════════════════════════════════════ */
|
|
12
|
+
/**
|
|
13
|
+
* Regular expression to match path parameters.
|
|
14
|
+
*
|
|
15
|
+
* Matches:
|
|
16
|
+
* - `:id` - simple parameter
|
|
17
|
+
* - `:id?` - optional parameter
|
|
18
|
+
* - `:id(\d+)` - regex constrained parameter
|
|
19
|
+
* - `:id(\d+)?` - optional regex constrained parameter
|
|
20
|
+
*/
|
|
21
|
+
const PATH_PARAM_REGEX = /:([a-zA-Z_][a-zA-Z0-9_]*)(?:\(([^)]+)\))?(\?)?/g;
|
|
22
|
+
/* ═══════════════════════════════════════════════════════════════════════════
|
|
23
|
+
* 🔍 Public API
|
|
24
|
+
* ═══════════════════════════════════════════════════════════════════════════ */
|
|
25
|
+
/**
|
|
26
|
+
* Parse a route path and extract all path parameters.
|
|
27
|
+
*
|
|
28
|
+
* @param path - Route path like '/users/:id' or '/users/:userId/posts/:postId'
|
|
29
|
+
* @returns Array of parsed path parameters
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```typescript
|
|
33
|
+
* parsePath('/users/:id');
|
|
34
|
+
* // [{ name: 'id', position: 1, optional: false, inferredType: 'string' }]
|
|
35
|
+
*
|
|
36
|
+
* parsePath('/users/:id(\\d+)?');
|
|
37
|
+
* // [{ name: 'id', position: 1, optional: true, pattern: '\\d+', inferredType: 'number' }]
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
export function parsePath(path) {
|
|
41
|
+
const params = [];
|
|
42
|
+
// Split path into segments to determine positions
|
|
43
|
+
const segments = path.split('/').filter(Boolean);
|
|
44
|
+
// Reset regex lastIndex
|
|
45
|
+
PATH_PARAM_REGEX.lastIndex = 0;
|
|
46
|
+
let match;
|
|
47
|
+
while ((match = PATH_PARAM_REGEX.exec(path)) !== null) {
|
|
48
|
+
const [fullMatch, name, pattern, optionalMark] = match;
|
|
49
|
+
// Find position by looking for the segment that contains this param
|
|
50
|
+
const position = segments.findIndex(seg => seg.includes(fullMatch) || seg.includes(`:${name}`));
|
|
51
|
+
// Infer type from pattern
|
|
52
|
+
const inferredType = inferTypeFromPattern(pattern);
|
|
53
|
+
params.push({
|
|
54
|
+
name,
|
|
55
|
+
position: position >= 0 ? position : params.length,
|
|
56
|
+
optional: optionalMark === '?',
|
|
57
|
+
pattern,
|
|
58
|
+
inferredType,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
return params;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Infer the JavaScript type from a regex pattern.
|
|
65
|
+
*
|
|
66
|
+
* @param pattern - Regex pattern string (e.g., '\\d+', '[0-9]+')
|
|
67
|
+
* @returns Inferred type
|
|
68
|
+
*/
|
|
69
|
+
function inferTypeFromPattern(pattern) {
|
|
70
|
+
if (!pattern) {
|
|
71
|
+
return 'string';
|
|
72
|
+
}
|
|
73
|
+
// Patterns that indicate numeric type
|
|
74
|
+
const numericPatterns = [
|
|
75
|
+
/^\\d\+?$/, // \d or \d+
|
|
76
|
+
/^\\d\*$/, // \d*
|
|
77
|
+
/^\\d\{[\d,]+\}$/, // \d{4} or \d{1,3}
|
|
78
|
+
/^\[0-9\]\+?$/, // [0-9] or [0-9]+
|
|
79
|
+
/^\[0-9\]\*$/, // [0-9]*
|
|
80
|
+
/^\[0-9\]\{[\d,]+\}$/, // [0-9]{4}
|
|
81
|
+
];
|
|
82
|
+
// Normalize the pattern for matching
|
|
83
|
+
const normalized = pattern.trim();
|
|
84
|
+
for (const numericPattern of numericPatterns) {
|
|
85
|
+
if (numericPattern.test(normalized)) {
|
|
86
|
+
return 'number';
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return 'string';
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Convert path parameters to a schema properties object.
|
|
93
|
+
*
|
|
94
|
+
* @param params - Array of path parameters
|
|
95
|
+
* @returns Record of property definitions suitable for NormalizedSchema
|
|
96
|
+
*
|
|
97
|
+
* @example
|
|
98
|
+
* ```typescript
|
|
99
|
+
* const params = parsePath('/users/:id(\\d+)');
|
|
100
|
+
* const properties = pathParametersToSchema(params);
|
|
101
|
+
* // {
|
|
102
|
+
* // id: {
|
|
103
|
+
* // type: { kind: 'primitive', value: 'number' },
|
|
104
|
+
* // optional: false,
|
|
105
|
+
* // nullable: false,
|
|
106
|
+
* // readonly: false,
|
|
107
|
+
* // deprecated: false,
|
|
108
|
+
* // constraints: { pattern: '\\d+' }
|
|
109
|
+
* // }
|
|
110
|
+
* // }
|
|
111
|
+
* ```
|
|
112
|
+
*/
|
|
113
|
+
export function pathParametersToSchema(params) {
|
|
114
|
+
const properties = {};
|
|
115
|
+
for (const param of params) {
|
|
116
|
+
const type = {
|
|
117
|
+
kind: 'primitive',
|
|
118
|
+
value: param.inferredType === 'number' ? 'number' : 'string',
|
|
119
|
+
};
|
|
120
|
+
const propDef = {
|
|
121
|
+
type,
|
|
122
|
+
optional: param.optional,
|
|
123
|
+
nullable: false,
|
|
124
|
+
readonly: false,
|
|
125
|
+
deprecated: false,
|
|
126
|
+
};
|
|
127
|
+
// Add pattern constraint if present
|
|
128
|
+
if (param.pattern) {
|
|
129
|
+
propDef.constraints = {
|
|
130
|
+
pattern: param.pattern,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
properties[param.name] = propDef;
|
|
134
|
+
}
|
|
135
|
+
return properties;
|
|
136
|
+
}
|
|
137
|
+
//# sourceMappingURL=path-parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"path-parser.js","sourceRoot":"","sources":["../../../src/patterns/rest/path-parser.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Response Inference
|
|
3
|
+
*
|
|
4
|
+
* Infers response schema from handler function implementations.
|
|
5
|
+
*
|
|
6
|
+
* @module patterns/rest/response-inference
|
|
7
|
+
* @see .context/ADR-P2-2-REST-DETECTION.md
|
|
8
|
+
*/
|
|
9
|
+
import { Node } from 'ts-morph';
|
|
10
|
+
import type { ResponseInference } from './types.js';
|
|
11
|
+
/**
|
|
12
|
+
* Infer the response schema from a handler function.
|
|
13
|
+
*
|
|
14
|
+
* Uses multiple strategies:
|
|
15
|
+
* 1. Explicit return type annotation
|
|
16
|
+
* 2. Generic type parameter on res.json<T>()
|
|
17
|
+
* 3. Analysis of res.json() argument structure
|
|
18
|
+
*
|
|
19
|
+
* @param handler - The handler function AST node
|
|
20
|
+
* @returns Response inference result with method and optional schema node
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```typescript
|
|
24
|
+
* // Handler: (req, res) => res.json<ProfileResponse>({ id: '123', name: 'John' })
|
|
25
|
+
* const inference = inferResponseSchema(handler);
|
|
26
|
+
* // { method: 'generic-param', node: <ProfileResponse node> }
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export declare function inferResponseSchema(handler: Node | undefined): ResponseInference;
|
|
30
|
+
/**
|
|
31
|
+
* Detect multiple response schemas by status code.
|
|
32
|
+
*
|
|
33
|
+
* @param handler - The handler function AST node
|
|
34
|
+
* @returns Map of status codes to response schema nodes
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ```typescript
|
|
38
|
+
* // Handler with res.status(200).json(ok) and res.status(400).json(error)
|
|
39
|
+
* const responses = detectMultipleResponses(handler);
|
|
40
|
+
* // Map { 200 => <ok node>, 400 => <error node> }
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
export declare function detectMultipleResponses(handler: Node | undefined): Map<number, Node>;
|
|
44
|
+
//# sourceMappingURL=response-inference.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"response-inference.d.ts","sourceRoot":"","sources":["../../../src/patterns/rest/response-inference.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,IAAI,EAA8B,MAAM,UAAU,CAAC;AAE5D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAMpD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,IAAI,GAAG,SAAS,GAAG,iBAAiB,CAwBhF;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,IAAI,GAAG,SAAS,GAAG,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAmBpF"}
|