@contractspec/lib.source-extractors 0.0.0-canary-20260119222405

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.
Files changed (78) hide show
  1. package/README.md +86 -0
  2. package/dist/_virtual/rolldown_runtime.js +18 -0
  3. package/dist/codegen/index.d.ts +12 -0
  4. package/dist/codegen/index.d.ts.map +1 -0
  5. package/dist/codegen/index.js +17 -0
  6. package/dist/codegen/index.js.map +1 -0
  7. package/dist/codegen/operation-gen.d.ts +16 -0
  8. package/dist/codegen/operation-gen.d.ts.map +1 -0
  9. package/dist/codegen/operation-gen.js +91 -0
  10. package/dist/codegen/operation-gen.js.map +1 -0
  11. package/dist/codegen/registry-gen.d.ts +11 -0
  12. package/dist/codegen/registry-gen.d.ts.map +1 -0
  13. package/dist/codegen/registry-gen.js +47 -0
  14. package/dist/codegen/registry-gen.js.map +1 -0
  15. package/dist/codegen/schema-gen.d.ts +16 -0
  16. package/dist/codegen/schema-gen.d.ts.map +1 -0
  17. package/dist/codegen/schema-gen.js +93 -0
  18. package/dist/codegen/schema-gen.js.map +1 -0
  19. package/dist/codegen/types.d.ts +48 -0
  20. package/dist/codegen/types.d.ts.map +1 -0
  21. package/dist/detect.d.ts +47 -0
  22. package/dist/detect.d.ts.map +1 -0
  23. package/dist/detect.js +177 -0
  24. package/dist/detect.js.map +1 -0
  25. package/dist/extract.d.ts +24 -0
  26. package/dist/extract.d.ts.map +1 -0
  27. package/dist/extract.js +125 -0
  28. package/dist/extract.js.map +1 -0
  29. package/dist/extractors/base.d.ts +90 -0
  30. package/dist/extractors/base.d.ts.map +1 -0
  31. package/dist/extractors/base.js +152 -0
  32. package/dist/extractors/base.js.map +1 -0
  33. package/dist/extractors/elysia/extractor.d.ts +15 -0
  34. package/dist/extractors/elysia/extractor.d.ts.map +1 -0
  35. package/dist/extractors/elysia/extractor.js +58 -0
  36. package/dist/extractors/elysia/extractor.js.map +1 -0
  37. package/dist/extractors/express/extractor.d.ts +15 -0
  38. package/dist/extractors/express/extractor.d.ts.map +1 -0
  39. package/dist/extractors/express/extractor.js +61 -0
  40. package/dist/extractors/express/extractor.js.map +1 -0
  41. package/dist/extractors/fastify/extractor.d.ts +15 -0
  42. package/dist/extractors/fastify/extractor.d.ts.map +1 -0
  43. package/dist/extractors/fastify/extractor.js +61 -0
  44. package/dist/extractors/fastify/extractor.js.map +1 -0
  45. package/dist/extractors/hono/extractor.d.ts +15 -0
  46. package/dist/extractors/hono/extractor.d.ts.map +1 -0
  47. package/dist/extractors/hono/extractor.js +57 -0
  48. package/dist/extractors/hono/extractor.js.map +1 -0
  49. package/dist/extractors/index.d.ts +21 -0
  50. package/dist/extractors/index.d.ts.map +1 -0
  51. package/dist/extractors/index.js +42 -0
  52. package/dist/extractors/index.js.map +1 -0
  53. package/dist/extractors/nestjs/extractor.d.ts +29 -0
  54. package/dist/extractors/nestjs/extractor.d.ts.map +1 -0
  55. package/dist/extractors/nestjs/extractor.js +118 -0
  56. package/dist/extractors/nestjs/extractor.js.map +1 -0
  57. package/dist/extractors/next-api/extractor.d.ts +16 -0
  58. package/dist/extractors/next-api/extractor.d.ts.map +1 -0
  59. package/dist/extractors/next-api/extractor.js +80 -0
  60. package/dist/extractors/next-api/extractor.js.map +1 -0
  61. package/dist/extractors/trpc/extractor.d.ts +15 -0
  62. package/dist/extractors/trpc/extractor.d.ts.map +1 -0
  63. package/dist/extractors/trpc/extractor.js +71 -0
  64. package/dist/extractors/trpc/extractor.js.map +1 -0
  65. package/dist/extractors/zod/extractor.d.ts +16 -0
  66. package/dist/extractors/zod/extractor.d.ts.map +1 -0
  67. package/dist/extractors/zod/extractor.js +69 -0
  68. package/dist/extractors/zod/extractor.js.map +1 -0
  69. package/dist/index.d.ts +7 -0
  70. package/dist/index.js +7 -0
  71. package/dist/registry.d.ts +85 -0
  72. package/dist/registry.d.ts.map +1 -0
  73. package/dist/registry.js +87 -0
  74. package/dist/registry.js.map +1 -0
  75. package/dist/types.d.ts +272 -0
  76. package/dist/types.d.ts.map +1 -0
  77. package/dist/types.js +0 -0
  78. package/package.json +71 -0
package/dist/detect.js ADDED
@@ -0,0 +1,177 @@
1
+ //#region src/detect.ts
2
+ /**
3
+ * Built-in framework detection rules.
4
+ */
5
+ const FRAMEWORK_RULES = [
6
+ {
7
+ id: "nestjs",
8
+ name: "NestJS",
9
+ packages: ["@nestjs/core", "@nestjs/common"],
10
+ importPatterns: [/@nestjs\//]
11
+ },
12
+ {
13
+ id: "express",
14
+ name: "Express",
15
+ packages: ["express"],
16
+ importPatterns: [/from ['"]express['"]/]
17
+ },
18
+ {
19
+ id: "fastify",
20
+ name: "Fastify",
21
+ packages: ["fastify"],
22
+ importPatterns: [/from ['"]fastify['"]/]
23
+ },
24
+ {
25
+ id: "hono",
26
+ name: "Hono",
27
+ packages: ["hono"],
28
+ importPatterns: [/from ['"]hono['"]/]
29
+ },
30
+ {
31
+ id: "elysia",
32
+ name: "Elysia",
33
+ packages: ["elysia"],
34
+ importPatterns: [/from ['"]elysia['"]/]
35
+ },
36
+ {
37
+ id: "trpc",
38
+ name: "tRPC",
39
+ packages: ["@trpc/server"],
40
+ importPatterns: [/@trpc\/server/]
41
+ },
42
+ {
43
+ id: "next-api",
44
+ name: "Next.js API",
45
+ packages: ["next"],
46
+ filePatterns: [/app\/api\/.*\/route\.ts$/, /pages\/api\/.*\.ts$/]
47
+ },
48
+ {
49
+ id: "koa",
50
+ name: "Koa",
51
+ packages: ["koa", "@koa/router"],
52
+ importPatterns: [/from ['"]koa['"]/]
53
+ },
54
+ {
55
+ id: "hapi",
56
+ name: "Hapi",
57
+ packages: ["@hapi/hapi"],
58
+ importPatterns: [/@hapi\/hapi/]
59
+ }
60
+ ];
61
+ /**
62
+ * Detect frameworks from package.json dependencies.
63
+ */
64
+ function detectFrameworksFromPackageJson(packageJson) {
65
+ const allDeps = {
66
+ ...packageJson.dependencies,
67
+ ...packageJson.devDependencies,
68
+ ...packageJson.peerDependencies
69
+ };
70
+ const detected = [];
71
+ for (const rule of FRAMEWORK_RULES) for (const pkg of rule.packages) if (pkg in allDeps) {
72
+ detected.push({
73
+ id: rule.id,
74
+ name: rule.name,
75
+ version: allDeps[pkg],
76
+ confidence: "high"
77
+ });
78
+ break;
79
+ }
80
+ return detected;
81
+ }
82
+ /**
83
+ * Detect frameworks from source code imports.
84
+ */
85
+ function detectFrameworksFromCode(sourceCode) {
86
+ const detected = [];
87
+ const seenIds = /* @__PURE__ */ new Set();
88
+ for (const rule of FRAMEWORK_RULES) {
89
+ if (!rule.importPatterns) continue;
90
+ for (const pattern of rule.importPatterns) if (pattern.test(sourceCode) && !seenIds.has(rule.id)) {
91
+ detected.push({
92
+ id: rule.id,
93
+ name: rule.name,
94
+ confidence: "medium"
95
+ });
96
+ seenIds.add(rule.id);
97
+ break;
98
+ }
99
+ }
100
+ return detected;
101
+ }
102
+ /**
103
+ * Detect frameworks from file paths.
104
+ */
105
+ function detectFrameworksFromPaths(filePaths) {
106
+ const detected = [];
107
+ const seenIds = /* @__PURE__ */ new Set();
108
+ for (const rule of FRAMEWORK_RULES) {
109
+ if (!rule.filePatterns) continue;
110
+ for (const pattern of rule.filePatterns) for (const filePath of filePaths) if (pattern.test(filePath) && !seenIds.has(rule.id)) {
111
+ detected.push({
112
+ id: rule.id,
113
+ name: rule.name,
114
+ confidence: "medium"
115
+ });
116
+ seenIds.add(rule.id);
117
+ break;
118
+ }
119
+ }
120
+ return detected;
121
+ }
122
+ /**
123
+ * Merge framework detections, preferring higher confidence.
124
+ */
125
+ function mergeFrameworkDetections(...detections) {
126
+ const byId = /* @__PURE__ */ new Map();
127
+ const confidenceOrder = {
128
+ high: 3,
129
+ medium: 2,
130
+ low: 1,
131
+ ambiguous: 0
132
+ };
133
+ for (const group of detections) for (const fw of group) {
134
+ const existing = byId.get(fw.id);
135
+ if (!existing || confidenceOrder[fw.confidence] > confidenceOrder[existing.confidence]) byId.set(fw.id, fw);
136
+ }
137
+ return Array.from(byId.values());
138
+ }
139
+ /**
140
+ * Detect frameworks for a project.
141
+ * This is a convenience function that combines all detection methods.
142
+ */
143
+ async function detectFramework(rootPath, options) {
144
+ const project = {
145
+ rootPath,
146
+ frameworks: []
147
+ };
148
+ if (options?.readFile) try {
149
+ const packageJsonPath = `${rootPath}/package.json`;
150
+ const content = await options.readFile(packageJsonPath);
151
+ const packageJson = JSON.parse(content);
152
+ project.packageJsonPath = packageJsonPath;
153
+ project.frameworks = detectFrameworksFromPackageJson(packageJson);
154
+ } catch {}
155
+ if (options?.readFile) try {
156
+ const tsConfigPath = `${rootPath}/tsconfig.json`;
157
+ await options.readFile(tsConfigPath);
158
+ project.tsConfigPath = tsConfigPath;
159
+ } catch {}
160
+ return project;
161
+ }
162
+ /**
163
+ * Get all supported framework IDs.
164
+ */
165
+ function getSupportedFrameworks() {
166
+ return FRAMEWORK_RULES.map((r) => r.id);
167
+ }
168
+ /**
169
+ * Check if a framework ID is supported.
170
+ */
171
+ function isFrameworkSupported(id) {
172
+ return FRAMEWORK_RULES.some((r) => r.id === id);
173
+ }
174
+
175
+ //#endregion
176
+ export { detectFramework, detectFrameworksFromCode, detectFrameworksFromPackageJson, detectFrameworksFromPaths, getSupportedFrameworks, isFrameworkSupported, mergeFrameworkDetections };
177
+ //# sourceMappingURL=detect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detect.js","names":[],"sources":["../src/detect.ts"],"sourcesContent":["/**\n * Framework detection utilities.\n *\n * Analyzes a project to detect which frameworks are in use.\n */\n\nimport type { ConfidenceLevel, FrameworkInfo, ProjectInfo } from './types';\n\n/**\n * Framework detection rule.\n */\ninterface FrameworkDetectionRule {\n id: string;\n name: string;\n /** Package names that indicate this framework */\n packages: string[];\n /** File patterns that indicate this framework */\n filePatterns?: RegExp[];\n /** Import patterns in code that indicate this framework */\n importPatterns?: RegExp[];\n}\n\n/**\n * Built-in framework detection rules.\n */\nconst FRAMEWORK_RULES: FrameworkDetectionRule[] = [\n {\n id: 'nestjs',\n name: 'NestJS',\n packages: ['@nestjs/core', '@nestjs/common'],\n importPatterns: [/@nestjs\\//],\n },\n {\n id: 'express',\n name: 'Express',\n packages: ['express'],\n importPatterns: [/from ['\"]express['\"]/],\n },\n {\n id: 'fastify',\n name: 'Fastify',\n packages: ['fastify'],\n importPatterns: [/from ['\"]fastify['\"]/],\n },\n {\n id: 'hono',\n name: 'Hono',\n packages: ['hono'],\n importPatterns: [/from ['\"]hono['\"]/],\n },\n {\n id: 'elysia',\n name: 'Elysia',\n packages: ['elysia'],\n importPatterns: [/from ['\"]elysia['\"]/],\n },\n {\n id: 'trpc',\n name: 'tRPC',\n packages: ['@trpc/server'],\n importPatterns: [/@trpc\\/server/],\n },\n {\n id: 'next-api',\n name: 'Next.js API',\n packages: ['next'],\n filePatterns: [/app\\/api\\/.*\\/route\\.ts$/, /pages\\/api\\/.*\\.ts$/],\n },\n {\n id: 'koa',\n name: 'Koa',\n packages: ['koa', '@koa/router'],\n importPatterns: [/from ['\"]koa['\"]/],\n },\n {\n id: 'hapi',\n name: 'Hapi',\n packages: ['@hapi/hapi'],\n importPatterns: [/@hapi\\/hapi/],\n },\n];\n\n/**\n * Dependencies from package.json.\n */\ninterface PackageDependencies {\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n peerDependencies?: Record<string, string>;\n}\n\n/**\n * Detect frameworks from package.json dependencies.\n */\nexport function detectFrameworksFromPackageJson(\n packageJson: PackageDependencies\n): FrameworkInfo[] {\n const allDeps = {\n ...packageJson.dependencies,\n ...packageJson.devDependencies,\n ...packageJson.peerDependencies,\n };\n\n const detected: FrameworkInfo[] = [];\n\n for (const rule of FRAMEWORK_RULES) {\n for (const pkg of rule.packages) {\n if (pkg in allDeps) {\n detected.push({\n id: rule.id,\n name: rule.name,\n version: allDeps[pkg],\n confidence: 'high',\n });\n break; // Only add once per framework\n }\n }\n }\n\n return detected;\n}\n\n/**\n * Detect frameworks from source code imports.\n */\nexport function detectFrameworksFromCode(sourceCode: string): FrameworkInfo[] {\n const detected: FrameworkInfo[] = [];\n const seenIds = new Set<string>();\n\n for (const rule of FRAMEWORK_RULES) {\n if (!rule.importPatterns) continue;\n\n for (const pattern of rule.importPatterns) {\n if (pattern.test(sourceCode) && !seenIds.has(rule.id)) {\n detected.push({\n id: rule.id,\n name: rule.name,\n confidence: 'medium',\n });\n seenIds.add(rule.id);\n break;\n }\n }\n }\n\n return detected;\n}\n\n/**\n * Detect frameworks from file paths.\n */\nexport function detectFrameworksFromPaths(\n filePaths: string[]\n): FrameworkInfo[] {\n const detected: FrameworkInfo[] = [];\n const seenIds = new Set<string>();\n\n for (const rule of FRAMEWORK_RULES) {\n if (!rule.filePatterns) continue;\n\n for (const pattern of rule.filePatterns) {\n for (const filePath of filePaths) {\n if (pattern.test(filePath) && !seenIds.has(rule.id)) {\n detected.push({\n id: rule.id,\n name: rule.name,\n confidence: 'medium',\n });\n seenIds.add(rule.id);\n break;\n }\n }\n }\n }\n\n return detected;\n}\n\n/**\n * Merge framework detections, preferring higher confidence.\n */\nexport function mergeFrameworkDetections(\n ...detections: FrameworkInfo[][]\n): FrameworkInfo[] {\n const byId = new Map<string, FrameworkInfo>();\n\n const confidenceOrder: Record<ConfidenceLevel, number> = {\n high: 3,\n medium: 2,\n low: 1,\n ambiguous: 0,\n };\n\n for (const group of detections) {\n for (const fw of group) {\n const existing = byId.get(fw.id);\n if (\n !existing ||\n confidenceOrder[fw.confidence] > confidenceOrder[existing.confidence]\n ) {\n byId.set(fw.id, fw);\n }\n }\n }\n\n return Array.from(byId.values());\n}\n\n/**\n * Detect frameworks for a project.\n * This is a convenience function that combines all detection methods.\n */\nexport async function detectFramework(\n rootPath: string,\n options?: {\n readFile?: (path: string) => Promise<string>;\n glob?: (pattern: string) => Promise<string[]>;\n }\n): Promise<ProjectInfo> {\n const project: ProjectInfo = {\n rootPath,\n frameworks: [],\n };\n\n // Try to read package.json\n if (options?.readFile) {\n try {\n const packageJsonPath = `${rootPath}/package.json`;\n const content = await options.readFile(packageJsonPath);\n const packageJson = JSON.parse(content) as PackageDependencies;\n project.packageJsonPath = packageJsonPath;\n project.frameworks = detectFrameworksFromPackageJson(packageJson);\n } catch {\n // No package.json or parse error\n }\n }\n\n // Check for tsconfig.json\n if (options?.readFile) {\n try {\n const tsConfigPath = `${rootPath}/tsconfig.json`;\n await options.readFile(tsConfigPath);\n project.tsConfigPath = tsConfigPath;\n } catch {\n // No tsconfig.json\n }\n }\n\n return project;\n}\n\n/**\n * Get all supported framework IDs.\n */\nexport function getSupportedFrameworks(): string[] {\n return FRAMEWORK_RULES.map((r) => r.id);\n}\n\n/**\n * Check if a framework ID is supported.\n */\nexport function isFrameworkSupported(id: string): boolean {\n return FRAMEWORK_RULES.some((r) => r.id === id);\n}\n"],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import { ExtractOptions, ExtractResult, ImportIR, ProjectInfo } from "./types.js";
2
+
3
+ //#region src/extract.d.ts
4
+
5
+ /**
6
+ * Extract contracts from a project.
7
+ *
8
+ * @param project Project information (from detectFramework)
9
+ * @param options Extraction options
10
+ * @returns Extraction result with IR
11
+ */
12
+ declare function extractFromProject(project: ProjectInfo, options?: ExtractOptions): Promise<ExtractResult>;
13
+ /**
14
+ * Merge multiple IRs into one.
15
+ * Useful when extracting from multiple sources or frameworks.
16
+ */
17
+ declare function mergeIRs(irs: ImportIR[]): ImportIR;
18
+ /**
19
+ * Create an empty IR structure.
20
+ */
21
+ declare function createEmptyIR(project: ProjectInfo): ImportIR;
22
+ //#endregion
23
+ export { createEmptyIR, extractFromProject, mergeIRs };
24
+ //# sourceMappingURL=extract.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extract.d.ts","names":[],"sources":["../src/extract.ts"],"sourcesContent":[],"mappings":";;;;;;AAsFA;AA0DA;;;;iBA1HsB,kBAAA,UACX,uBACA,iBACR,QAAQ;;;;;iBA6DK,QAAA,MAAc,aAAa;;;;iBA0D3B,aAAA,UAAuB,cAAc"}
@@ -0,0 +1,125 @@
1
+ import { extractorRegistry } from "./registry.js";
2
+
3
+ //#region src/extract.ts
4
+ /**
5
+ * Extract contracts from a project.
6
+ *
7
+ * @param project Project information (from detectFramework)
8
+ * @param options Extraction options
9
+ * @returns Extraction result with IR
10
+ */
11
+ async function extractFromProject(project, options = {}) {
12
+ let extractors;
13
+ if (options.framework) {
14
+ extractors = extractorRegistry.findByFramework(options.framework);
15
+ if (extractors.length === 0) return {
16
+ success: false,
17
+ errors: [{
18
+ code: "EXTRACTOR_NOT_FOUND",
19
+ message: `No extractor found for framework: ${options.framework}`,
20
+ recoverable: false
21
+ }]
22
+ };
23
+ } else {
24
+ extractors = await extractorRegistry.findMatching(project);
25
+ if (extractors.length === 0) return {
26
+ success: false,
27
+ errors: [{
28
+ code: "NO_FRAMEWORK_DETECTED",
29
+ message: "No supported framework detected in project",
30
+ recoverable: false
31
+ }]
32
+ };
33
+ }
34
+ const extractor = extractors[0];
35
+ if (!extractor) return {
36
+ success: false,
37
+ errors: [{
38
+ code: "NO_EXTRACTOR",
39
+ message: "No extractor available",
40
+ recoverable: false
41
+ }]
42
+ };
43
+ return await extractor.extract(project, options);
44
+ }
45
+ /**
46
+ * Merge multiple IRs into one.
47
+ * Useful when extracting from multiple sources or frameworks.
48
+ */
49
+ function mergeIRs(irs) {
50
+ if (irs.length === 0) throw new Error("Cannot merge empty IR array");
51
+ if (irs.length === 1) {
52
+ if (!irs[0]) throw new Error("First IR is undefined");
53
+ return irs[0];
54
+ }
55
+ const first = irs[0];
56
+ if (!first) throw new Error("First IR is undefined");
57
+ const merged = {
58
+ version: "1.0",
59
+ extractedAt: (/* @__PURE__ */ new Date()).toISOString(),
60
+ project: first.project,
61
+ endpoints: [],
62
+ schemas: [],
63
+ errors: [],
64
+ events: [],
65
+ ambiguities: [],
66
+ stats: {
67
+ filesScanned: 0,
68
+ endpointsFound: 0,
69
+ schemasFound: 0,
70
+ errorsFound: 0,
71
+ eventsFound: 0,
72
+ ambiguitiesFound: 0,
73
+ highConfidence: 0,
74
+ mediumConfidence: 0,
75
+ lowConfidence: 0
76
+ }
77
+ };
78
+ for (const ir of irs) {
79
+ merged.endpoints.push(...ir.endpoints);
80
+ merged.schemas.push(...ir.schemas);
81
+ merged.errors.push(...ir.errors);
82
+ merged.events.push(...ir.events);
83
+ merged.ambiguities.push(...ir.ambiguities);
84
+ merged.stats.filesScanned += ir.stats.filesScanned;
85
+ merged.stats.endpointsFound += ir.stats.endpointsFound;
86
+ merged.stats.schemasFound += ir.stats.schemasFound;
87
+ merged.stats.errorsFound += ir.stats.errorsFound;
88
+ merged.stats.eventsFound += ir.stats.eventsFound;
89
+ merged.stats.ambiguitiesFound += ir.stats.ambiguitiesFound;
90
+ merged.stats.highConfidence += ir.stats.highConfidence;
91
+ merged.stats.mediumConfidence += ir.stats.mediumConfidence;
92
+ merged.stats.lowConfidence += ir.stats.lowConfidence;
93
+ }
94
+ return merged;
95
+ }
96
+ /**
97
+ * Create an empty IR structure.
98
+ */
99
+ function createEmptyIR(project) {
100
+ return {
101
+ version: "1.0",
102
+ extractedAt: (/* @__PURE__ */ new Date()).toISOString(),
103
+ project,
104
+ endpoints: [],
105
+ schemas: [],
106
+ errors: [],
107
+ events: [],
108
+ ambiguities: [],
109
+ stats: {
110
+ filesScanned: 0,
111
+ endpointsFound: 0,
112
+ schemasFound: 0,
113
+ errorsFound: 0,
114
+ eventsFound: 0,
115
+ ambiguitiesFound: 0,
116
+ highConfidence: 0,
117
+ mediumConfidence: 0,
118
+ lowConfidence: 0
119
+ }
120
+ };
121
+ }
122
+
123
+ //#endregion
124
+ export { createEmptyIR, extractFromProject, mergeIRs };
125
+ //# sourceMappingURL=extract.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extract.js","names":[],"sources":["../src/extract.ts"],"sourcesContent":["/**\n * Main extraction function.\n *\n * Orchestrates the extraction process using detected frameworks\n * and registered extractors.\n */\n\nimport type {\n ExtractOptions,\n ExtractResult,\n ImportIR,\n ProjectInfo,\n} from './types';\nimport { extractorRegistry } from './registry';\n\n/**\n * Extract contracts from a project.\n *\n * @param project Project information (from detectFramework)\n * @param options Extraction options\n * @returns Extraction result with IR\n */\nexport async function extractFromProject(\n project: ProjectInfo,\n options: ExtractOptions = {}\n): Promise<ExtractResult> {\n // Find matching extractors\n let extractors;\n\n if (options.framework) {\n // Use specific framework if requested\n extractors = extractorRegistry.findByFramework(options.framework);\n if (extractors.length === 0) {\n return {\n success: false,\n errors: [\n {\n code: 'EXTRACTOR_NOT_FOUND',\n message: `No extractor found for framework: ${options.framework}`,\n recoverable: false,\n },\n ],\n };\n }\n } else {\n // Auto-detect\n extractors = await extractorRegistry.findMatching(project);\n if (extractors.length === 0) {\n return {\n success: false,\n errors: [\n {\n code: 'NO_FRAMEWORK_DETECTED',\n message: 'No supported framework detected in project',\n recoverable: false,\n },\n ],\n };\n }\n }\n\n // Use the highest priority extractor\n const extractor = extractors[0];\n if (!extractor) {\n return {\n success: false,\n errors: [\n {\n code: 'NO_EXTRACTOR',\n message: 'No extractor available',\n recoverable: false,\n },\n ],\n };\n }\n\n // Run extraction\n const result = await extractor.extract(project, options);\n\n return result;\n}\n\n/**\n * Merge multiple IRs into one.\n * Useful when extracting from multiple sources or frameworks.\n */\nexport function mergeIRs(irs: ImportIR[]): ImportIR {\n if (irs.length === 0) {\n throw new Error('Cannot merge empty IR array');\n }\n\n if (irs.length === 1) {\n if (!irs[0]) throw new Error('First IR is undefined');\n return irs[0];\n }\n\n const first = irs[0];\n if (!first) throw new Error('First IR is undefined');\n const merged: ImportIR = {\n version: '1.0',\n extractedAt: new Date().toISOString(),\n project: first.project,\n endpoints: [],\n schemas: [],\n errors: [],\n events: [],\n ambiguities: [],\n stats: {\n filesScanned: 0,\n endpointsFound: 0,\n schemasFound: 0,\n errorsFound: 0,\n eventsFound: 0,\n ambiguitiesFound: 0,\n highConfidence: 0,\n mediumConfidence: 0,\n lowConfidence: 0,\n },\n };\n\n for (const ir of irs) {\n merged.endpoints.push(...ir.endpoints);\n merged.schemas.push(...ir.schemas);\n merged.errors.push(...ir.errors);\n merged.events.push(...ir.events);\n merged.ambiguities.push(...ir.ambiguities);\n\n merged.stats.filesScanned += ir.stats.filesScanned;\n merged.stats.endpointsFound += ir.stats.endpointsFound;\n merged.stats.schemasFound += ir.stats.schemasFound;\n merged.stats.errorsFound += ir.stats.errorsFound;\n merged.stats.eventsFound += ir.stats.eventsFound;\n merged.stats.ambiguitiesFound += ir.stats.ambiguitiesFound;\n merged.stats.highConfidence += ir.stats.highConfidence;\n merged.stats.mediumConfidence += ir.stats.mediumConfidence;\n merged.stats.lowConfidence += ir.stats.lowConfidence;\n }\n\n return merged;\n}\n\n/**\n * Create an empty IR structure.\n */\nexport function createEmptyIR(project: ProjectInfo): ImportIR {\n return {\n version: '1.0',\n extractedAt: new Date().toISOString(),\n project,\n endpoints: [],\n schemas: [],\n errors: [],\n events: [],\n ambiguities: [],\n stats: {\n filesScanned: 0,\n endpointsFound: 0,\n schemasFound: 0,\n errorsFound: 0,\n eventsFound: 0,\n ambiguitiesFound: 0,\n highConfidence: 0,\n mediumConfidence: 0,\n lowConfidence: 0,\n },\n };\n}\n"],"mappings":";;;;;;;;;;AAsBA,eAAsB,mBACpB,SACA,UAA0B,EAAE,EACJ;CAExB,IAAI;AAEJ,KAAI,QAAQ,WAAW;AAErB,eAAa,kBAAkB,gBAAgB,QAAQ,UAAU;AACjE,MAAI,WAAW,WAAW,EACxB,QAAO;GACL,SAAS;GACT,QAAQ,CACN;IACE,MAAM;IACN,SAAS,qCAAqC,QAAQ;IACtD,aAAa;IACd,CACF;GACF;QAEE;AAEL,eAAa,MAAM,kBAAkB,aAAa,QAAQ;AAC1D,MAAI,WAAW,WAAW,EACxB,QAAO;GACL,SAAS;GACT,QAAQ,CACN;IACE,MAAM;IACN,SAAS;IACT,aAAa;IACd,CACF;GACF;;CAKL,MAAM,YAAY,WAAW;AAC7B,KAAI,CAAC,UACH,QAAO;EACL,SAAS;EACT,QAAQ,CACN;GACE,MAAM;GACN,SAAS;GACT,aAAa;GACd,CACF;EACF;AAMH,QAFe,MAAM,UAAU,QAAQ,SAAS,QAAQ;;;;;;AAS1D,SAAgB,SAAS,KAA2B;AAClD,KAAI,IAAI,WAAW,EACjB,OAAM,IAAI,MAAM,8BAA8B;AAGhD,KAAI,IAAI,WAAW,GAAG;AACpB,MAAI,CAAC,IAAI,GAAI,OAAM,IAAI,MAAM,wBAAwB;AACrD,SAAO,IAAI;;CAGb,MAAM,QAAQ,IAAI;AAClB,KAAI,CAAC,MAAO,OAAM,IAAI,MAAM,wBAAwB;CACpD,MAAM,SAAmB;EACvB,SAAS;EACT,8BAAa,IAAI,MAAM,EAAC,aAAa;EACrC,SAAS,MAAM;EACf,WAAW,EAAE;EACb,SAAS,EAAE;EACX,QAAQ,EAAE;EACV,QAAQ,EAAE;EACV,aAAa,EAAE;EACf,OAAO;GACL,cAAc;GACd,gBAAgB;GAChB,cAAc;GACd,aAAa;GACb,aAAa;GACb,kBAAkB;GAClB,gBAAgB;GAChB,kBAAkB;GAClB,eAAe;GAChB;EACF;AAED,MAAK,MAAM,MAAM,KAAK;AACpB,SAAO,UAAU,KAAK,GAAG,GAAG,UAAU;AACtC,SAAO,QAAQ,KAAK,GAAG,GAAG,QAAQ;AAClC,SAAO,OAAO,KAAK,GAAG,GAAG,OAAO;AAChC,SAAO,OAAO,KAAK,GAAG,GAAG,OAAO;AAChC,SAAO,YAAY,KAAK,GAAG,GAAG,YAAY;AAE1C,SAAO,MAAM,gBAAgB,GAAG,MAAM;AACtC,SAAO,MAAM,kBAAkB,GAAG,MAAM;AACxC,SAAO,MAAM,gBAAgB,GAAG,MAAM;AACtC,SAAO,MAAM,eAAe,GAAG,MAAM;AACrC,SAAO,MAAM,eAAe,GAAG,MAAM;AACrC,SAAO,MAAM,oBAAoB,GAAG,MAAM;AAC1C,SAAO,MAAM,kBAAkB,GAAG,MAAM;AACxC,SAAO,MAAM,oBAAoB,GAAG,MAAM;AAC1C,SAAO,MAAM,iBAAiB,GAAG,MAAM;;AAGzC,QAAO;;;;;AAMT,SAAgB,cAAc,SAAgC;AAC5D,QAAO;EACL,SAAS;EACT,8BAAa,IAAI,MAAM,EAAC,aAAa;EACrC;EACA,WAAW,EAAE;EACb,SAAS,EAAE;EACX,QAAQ,EAAE;EACV,QAAQ,EAAE;EACV,aAAa,EAAE;EACf,OAAO;GACL,cAAc;GACd,gBAAgB;GAChB,cAAc;GACd,aAAa;GACb,aAAa;GACb,kBAAkB;GAClB,gBAAgB;GAChB,kBAAkB;GAClB,eAAe;GAChB;EACF"}
@@ -0,0 +1,90 @@
1
+ import { ConfidenceLevel, ConfidenceMeta, EndpointCandidate, ExtractOptions, ExtractResult, HttpMethod, ImportIR, OpKind, ProjectInfo, SchemaCandidate, SourceLocation } from "../types.js";
2
+ import { SourceExtractor } from "../registry.js";
3
+
4
+ //#region src/extractors/base.d.ts
5
+
6
+ /**
7
+ * File system adapter interface for extractors.
8
+ */
9
+ interface ExtractorFsAdapter {
10
+ readFile(path: string): Promise<string>;
11
+ glob(pattern: string, options?: {
12
+ cwd?: string;
13
+ }): Promise<string[]>;
14
+ exists(path: string): Promise<boolean>;
15
+ }
16
+ /**
17
+ * Context passed to extraction methods.
18
+ */
19
+ interface ExtractionContext {
20
+ project: ProjectInfo;
21
+ options: ExtractOptions;
22
+ fs: ExtractorFsAdapter;
23
+ ir: ImportIR;
24
+ }
25
+ /**
26
+ * Abstract base class for source extractors.
27
+ * Provides common utilities and structure for framework-specific extractors.
28
+ */
29
+ declare abstract class BaseExtractor implements SourceExtractor {
30
+ abstract id: string;
31
+ abstract name: string;
32
+ abstract frameworks: string[];
33
+ priority: number;
34
+ /**
35
+ * File system adapter - must be set before extraction.
36
+ */
37
+ protected fs?: ExtractorFsAdapter;
38
+ /**
39
+ * Set the file system adapter.
40
+ */
41
+ setFs(fs: ExtractorFsAdapter): void;
42
+ /**
43
+ * Detect if this extractor can handle the given project.
44
+ * Default implementation checks if any supported framework is detected.
45
+ */
46
+ detect(project: ProjectInfo): Promise<boolean>;
47
+ /**
48
+ * Main extraction method.
49
+ */
50
+ extract(project: ProjectInfo, options: ExtractOptions): Promise<ExtractResult>;
51
+ /**
52
+ * Implement this method in subclasses to perform actual extraction.
53
+ */
54
+ protected abstract doExtract(ctx: ExtractionContext): Promise<void>;
55
+ /**
56
+ * Calculate statistics for the IR.
57
+ */
58
+ protected calculateStats(ir: ImportIR): void;
59
+ /**
60
+ * Generate a unique ID for an endpoint.
61
+ */
62
+ protected generateEndpointId(method: HttpMethod, path: string, handlerName?: string): string;
63
+ /**
64
+ * Generate a unique ID for a schema.
65
+ */
66
+ protected generateSchemaId(name: string, file: string): string;
67
+ /**
68
+ * Determine operation kind from HTTP method.
69
+ */
70
+ protected methodToOpKind(method: HttpMethod): OpKind;
71
+ /**
72
+ * Create a source location object.
73
+ */
74
+ protected createLocation(file: string, startLine: number, endLine: number): SourceLocation;
75
+ /**
76
+ * Create confidence metadata.
77
+ */
78
+ protected createConfidence(level: ConfidenceLevel, ...reasons: ConfidenceMeta['reasons']): ConfidenceMeta;
79
+ /**
80
+ * Add an endpoint to the IR.
81
+ */
82
+ protected addEndpoint(ctx: ExtractionContext, endpoint: EndpointCandidate): void;
83
+ /**
84
+ * Add a schema to the IR.
85
+ */
86
+ protected addSchema(ctx: ExtractionContext, schema: SchemaCandidate): void;
87
+ }
88
+ //#endregion
89
+ export { BaseExtractor, ExtractionContext, ExtractorFsAdapter };
90
+ //# sourceMappingURL=base.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base.d.ts","names":[],"sources":["../../src/extractors/base.ts"],"sourcesContent":[],"mappings":";;;;;;;AAkCA;AACW,UAVM,kBAAA,CAUN;EACA,QAAA,CAAA,IAAA,EAAA,MAAA,CAAA,EAVe,OAUf,CAAA,MAAA,CAAA;EACL,IAAA,CAAA,OAAA,EAAA,MAAA,EAAA,OACQ,CADR,EAAA;IACA,GAAA,CAAA,EAAA,MAAA;EAAQ,CAAA,CAAA,EAXuC,OAWvC,CAAA,MAAA,EAAA,CAAA;EAOQ,MAAA,CAAA,IAAA,EAAA,MAAc,CAAA,EAjBZ,OAiBY,CAAA,OAAA,CAAA;;;;;AA8BvB,UAzCI,iBAAA,CAyCJ;EACA,OAAA,EAzCF,WAyCE;EACA,OAAA,EAzCF,cAyCE;EAAR,EAAA,EAxCC,kBAwCD;EA2C+B,EAAA,EAlF9B,QAkF8B;;;;;;AAyF/B,uBApKiB,aAAA,YAAyB,eAoK1C,CAAA;EAQM,SAAA,EAAA,EAAA,MAAA;EACK,SAAA,IAAA,EAAA,MAAA;EACX,SAAA,UAAA,EAAA,MAAA,EAAA;EAQI,QAAA,EAAA,MAAA;EACK;;;EAvLiC,UAAA,EAAA,CAAA,EAS9B,kBAT8B;EAAe;;;YAclD;;;;;kBAQY,cAAc;;;;mBAQzB,sBACA,iBACR,QAAQ;;;;oCA2CuB,oBAAoB;;;;+BAKzB;;;;uCAsCnB;;;;;;;;mCA4BuB,aAAa;;;;8EAkB3C;;;;oCAQM,6BACK,4BACX;;;;6BAQI,6BACK;;;;2BAQa,2BAA2B"}
@@ -0,0 +1,152 @@
1
+ import { createEmptyIR } from "../extract.js";
2
+
3
+ //#region src/extractors/base.ts
4
+ /**
5
+ * Abstract base class for source extractors.
6
+ * Provides common utilities and structure for framework-specific extractors.
7
+ */
8
+ var BaseExtractor = class {
9
+ priority = 10;
10
+ /**
11
+ * File system adapter - must be set before extraction.
12
+ */
13
+ fs;
14
+ /**
15
+ * Set the file system adapter.
16
+ */
17
+ setFs(fs) {
18
+ this.fs = fs;
19
+ }
20
+ /**
21
+ * Detect if this extractor can handle the given project.
22
+ * Default implementation checks if any supported framework is detected.
23
+ */
24
+ async detect(project) {
25
+ return project.frameworks.some((fw) => this.frameworks.includes(fw.id));
26
+ }
27
+ /**
28
+ * Main extraction method.
29
+ */
30
+ async extract(project, options) {
31
+ if (!this.fs) return {
32
+ success: false,
33
+ errors: [{
34
+ code: "NO_FS_ADAPTER",
35
+ message: "File system adapter not configured",
36
+ recoverable: false
37
+ }]
38
+ };
39
+ const ir = createEmptyIR(project);
40
+ const ctx = {
41
+ project,
42
+ options,
43
+ fs: this.fs,
44
+ ir
45
+ };
46
+ try {
47
+ await this.doExtract(ctx);
48
+ this.calculateStats(ir);
49
+ return {
50
+ success: true,
51
+ ir
52
+ };
53
+ } catch (error) {
54
+ return {
55
+ success: false,
56
+ errors: [{
57
+ code: "EXTRACTION_ERROR",
58
+ message: error instanceof Error ? error.message : String(error),
59
+ recoverable: false
60
+ }]
61
+ };
62
+ }
63
+ }
64
+ /**
65
+ * Calculate statistics for the IR.
66
+ */
67
+ calculateStats(ir) {
68
+ ir.stats.endpointsFound = ir.endpoints.length;
69
+ ir.stats.schemasFound = ir.schemas.length;
70
+ ir.stats.errorsFound = ir.errors.length;
71
+ ir.stats.eventsFound = ir.events.length;
72
+ ir.stats.ambiguitiesFound = ir.ambiguities.length;
73
+ const allItems = [
74
+ ...ir.endpoints,
75
+ ...ir.schemas,
76
+ ...ir.errors,
77
+ ...ir.events
78
+ ];
79
+ for (const item of allItems) switch (item.confidence.level) {
80
+ case "high":
81
+ ir.stats.highConfidence++;
82
+ break;
83
+ case "medium":
84
+ ir.stats.mediumConfidence++;
85
+ break;
86
+ case "low":
87
+ case "ambiguous":
88
+ ir.stats.lowConfidence++;
89
+ break;
90
+ }
91
+ }
92
+ /**
93
+ * Generate a unique ID for an endpoint.
94
+ */
95
+ generateEndpointId(method, path, handlerName) {
96
+ const pathPart = path.replace(/^\//, "").replace(/\//g, ".").replace(/:/g, "").replace(/\{/g, "").replace(/\}/g, "");
97
+ const base = `${method.toLowerCase()}.${pathPart}`;
98
+ return handlerName ? `${base}.${handlerName}` : base;
99
+ }
100
+ /**
101
+ * Generate a unique ID for a schema.
102
+ */
103
+ generateSchemaId(name, file) {
104
+ return `${file.replace(/\.ts$/, "").replace(/\//g, ".").replace(/^\.+/, "")}.${name}`;
105
+ }
106
+ /**
107
+ * Determine operation kind from HTTP method.
108
+ */
109
+ methodToOpKind(method) {
110
+ switch (method) {
111
+ case "GET":
112
+ case "HEAD":
113
+ case "OPTIONS": return "query";
114
+ default: return "command";
115
+ }
116
+ }
117
+ /**
118
+ * Create a source location object.
119
+ */
120
+ createLocation(file, startLine, endLine) {
121
+ return {
122
+ file,
123
+ startLine,
124
+ endLine
125
+ };
126
+ }
127
+ /**
128
+ * Create confidence metadata.
129
+ */
130
+ createConfidence(level, ...reasons) {
131
+ return {
132
+ level,
133
+ reasons
134
+ };
135
+ }
136
+ /**
137
+ * Add an endpoint to the IR.
138
+ */
139
+ addEndpoint(ctx, endpoint) {
140
+ ctx.ir.endpoints.push(endpoint);
141
+ }
142
+ /**
143
+ * Add a schema to the IR.
144
+ */
145
+ addSchema(ctx, schema) {
146
+ ctx.ir.schemas.push(schema);
147
+ }
148
+ };
149
+
150
+ //#endregion
151
+ export { BaseExtractor };
152
+ //# sourceMappingURL=base.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base.js","names":[],"sources":["../../src/extractors/base.ts"],"sourcesContent":["/**\n * Base extractor class.\n *\n * Provides common functionality for all framework extractors.\n */\n\nimport type { SourceExtractor } from '../registry';\nimport type {\n ConfidenceLevel,\n ConfidenceMeta,\n EndpointCandidate,\n ExtractOptions,\n ExtractResult,\n HttpMethod,\n ImportIR,\n OpKind,\n ProjectInfo,\n SchemaCandidate,\n SourceLocation,\n} from '../types';\nimport { createEmptyIR } from '../extract';\n\n/**\n * File system adapter interface for extractors.\n */\nexport interface ExtractorFsAdapter {\n readFile(path: string): Promise<string>;\n glob(pattern: string, options?: { cwd?: string }): Promise<string[]>;\n exists(path: string): Promise<boolean>;\n}\n\n/**\n * Context passed to extraction methods.\n */\nexport interface ExtractionContext {\n project: ProjectInfo;\n options: ExtractOptions;\n fs: ExtractorFsAdapter;\n ir: ImportIR;\n}\n\n/**\n * Abstract base class for source extractors.\n * Provides common utilities and structure for framework-specific extractors.\n */\nexport abstract class BaseExtractor implements SourceExtractor {\n abstract id: string;\n abstract name: string;\n abstract frameworks: string[];\n priority = 10;\n\n /**\n * File system adapter - must be set before extraction.\n */\n protected fs?: ExtractorFsAdapter;\n\n /**\n * Set the file system adapter.\n */\n setFs(fs: ExtractorFsAdapter): void {\n this.fs = fs;\n }\n\n /**\n * Detect if this extractor can handle the given project.\n * Default implementation checks if any supported framework is detected.\n */\n async detect(project: ProjectInfo): Promise<boolean> {\n return project.frameworks.some((fw) => this.frameworks.includes(fw.id));\n }\n\n /**\n * Main extraction method.\n */\n async extract(\n project: ProjectInfo,\n options: ExtractOptions\n ): Promise<ExtractResult> {\n if (!this.fs) {\n return {\n success: false,\n errors: [\n {\n code: 'NO_FS_ADAPTER',\n message: 'File system adapter not configured',\n recoverable: false,\n },\n ],\n };\n }\n\n const ir = createEmptyIR(project);\n const ctx: ExtractionContext = {\n project,\n options,\n fs: this.fs,\n ir,\n };\n\n try {\n await this.doExtract(ctx);\n this.calculateStats(ir);\n return { success: true, ir };\n } catch (error) {\n return {\n success: false,\n errors: [\n {\n code: 'EXTRACTION_ERROR',\n message: error instanceof Error ? error.message : String(error),\n recoverable: false,\n },\n ],\n };\n }\n }\n\n /**\n * Implement this method in subclasses to perform actual extraction.\n */\n protected abstract doExtract(ctx: ExtractionContext): Promise<void>;\n\n /**\n * Calculate statistics for the IR.\n */\n protected calculateStats(ir: ImportIR): void {\n ir.stats.endpointsFound = ir.endpoints.length;\n ir.stats.schemasFound = ir.schemas.length;\n ir.stats.errorsFound = ir.errors.length;\n ir.stats.eventsFound = ir.events.length;\n ir.stats.ambiguitiesFound = ir.ambiguities.length;\n\n const allItems = [\n ...ir.endpoints,\n ...ir.schemas,\n ...ir.errors,\n ...ir.events,\n ];\n\n for (const item of allItems) {\n switch (item.confidence.level) {\n case 'high':\n ir.stats.highConfidence++;\n break;\n case 'medium':\n ir.stats.mediumConfidence++;\n break;\n case 'low':\n case 'ambiguous':\n ir.stats.lowConfidence++;\n break;\n }\n }\n }\n\n // ───────────────────────────────────────────────────────────────────\n // Helper methods for subclasses\n // ───────────────────────────────────────────────────────────────────\n\n /**\n * Generate a unique ID for an endpoint.\n */\n protected generateEndpointId(\n method: HttpMethod,\n path: string,\n handlerName?: string\n ): string {\n const pathPart = path\n .replace(/^\\//, '')\n .replace(/\\//g, '.')\n .replace(/:/g, '')\n .replace(/\\{/g, '')\n .replace(/\\}/g, '');\n const base = `${method.toLowerCase()}.${pathPart}`;\n return handlerName ? `${base}.${handlerName}` : base;\n }\n\n /**\n * Generate a unique ID for a schema.\n */\n protected generateSchemaId(name: string, file: string): string {\n const filePart = file\n .replace(/\\.ts$/, '')\n .replace(/\\//g, '.')\n .replace(/^\\.+/, '');\n return `${filePart}.${name}`;\n }\n\n /**\n * Determine operation kind from HTTP method.\n */\n protected methodToOpKind(method: HttpMethod): OpKind {\n switch (method) {\n case 'GET':\n case 'HEAD':\n case 'OPTIONS':\n return 'query';\n default:\n return 'command';\n }\n }\n\n /**\n * Create a source location object.\n */\n protected createLocation(\n file: string,\n startLine: number,\n endLine: number\n ): SourceLocation {\n return { file, startLine, endLine };\n }\n\n /**\n * Create confidence metadata.\n */\n protected createConfidence(\n level: ConfidenceLevel,\n ...reasons: ConfidenceMeta['reasons']\n ): ConfidenceMeta {\n return { level, reasons };\n }\n\n /**\n * Add an endpoint to the IR.\n */\n protected addEndpoint(\n ctx: ExtractionContext,\n endpoint: EndpointCandidate\n ): void {\n ctx.ir.endpoints.push(endpoint);\n }\n\n /**\n * Add a schema to the IR.\n */\n protected addSchema(ctx: ExtractionContext, schema: SchemaCandidate): void {\n ctx.ir.schemas.push(schema);\n }\n}\n"],"mappings":";;;;;;;AA6CA,IAAsB,gBAAtB,MAA+D;CAI7D,WAAW;;;;CAKX,AAAU;;;;CAKV,MAAM,IAA8B;AAClC,OAAK,KAAK;;;;;;CAOZ,MAAM,OAAO,SAAwC;AACnD,SAAO,QAAQ,WAAW,MAAM,OAAO,KAAK,WAAW,SAAS,GAAG,GAAG,CAAC;;;;;CAMzE,MAAM,QACJ,SACA,SACwB;AACxB,MAAI,CAAC,KAAK,GACR,QAAO;GACL,SAAS;GACT,QAAQ,CACN;IACE,MAAM;IACN,SAAS;IACT,aAAa;IACd,CACF;GACF;EAGH,MAAM,KAAK,cAAc,QAAQ;EACjC,MAAM,MAAyB;GAC7B;GACA;GACA,IAAI,KAAK;GACT;GACD;AAED,MAAI;AACF,SAAM,KAAK,UAAU,IAAI;AACzB,QAAK,eAAe,GAAG;AACvB,UAAO;IAAE,SAAS;IAAM;IAAI;WACrB,OAAO;AACd,UAAO;IACL,SAAS;IACT,QAAQ,CACN;KACE,MAAM;KACN,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;KAC/D,aAAa;KACd,CACF;IACF;;;;;;CAYL,AAAU,eAAe,IAAoB;AAC3C,KAAG,MAAM,iBAAiB,GAAG,UAAU;AACvC,KAAG,MAAM,eAAe,GAAG,QAAQ;AACnC,KAAG,MAAM,cAAc,GAAG,OAAO;AACjC,KAAG,MAAM,cAAc,GAAG,OAAO;AACjC,KAAG,MAAM,mBAAmB,GAAG,YAAY;EAE3C,MAAM,WAAW;GACf,GAAG,GAAG;GACN,GAAG,GAAG;GACN,GAAG,GAAG;GACN,GAAG,GAAG;GACP;AAED,OAAK,MAAM,QAAQ,SACjB,SAAQ,KAAK,WAAW,OAAxB;GACE,KAAK;AACH,OAAG,MAAM;AACT;GACF,KAAK;AACH,OAAG,MAAM;AACT;GACF,KAAK;GACL,KAAK;AACH,OAAG,MAAM;AACT;;;;;;CAYR,AAAU,mBACR,QACA,MACA,aACQ;EACR,MAAM,WAAW,KACd,QAAQ,OAAO,GAAG,CAClB,QAAQ,OAAO,IAAI,CACnB,QAAQ,MAAM,GAAG,CACjB,QAAQ,OAAO,GAAG,CAClB,QAAQ,OAAO,GAAG;EACrB,MAAM,OAAO,GAAG,OAAO,aAAa,CAAC,GAAG;AACxC,SAAO,cAAc,GAAG,KAAK,GAAG,gBAAgB;;;;;CAMlD,AAAU,iBAAiB,MAAc,MAAsB;AAK7D,SAAO,GAJU,KACd,QAAQ,SAAS,GAAG,CACpB,QAAQ,OAAO,IAAI,CACnB,QAAQ,QAAQ,GAAG,CACH,GAAG;;;;;CAMxB,AAAU,eAAe,QAA4B;AACnD,UAAQ,QAAR;GACE,KAAK;GACL,KAAK;GACL,KAAK,UACH,QAAO;GACT,QACE,QAAO;;;;;;CAOb,AAAU,eACR,MACA,WACA,SACgB;AAChB,SAAO;GAAE;GAAM;GAAW;GAAS;;;;;CAMrC,AAAU,iBACR,OACA,GAAG,SACa;AAChB,SAAO;GAAE;GAAO;GAAS;;;;;CAM3B,AAAU,YACR,KACA,UACM;AACN,MAAI,GAAG,UAAU,KAAK,SAAS;;;;;CAMjC,AAAU,UAAU,KAAwB,QAA+B;AACzE,MAAI,GAAG,QAAQ,KAAK,OAAO"}
@@ -0,0 +1,15 @@
1
+ import { BaseExtractor, ExtractionContext } from "../base.js";
2
+
3
+ //#region src/extractors/elysia/extractor.d.ts
4
+
5
+ declare class ElysiaExtractor extends BaseExtractor {
6
+ id: string;
7
+ name: string;
8
+ frameworks: string[];
9
+ priority: number;
10
+ protected doExtract(ctx: ExtractionContext): Promise<void>;
11
+ private extractRoutes;
12
+ }
13
+ //#endregion
14
+ export { ElysiaExtractor };
15
+ //# sourceMappingURL=extractor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extractor.d.ts","names":[],"sources":["../../../src/extractors/elysia/extractor.ts"],"sourcesContent":[],"mappings":";;;;cAgBa,eAAA,SAAwB,aAAA;;;;;2BAMJ,oBAAoB"}