@flink-app/flink 0.14.3 → 2.0.0-alpha.100
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 +1051 -0
- package/SCHEMA_EXTRACTION_ANALYSIS.md +494 -0
- package/SIMPLE_AST_FEASIBILITY.md +570 -0
- package/bin/flink.ts +13 -2
- package/cli/build.ts +24 -44
- package/cli/clean.ts +13 -25
- package/cli/cli-utils.ts +190 -17
- package/cli/dev.ts +252 -0
- package/cli/loadEnvFiles.ts +116 -0
- package/cli/run.ts +45 -62
- package/dist/bin/flink.js +61 -2
- package/dist/cli/build.js +20 -25
- package/dist/cli/clean.js +12 -10
- package/dist/cli/cli-utils.d.ts +34 -3
- package/dist/cli/cli-utils.js +193 -12
- package/dist/cli/dev.d.ts +2 -0
- package/dist/cli/dev.js +279 -0
- package/dist/cli/loadEnvFiles.d.ts +30 -0
- package/dist/cli/loadEnvFiles.js +113 -0
- package/dist/cli/run.js +47 -46
- package/dist/src/DependencyTracker.d.ts +44 -0
- package/dist/src/DependencyTracker.js +239 -0
- package/dist/src/FlinkApp.d.ts +163 -10
- package/dist/src/FlinkApp.js +847 -184
- package/dist/src/FlinkContext.d.ts +41 -0
- package/dist/src/FlinkErrors.d.ts +19 -6
- package/dist/src/FlinkErrors.js +36 -42
- package/dist/src/FlinkHttpHandler.d.ts +219 -26
- package/dist/src/FlinkHttpHandler.js +37 -1
- package/dist/src/FlinkJob.d.ts +10 -0
- package/dist/src/FlinkLog.d.ts +82 -18
- package/dist/src/FlinkLog.js +165 -13
- package/dist/src/FlinkLogFactory.d.ts +288 -0
- package/dist/src/FlinkLogFactory.js +619 -0
- package/dist/src/FlinkRepo.d.ts +10 -2
- package/dist/src/FlinkRepo.js +11 -1
- package/dist/src/FlinkRequestContext.d.ts +63 -0
- package/dist/src/FlinkRequestContext.js +74 -0
- package/dist/src/FlinkResponse.d.ts +6 -0
- package/dist/src/FlinkService.d.ts +38 -0
- package/dist/src/FlinkService.js +46 -0
- package/dist/src/LeaderElection.d.ts +45 -0
- package/dist/src/LeaderElection.js +269 -0
- package/dist/src/SchemaCache.d.ts +84 -0
- package/dist/src/SchemaCache.js +289 -0
- package/dist/src/TypeScriptCompiler.d.ts +161 -51
- package/dist/src/TypeScriptCompiler.js +1253 -617
- package/dist/src/TypeScriptUtils.js +4 -0
- package/dist/src/ai/AgentRunner.d.ts +39 -0
- package/dist/src/ai/AgentRunner.js +760 -0
- package/dist/src/ai/ConversationAgent.d.ts +279 -0
- package/dist/src/ai/ConversationAgent.js +404 -0
- package/dist/src/ai/ConversationFlinkAgent.d.ts +278 -0
- package/dist/src/ai/ConversationFlinkAgent.js +404 -0
- package/dist/src/ai/FlinkAgent.d.ts +690 -0
- package/dist/src/ai/FlinkAgent.js +729 -0
- package/dist/src/ai/FlinkTool.d.ts +135 -0
- package/dist/src/ai/FlinkTool.js +2 -0
- package/dist/src/ai/InMemoryConversationAgent.d.ts +121 -0
- package/dist/src/ai/InMemoryConversationAgent.js +209 -0
- package/dist/src/ai/LLMAdapter.d.ts +148 -0
- package/dist/src/ai/LLMAdapter.js +2 -0
- package/dist/src/ai/PersistentFlinkAgent.d.ts +278 -0
- package/dist/src/ai/PersistentFlinkAgent.js +403 -0
- package/dist/src/ai/SubAgentExecutor.d.ts +38 -0
- package/dist/src/ai/SubAgentExecutor.js +223 -0
- package/dist/src/ai/ToolExecutor.d.ts +64 -0
- package/dist/src/ai/ToolExecutor.js +497 -0
- package/dist/src/ai/agentInstructions.d.ts +68 -0
- package/dist/src/ai/agentInstructions.js +286 -0
- package/dist/src/ai/index.d.ts +8 -0
- package/dist/src/ai/index.js +26 -0
- package/dist/src/ai/instructionFileLoader.d.ts +44 -0
- package/dist/src/ai/instructionFileLoader.js +179 -0
- package/dist/src/auth/FlinkAuthPlugin.d.ts +1 -1
- package/dist/src/handlers/StreamWriterFactory.d.ts +20 -0
- package/dist/src/handlers/StreamWriterFactory.js +83 -0
- package/dist/src/index.d.ts +14 -0
- package/dist/src/index.js +17 -0
- package/dist/src/loadPluginSchemas.d.ts +45 -0
- package/dist/src/loadPluginSchemas.js +143 -0
- package/dist/src/schema-extraction/ComplexTypeDetection.d.ts +40 -0
- package/dist/src/schema-extraction/ComplexTypeDetection.js +75 -0
- package/dist/src/schema-extraction/TypeScriptSourceParser.d.ts +321 -0
- package/dist/src/schema-extraction/TypeScriptSourceParser.js +925 -0
- package/dist/src/schema-extraction/TypeScriptSourceParser.spec.d.ts +1 -0
- package/dist/src/schema-extraction/TypeScriptSourceParser.spec.js +233 -0
- package/dist/src/schema-extraction/TypeScriptTokenizer.d.ts +57 -0
- package/dist/src/schema-extraction/TypeScriptTokenizer.js +177 -0
- package/dist/src/schema-extraction/index.d.ts +2 -0
- package/dist/src/schema-extraction/index.js +20 -0
- package/dist/src/schema-extraction/types.d.ts +31 -0
- package/dist/src/schema-extraction/types.js +2 -0
- package/dist/src/utils/loadFlinkConfig.d.ts +53 -0
- package/dist/src/utils/loadFlinkConfig.js +77 -0
- package/dist/src/utils.d.ts +30 -0
- package/dist/src/utils.js +52 -0
- package/dist/src/workers/SchemaGeneratorWorker.d.ts +1 -0
- package/dist/src/workers/SchemaGeneratorWorker.js +49 -0
- package/dist/src/workers/WorkerPool.d.ts +60 -0
- package/dist/src/workers/WorkerPool.js +306 -0
- package/examples/logging-hierarchical-example.ts +125 -0
- package/package.json +29 -4
- package/readme.md +499 -0
- package/spec/AgentDescendantDetection.spec.ts +335 -0
- package/spec/AgentDuplicateDetection.spec.ts +112 -0
- package/spec/AgentObserver.spec.ts +266 -0
- package/spec/AgentRunner.spec.ts +1062 -0
- package/spec/AsyncLocalStorageContext.spec.ts +223 -0
- package/spec/ConversationHooks.spec.ts +257 -0
- package/spec/FlinkAgent.spec.ts +681 -0
- package/spec/FlinkApp.htmlResponse.spec.ts +260 -0
- package/spec/FlinkApp.onError.invocation.spec.ts +151 -0
- package/spec/FlinkApp.onError.spec.ts +1 -2
- package/spec/FlinkApp.query.spec.ts +107 -0
- package/spec/FlinkApp.routeOrdering.spec.ts +61 -0
- package/spec/FlinkApp.undefinedResponse.spec.ts +123 -0
- package/spec/FlinkApp.validationMode.spec.ts +155 -0
- package/spec/FlinkJob.spec.ts +171 -0
- package/spec/FlinkLogFactory.spec.ts +337 -0
- package/spec/FlinkRepo.spec.ts +1 -1
- package/spec/LeaderElection.spec.ts +174 -0
- package/spec/StreamingIntegration.spec.ts +139 -0
- package/spec/ToolExecutor.spec.ts +465 -0
- package/spec/TypeScriptCompiler.spec.ts +1 -1
- package/spec/TypeScriptSourceParser.spec.ts +1215 -0
- package/spec/TypeScriptTokenizer.spec.ts +366 -0
- package/spec/ai/ContextCompaction.spec.ts +405 -0
- package/spec/ai/ConversationAgent.spec.ts +520 -0
- package/spec/ai/InMemoryConversationAgent.spec.ts +144 -0
- package/spec/ai/agentInstructions.spec.ts +358 -0
- package/spec/fixtures/agent-instructions/TestAgent.ts +24 -0
- package/spec/fixtures/agent-instructions/simple.md +3 -0
- package/spec/fixtures/agent-instructions/template.md +18 -0
- package/spec/fixtures/agent-instructions/yaml-format.yaml +9 -0
- package/spec/mock-project/dist/.tsbuildinfo +1 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/GetCar.js +56 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/GetCar2.js +58 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/GetCarWithArraySchema.js +52 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/GetCarWithArraySchema2.js +52 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/GetCarWithArraySchema3.js +52 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/GetCarWithLiteralSchema.js +54 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/GetCarWithLiteralSchema2.js +54 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/GetCarWithSchemaInFile.js +57 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/GetCarWithSchemaInFile2.js +57 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/ManuallyAddedHandler.js +53 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/ManuallyAddedHandler2.js +55 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/PatchCar.js +57 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/PatchOnboardingSession.js +75 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/PatchOrderWithComplexTypes.js +57 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/PatchProductWithIntersection.js +58 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/PatchUserWithUnion.js +58 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/PostCar.js +54 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/PostLogin.js +55 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/PostLogout.js +54 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/PutCar.js +54 -0
- package/spec/mock-project/dist/spec/mock-project/src/index.js +83 -0
- package/spec/mock-project/dist/spec/mock-project/src/repos/CarRepo.js +26 -0
- package/spec/mock-project/dist/spec/mock-project/src/schemas/Car.js +2 -0
- package/spec/mock-project/dist/spec/mock-project/src/schemas/DefaultExportSchema.js +2 -0
- package/spec/mock-project/dist/spec/mock-project/src/schemas/FileWithTwoSchemas.js +2 -0
- package/spec/mock-project/dist/src/FlinkApp.js +1000 -0
- package/spec/mock-project/dist/src/FlinkContext.js +2 -0
- package/spec/mock-project/dist/src/FlinkErrors.js +143 -0
- package/spec/mock-project/dist/src/FlinkHttpHandler.js +47 -0
- package/spec/mock-project/dist/src/FlinkJob.js +2 -0
- package/spec/mock-project/dist/src/FlinkLog.js +119 -0
- package/spec/mock-project/dist/src/FlinkLogFactory.js +617 -0
- package/spec/mock-project/dist/src/FlinkPlugin.js +2 -0
- package/spec/mock-project/dist/src/FlinkRepo.js +224 -0
- package/spec/mock-project/dist/src/FlinkRequestContext.js +74 -0
- package/spec/mock-project/dist/src/FlinkResponse.js +2 -0
- package/spec/mock-project/dist/src/ai/AgentExecutor.js +279 -0
- package/spec/mock-project/dist/src/ai/AgentRunner.js +632 -0
- package/spec/mock-project/dist/src/ai/ConversationAgent.js +402 -0
- package/spec/mock-project/dist/src/ai/ConversationFlinkAgent.js +422 -0
- package/spec/mock-project/dist/src/ai/FlinkAgent.js +699 -0
- package/spec/mock-project/dist/src/ai/FlinkTool.js +2 -0
- package/spec/mock-project/dist/src/ai/InMemoryConversationAgent.js +209 -0
- package/spec/mock-project/dist/src/ai/LLMAdapter.js +2 -0
- package/spec/mock-project/dist/src/ai/SubAgentExecutor.js +223 -0
- package/spec/mock-project/dist/src/ai/ToolExecutor.js +412 -0
- package/spec/mock-project/dist/src/ai/agentInstructions.js +246 -0
- package/spec/mock-project/dist/src/auth/FlinkAuthPlugin.js +2 -0
- package/spec/mock-project/dist/src/auth/FlinkAuthUser.js +2 -0
- package/spec/mock-project/dist/src/handlers/GetCar.js +26 -52
- package/spec/mock-project/dist/src/handlers/GetCar.js.map +1 -0
- package/spec/mock-project/dist/src/handlers/GetCar2.js +32 -54
- package/spec/mock-project/dist/src/handlers/GetCar2.js.map +1 -0
- package/spec/mock-project/dist/src/handlers/GetCarWithArraySchema.js +26 -48
- package/spec/mock-project/dist/src/handlers/GetCarWithArraySchema.js.map +1 -0
- package/spec/mock-project/dist/src/handlers/GetCarWithArraySchema2.js +28 -48
- package/spec/mock-project/dist/src/handlers/GetCarWithArraySchema2.js.map +1 -0
- package/spec/mock-project/dist/src/handlers/GetCarWithArraySchema3.js +29 -48
- package/spec/mock-project/dist/src/handlers/GetCarWithArraySchema3.js.map +1 -0
- package/spec/mock-project/dist/src/handlers/GetCarWithLiteralSchema.js +26 -50
- package/spec/mock-project/dist/src/handlers/GetCarWithLiteralSchema.js.map +1 -0
- package/spec/mock-project/dist/src/handlers/GetCarWithLiteralSchema2.js +28 -50
- package/spec/mock-project/dist/src/handlers/GetCarWithLiteralSchema2.js.map +1 -0
- package/spec/mock-project/dist/src/handlers/GetCarWithSchemaInFile.js +27 -53
- package/spec/mock-project/dist/src/handlers/GetCarWithSchemaInFile.js.map +1 -0
- package/spec/mock-project/dist/src/handlers/GetCarWithSchemaInFile2.js +29 -53
- package/spec/mock-project/dist/src/handlers/GetCarWithSchemaInFile2.js.map +1 -0
- package/spec/mock-project/dist/src/handlers/ManuallyAddedHandler.js +16 -49
- package/spec/mock-project/dist/src/handlers/ManuallyAddedHandler.js.map +1 -0
- package/spec/mock-project/dist/src/handlers/ManuallyAddedHandler2.js +25 -50
- package/spec/mock-project/dist/src/handlers/ManuallyAddedHandler2.js.map +1 -0
- package/spec/mock-project/dist/src/handlers/PatchCar.js +27 -53
- package/spec/mock-project/dist/src/handlers/PatchCar.js.map +1 -0
- package/spec/mock-project/dist/src/handlers/PatchOnboardingSession.js +44 -70
- package/spec/mock-project/dist/src/handlers/PatchOnboardingSession.js.map +1 -0
- package/spec/mock-project/dist/src/handlers/PatchOrderWithComplexTypes.js +27 -53
- package/spec/mock-project/dist/src/handlers/PatchOrderWithComplexTypes.js.map +1 -0
- package/spec/mock-project/dist/src/handlers/PatchProductWithIntersection.js +28 -54
- package/spec/mock-project/dist/src/handlers/PatchProductWithIntersection.js.map +1 -0
- package/spec/mock-project/dist/src/handlers/PatchUserWithUnion.js +28 -54
- package/spec/mock-project/dist/src/handlers/PatchUserWithUnion.js.map +1 -0
- package/spec/mock-project/dist/src/handlers/PostCar.js +24 -50
- package/spec/mock-project/dist/src/handlers/PostCar.js.map +1 -0
- package/spec/mock-project/dist/src/handlers/PostLogin.js +25 -51
- package/spec/mock-project/dist/src/handlers/PostLogin.js.map +1 -0
- package/spec/mock-project/dist/src/handlers/PostLogout.js +24 -50
- package/spec/mock-project/dist/src/handlers/PostLogout.js.map +1 -0
- package/spec/mock-project/dist/src/handlers/PutCar.js +24 -50
- package/spec/mock-project/dist/src/handlers/PutCar.js.map +1 -0
- package/spec/mock-project/dist/src/handlers/StreamWriterFactory.js +83 -0
- package/spec/mock-project/dist/src/index.js +52 -76
- package/spec/mock-project/dist/src/index.js.map +1 -0
- package/spec/mock-project/dist/src/mock-data-generator.js +9 -0
- package/spec/mock-project/dist/src/repos/CarRepo.js +12 -24
- package/spec/mock-project/dist/src/repos/CarRepo.js.map +1 -0
- package/spec/mock-project/dist/src/schemas/Car.js +3 -1
- package/spec/mock-project/dist/src/schemas/Car.js.map +1 -0
- package/spec/mock-project/dist/src/schemas/DefaultExportSchema.js +3 -1
- package/spec/mock-project/dist/src/schemas/DefaultExportSchema.js.map +1 -0
- package/spec/mock-project/dist/src/schemas/FileWithTwoSchemas.js +3 -1
- package/spec/mock-project/dist/src/schemas/FileWithTwoSchemas.js.map +1 -0
- package/spec/mock-project/dist/src/utils.js +290 -0
- package/spec/mock-project/tsconfig.json +6 -1
- package/spec/schema-generation-nested-objects.spec.ts +97 -0
- package/spec/testHelpers.ts +49 -0
- package/spec/utils.caseConversion.spec.ts +78 -0
- package/spec/utils.spec.ts +13 -13
- package/src/DependencyTracker.ts +166 -0
- package/src/FlinkApp.ts +919 -155
- package/src/FlinkContext.ts +43 -0
- package/src/FlinkErrors.ts +32 -12
- package/src/FlinkHttpHandler.ts +246 -28
- package/src/FlinkJob.ts +11 -0
- package/src/FlinkLog.ts +119 -12
- package/src/FlinkLogFactory.ts +699 -0
- package/src/FlinkRepo.ts +10 -3
- package/src/FlinkRequestContext.ts +95 -0
- package/src/FlinkResponse.ts +6 -0
- package/src/FlinkService.ts +49 -0
- package/src/LeaderElection.ts +203 -0
- package/src/SchemaCache.ts +232 -0
- package/src/TypeScriptCompiler.ts +1347 -610
- package/src/TypeScriptUtils.ts +5 -0
- package/src/ai/AgentRunner.ts +646 -0
- package/src/ai/ConversationAgent.ts +413 -0
- package/src/ai/FlinkAgent.ts +1069 -0
- package/src/ai/FlinkTool.ts +165 -0
- package/src/ai/InMemoryConversationAgent.ts +149 -0
- package/src/ai/LLMAdapter.ts +126 -0
- package/src/ai/ToolExecutor.ts +485 -0
- package/src/ai/agentInstructions.ts +245 -0
- package/src/ai/index.ts +8 -0
- package/src/ai/instructionFileLoader.ts +156 -0
- package/src/auth/FlinkAuthPlugin.ts +2 -1
- package/src/handlers/StreamWriterFactory.ts +84 -0
- package/src/index.ts +14 -0
- package/src/loadPluginSchemas.ts +141 -0
- package/src/schema-extraction/TypeScriptSourceParser.ts +1058 -0
- package/src/schema-extraction/TypeScriptTokenizer.ts +205 -0
- package/src/schema-extraction/index.ts +2 -0
- package/src/schema-extraction/types.ts +34 -0
- package/src/utils/loadFlinkConfig.ts +89 -0
- package/src/utils.ts +52 -0
- package/tsconfig.json +6 -1
|
@@ -0,0 +1,925 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TypeScriptSourceParser = void 0;
|
|
4
|
+
var TypeScriptTokenizer_1 = require("./TypeScriptTokenizer");
|
|
5
|
+
/**
|
|
6
|
+
* Pure utility class for parsing TypeScript source code as text.
|
|
7
|
+
* All methods are static and side-effect free for easy testing.
|
|
8
|
+
*
|
|
9
|
+
* This class provides fast, regex-based parsing without using ts-morph
|
|
10
|
+
* or the TypeScript compiler, making it suitable for performance-critical
|
|
11
|
+
* schema extraction.
|
|
12
|
+
*/
|
|
13
|
+
var TypeScriptSourceParser = /** @class */ (function () {
|
|
14
|
+
function TypeScriptSourceParser() {
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Remove comments from source code to avoid false positives in schema detection.
|
|
18
|
+
* Handles both single-line (//) and multi-line (/* *\/) comments.
|
|
19
|
+
*/
|
|
20
|
+
TypeScriptSourceParser.removeComments = function (sourceText) {
|
|
21
|
+
// Remove multi-line comments: /* ... */
|
|
22
|
+
var text = sourceText.replace(/\/\*[\s\S]*?\*\//g, '');
|
|
23
|
+
// Remove single-line comments: // ...
|
|
24
|
+
text = text.replace(/\/\/.*$/gm, '');
|
|
25
|
+
return text;
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Detect if a tool source file uses Zod or JSON schemas.
|
|
29
|
+
* If true, TypeScript schema extraction should be skipped.
|
|
30
|
+
*
|
|
31
|
+
* Note: Strips comments first to avoid false positives from commented-out schemas.
|
|
32
|
+
*/
|
|
33
|
+
TypeScriptSourceParser.detectSchemaType = function (sourceText) {
|
|
34
|
+
// Strip comments to avoid matching commented-out schema definitions
|
|
35
|
+
var textWithoutComments = this.removeComments(sourceText);
|
|
36
|
+
var hasZodSchemas = textWithoutComments.includes('inputSchema:') || textWithoutComments.includes('outputSchema:');
|
|
37
|
+
var hasJsonSchemas = textWithoutComments.includes('inputJsonSchema:') || textWithoutComments.includes('outputJsonSchema:');
|
|
38
|
+
return {
|
|
39
|
+
hasZodSchemas: hasZodSchemas,
|
|
40
|
+
hasJsonSchemas: hasJsonSchemas,
|
|
41
|
+
shouldSkipTypeScriptExtraction: hasZodSchemas || hasJsonSchemas,
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* Extract type arguments from Handler<Ctx, Req, Res, Params, Query> declaration.
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* ```typescript
|
|
49
|
+
* parseHandlerTypeArgs('const handler: Handler<AppCtx, LoginReq, LoginRes>')
|
|
50
|
+
* // Returns: { contextType: 'AppCtx', reqType: 'LoginReq', resType: 'LoginRes' }
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
TypeScriptSourceParser.parseHandlerTypeArgs = function (sourceText) {
|
|
54
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
55
|
+
// Try to find Handler< or GetHandler< or PostHandler< etc.
|
|
56
|
+
var handlerMatch = sourceText.match(/\b(Get|Post|Put|Patch|Delete)?Handler\s*</);
|
|
57
|
+
if (!handlerMatch) {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
var handlerType = handlerMatch[0].replace(/\s*<$/, '');
|
|
61
|
+
var startIdx = sourceText.indexOf(handlerMatch[0]);
|
|
62
|
+
if (startIdx === -1) {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
// Find the matching closing > by counting bracket depth
|
|
66
|
+
var depth = 0;
|
|
67
|
+
var endIdx = -1;
|
|
68
|
+
for (var i = startIdx + handlerMatch[0].length; i < sourceText.length; i++) {
|
|
69
|
+
if (sourceText[i] === '<') {
|
|
70
|
+
depth++;
|
|
71
|
+
}
|
|
72
|
+
else if (sourceText[i] === '>') {
|
|
73
|
+
if (depth === 0) {
|
|
74
|
+
endIdx = i;
|
|
75
|
+
break;
|
|
76
|
+
}
|
|
77
|
+
depth--;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
if (endIdx === -1) {
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
var typeArgsText = sourceText.slice(startIdx + handlerMatch[0].length, endIdx);
|
|
84
|
+
var typeArgs = this.splitTopLevelCommas(typeArgsText);
|
|
85
|
+
if (typeArgs.length === 0) {
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
// Handler<Ctx, Req, Res, Params, Query>
|
|
89
|
+
// GetHandler<Ctx, Res, Params, Query> (no Req)
|
|
90
|
+
// PostHandler<Ctx, Req, Res, Params, Query>
|
|
91
|
+
// etc.
|
|
92
|
+
var isGetHandler = handlerType === 'GetHandler';
|
|
93
|
+
if (isGetHandler) {
|
|
94
|
+
// GetHandler<Ctx, Res, Params, Query>
|
|
95
|
+
return {
|
|
96
|
+
contextType: (_a = typeArgs[0]) === null || _a === void 0 ? void 0 : _a.trim(),
|
|
97
|
+
resType: (_b = typeArgs[1]) === null || _b === void 0 ? void 0 : _b.trim(),
|
|
98
|
+
paramsType: (_c = typeArgs[2]) === null || _c === void 0 ? void 0 : _c.trim(),
|
|
99
|
+
queryType: (_d = typeArgs[3]) === null || _d === void 0 ? void 0 : _d.trim(),
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
// Handler<Ctx, Req, Res, Params, Query>
|
|
104
|
+
return {
|
|
105
|
+
contextType: (_e = typeArgs[0]) === null || _e === void 0 ? void 0 : _e.trim(),
|
|
106
|
+
reqType: (_f = typeArgs[1]) === null || _f === void 0 ? void 0 : _f.trim(),
|
|
107
|
+
resType: (_g = typeArgs[2]) === null || _g === void 0 ? void 0 : _g.trim(),
|
|
108
|
+
paramsType: (_h = typeArgs[3]) === null || _h === void 0 ? void 0 : _h.trim(),
|
|
109
|
+
queryType: (_j = typeArgs[4]) === null || _j === void 0 ? void 0 : _j.trim(),
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
/**
|
|
114
|
+
* Extract type arguments from FlinkTool<Ctx, Input, Output> declaration.
|
|
115
|
+
*
|
|
116
|
+
* @example
|
|
117
|
+
* ```typescript
|
|
118
|
+
* parseFlinkToolTypeArgs('const handler: FlinkTool<Ctx, CreateDocInput, ToolResult<DocOutput>>')
|
|
119
|
+
* // Returns: { contextType: 'Ctx', inputType: 'CreateDocInput', outputType: 'ToolResult<DocOutput>' }
|
|
120
|
+
* ```
|
|
121
|
+
*/
|
|
122
|
+
TypeScriptSourceParser.parseFlinkToolTypeArgs = function (sourceText) {
|
|
123
|
+
// Find FlinkTool< and then manually parse to find the matching closing >
|
|
124
|
+
var startIdx = sourceText.indexOf('FlinkTool<');
|
|
125
|
+
if (startIdx === -1) {
|
|
126
|
+
return null;
|
|
127
|
+
}
|
|
128
|
+
// Find the matching closing > by counting bracket depth
|
|
129
|
+
var depth = 0;
|
|
130
|
+
var endIdx = -1;
|
|
131
|
+
for (var i = startIdx + 'FlinkTool<'.length; i < sourceText.length; i++) {
|
|
132
|
+
if (sourceText[i] === '<') {
|
|
133
|
+
depth++;
|
|
134
|
+
}
|
|
135
|
+
else if (sourceText[i] === '>') {
|
|
136
|
+
if (depth === 0) {
|
|
137
|
+
endIdx = i;
|
|
138
|
+
break;
|
|
139
|
+
}
|
|
140
|
+
depth--;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
if (endIdx === -1) {
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
146
|
+
// Extract the content between the brackets
|
|
147
|
+
var typeArgsStr = sourceText.substring(startIdx + 'FlinkTool<'.length, endIdx);
|
|
148
|
+
// Parse the type arguments by splitting on commas at the top level (not inside angle brackets)
|
|
149
|
+
var typeArgs = this.splitTopLevelCommas(typeArgsStr);
|
|
150
|
+
if (typeArgs.length < 3) {
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
153
|
+
return {
|
|
154
|
+
contextType: typeArgs[0].trim(),
|
|
155
|
+
inputType: typeArgs[1].trim(),
|
|
156
|
+
outputType: typeArgs[2].trim(),
|
|
157
|
+
};
|
|
158
|
+
};
|
|
159
|
+
/**
|
|
160
|
+
* Split a string by commas, but only at the top level (not inside angle brackets).
|
|
161
|
+
* Helper for parsing generic type arguments like "Ctx, Input, ToolResult<Output>"
|
|
162
|
+
*/
|
|
163
|
+
TypeScriptSourceParser.splitTopLevelCommas = function (str) {
|
|
164
|
+
var result = [];
|
|
165
|
+
var current = '';
|
|
166
|
+
var depth = 0;
|
|
167
|
+
for (var _i = 0, str_1 = str; _i < str_1.length; _i++) {
|
|
168
|
+
var char = str_1[_i];
|
|
169
|
+
if (char === '<') {
|
|
170
|
+
depth++;
|
|
171
|
+
current += char;
|
|
172
|
+
}
|
|
173
|
+
else if (char === '>') {
|
|
174
|
+
depth--;
|
|
175
|
+
current += char;
|
|
176
|
+
}
|
|
177
|
+
else if (char === ',' && depth === 0) {
|
|
178
|
+
result.push(current);
|
|
179
|
+
current = '';
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
current += char;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
if (current) {
|
|
186
|
+
result.push(current);
|
|
187
|
+
}
|
|
188
|
+
return result;
|
|
189
|
+
};
|
|
190
|
+
/**
|
|
191
|
+
* Check if a type should generate a schema.
|
|
192
|
+
* Returns false for primitives and special types, true for named types and inline objects.
|
|
193
|
+
*/
|
|
194
|
+
TypeScriptSourceParser.shouldGenerateSchema = function (typeName) {
|
|
195
|
+
// Skip 'any' and 'unknown'
|
|
196
|
+
if (typeName === 'any' || typeName === 'unknown') {
|
|
197
|
+
return false;
|
|
198
|
+
}
|
|
199
|
+
// Generate schemas for inline object types like {} or { foo: string }
|
|
200
|
+
if (typeName.startsWith('{')) {
|
|
201
|
+
return true;
|
|
202
|
+
}
|
|
203
|
+
// Skip primitive types
|
|
204
|
+
var primitives = ['string', 'number', 'boolean', 'void', 'undefined', 'null'];
|
|
205
|
+
if (primitives.includes(typeName.toLowerCase())) {
|
|
206
|
+
return false;
|
|
207
|
+
}
|
|
208
|
+
// Skip binary/non-serializable built-in types that can never have JSON schemas
|
|
209
|
+
var nonSerializableTypes = ['Buffer', 'ArrayBuffer', 'SharedArrayBuffer', 'Blob', 'ReadableStream', 'WritableStream', 'DataView', 'Uint8Array'];
|
|
210
|
+
if (nonSerializableTypes.includes(typeName)) {
|
|
211
|
+
return false;
|
|
212
|
+
}
|
|
213
|
+
// Must be a named type (starts with uppercase letter)
|
|
214
|
+
return /^[A-Z]/.test(typeName);
|
|
215
|
+
};
|
|
216
|
+
/**
|
|
217
|
+
* Check if a type is a built-in TypeScript type.
|
|
218
|
+
*/
|
|
219
|
+
TypeScriptSourceParser.isBuiltInType = function (typeName) {
|
|
220
|
+
var builtIns = [
|
|
221
|
+
'String', 'Number', 'Boolean', 'Date', 'Array', 'Object', 'Record',
|
|
222
|
+
'Promise', 'Set', 'Map', 'Partial', 'Required', 'Pick', 'Omit',
|
|
223
|
+
'Readonly', 'ReadonlyArray'
|
|
224
|
+
];
|
|
225
|
+
return builtIns.includes(typeName);
|
|
226
|
+
};
|
|
227
|
+
/**
|
|
228
|
+
* Extract T from ToolResult<T> type name.
|
|
229
|
+
*
|
|
230
|
+
* @example
|
|
231
|
+
* ```typescript
|
|
232
|
+
* unwrapToolResultType('ToolResult<DocOutput>') // Returns: 'DocOutput'
|
|
233
|
+
* unwrapToolResultType('DocOutput') // Returns: 'DocOutput'
|
|
234
|
+
* ```
|
|
235
|
+
*/
|
|
236
|
+
TypeScriptSourceParser.unwrapToolResultType = function (typeName) {
|
|
237
|
+
var match = typeName.match(/ToolResult<(.+)>/);
|
|
238
|
+
if (match) {
|
|
239
|
+
return match[1].trim();
|
|
240
|
+
}
|
|
241
|
+
return typeName;
|
|
242
|
+
};
|
|
243
|
+
/**
|
|
244
|
+
* Convert inline object type to interface definition.
|
|
245
|
+
*
|
|
246
|
+
* @example
|
|
247
|
+
* ```typescript
|
|
248
|
+
* convertInlineObjectToInterface('{}', 'MyInput')
|
|
249
|
+
* // Returns: 'export interface MyInput {}'
|
|
250
|
+
*
|
|
251
|
+
* convertInlineObjectToInterface('{ foo: string }', 'MyInput')
|
|
252
|
+
* // Returns: 'export interface MyInput {\n foo: string;\n}'
|
|
253
|
+
* ```
|
|
254
|
+
*/
|
|
255
|
+
TypeScriptSourceParser.convertInlineObjectToInterface = function (inlineType, interfaceName) {
|
|
256
|
+
// For empty object, create empty interface
|
|
257
|
+
if (inlineType.trim() === '{}') {
|
|
258
|
+
return "export interface ".concat(interfaceName, " {}");
|
|
259
|
+
}
|
|
260
|
+
// For non-empty inline object, convert to interface
|
|
261
|
+
// Remove outer braces and clean up
|
|
262
|
+
var body = inlineType.trim().slice(1, -1).trim();
|
|
263
|
+
// Ensure properties end with semicolons (convert commas to semicolons if needed)
|
|
264
|
+
body = body.replace(/,\s*$/g, ';').replace(/([^;])\s*$/g, '$1;');
|
|
265
|
+
return "export interface ".concat(interfaceName, " {\n ").concat(body, "\n}");
|
|
266
|
+
};
|
|
267
|
+
/**
|
|
268
|
+
* Find an interface or type definition in source text.
|
|
269
|
+
*
|
|
270
|
+
* @example
|
|
271
|
+
* ```typescript
|
|
272
|
+
* const source = `
|
|
273
|
+
* interface User {
|
|
274
|
+
* name: string;
|
|
275
|
+
* }
|
|
276
|
+
* `;
|
|
277
|
+
* findTypeDefinition(source, 'User')
|
|
278
|
+
* // Returns: { name: 'User', definition: 'interface User { ... }', kind: 'interface' }
|
|
279
|
+
* ```
|
|
280
|
+
*/
|
|
281
|
+
TypeScriptSourceParser.findTypeDefinition = function (sourceText, typeName) {
|
|
282
|
+
// Skip if it's an inline type
|
|
283
|
+
if (typeName.startsWith('{')) {
|
|
284
|
+
return null;
|
|
285
|
+
}
|
|
286
|
+
// Try to find interface definition first
|
|
287
|
+
// Pattern: (optional JSDoc) interface Name (optional generics) (optional extends) { ... }
|
|
288
|
+
var interfacePattern = new RegExp("((?:\\/\\*\\*[\\s\\S]*?\\*\\/\\s*)?)interface\\s+".concat(typeName, "\\s*"), 'gm');
|
|
289
|
+
var interfaceMatch = interfacePattern.exec(sourceText);
|
|
290
|
+
if (interfaceMatch) {
|
|
291
|
+
var startIndex = interfaceMatch.index;
|
|
292
|
+
var jsDocAndInterface = interfaceMatch[0];
|
|
293
|
+
// Find the opening brace
|
|
294
|
+
var afterInterface = sourceText.slice(interfaceMatch.index + interfaceMatch[0].length);
|
|
295
|
+
var braceMatch = afterInterface.match(/^[^{]*\{/);
|
|
296
|
+
if (braceMatch) {
|
|
297
|
+
var braceStart = interfaceMatch.index + interfaceMatch[0].length + braceMatch[0].length - 1;
|
|
298
|
+
// Use tokenizer for robust bracket matching (handles strings and comments)
|
|
299
|
+
var tokenizer = new TypeScriptTokenizer_1.TypeScriptTokenizer(sourceText);
|
|
300
|
+
var braceEnd = tokenizer.findMatchingBracketAt(braceStart, '{');
|
|
301
|
+
if (braceEnd !== -1) {
|
|
302
|
+
var definition = sourceText.slice(startIndex, braceEnd + 1).trim();
|
|
303
|
+
return {
|
|
304
|
+
name: typeName,
|
|
305
|
+
definition: definition,
|
|
306
|
+
kind: 'interface',
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
// Match type alias: type Name = ...;
|
|
312
|
+
var typePattern = new RegExp("((?:\\/\\*\\*[\\s\\S]*?\\*\\/\\s*)?)type\\s+".concat(typeName, "\\s*=\\s*"), 'gm');
|
|
313
|
+
var typeMatch = typePattern.exec(sourceText);
|
|
314
|
+
if (typeMatch) {
|
|
315
|
+
var startIndex = typeMatch.index;
|
|
316
|
+
var afterEquals = typeMatch.index + typeMatch[0].length;
|
|
317
|
+
// Use tokenizer to find semicolon, properly handling strings and comments
|
|
318
|
+
var tokenizer = new TypeScriptTokenizer_1.TypeScriptTokenizer(sourceText);
|
|
319
|
+
var depth = 0;
|
|
320
|
+
var i = afterEquals;
|
|
321
|
+
while (i < sourceText.length) {
|
|
322
|
+
var token = tokenizer.getNextToken(i);
|
|
323
|
+
// Only process non-string, non-comment tokens
|
|
324
|
+
if (token.type !== 'string' && token.type !== 'comment') {
|
|
325
|
+
var char = token.value;
|
|
326
|
+
// Track depth
|
|
327
|
+
if (char === '{' || char === '[' || char === '(' || char === '<') {
|
|
328
|
+
depth++;
|
|
329
|
+
}
|
|
330
|
+
else if (char === '}' || char === ']' || char === ')' || char === '>') {
|
|
331
|
+
depth--;
|
|
332
|
+
// Closing a bracket back to top level may terminate a
|
|
333
|
+
// semicolon-free type alias (e.g. `type Params = { ... }`
|
|
334
|
+
// with no trailing `;`). Only stop if the type does not
|
|
335
|
+
// continue with an operator such as `|` or `&`.
|
|
336
|
+
if (depth === 0 && !this.typeContinuesAfter(sourceText, token.endPos)) {
|
|
337
|
+
var definition = sourceText.slice(startIndex, token.endPos).trim();
|
|
338
|
+
return {
|
|
339
|
+
name: typeName,
|
|
340
|
+
definition: definition,
|
|
341
|
+
kind: 'type',
|
|
342
|
+
};
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
// End of type at semicolon (at depth 0)
|
|
346
|
+
if (char === ';' && depth === 0) {
|
|
347
|
+
var definition = sourceText.slice(startIndex, i + 1).trim();
|
|
348
|
+
return {
|
|
349
|
+
name: typeName,
|
|
350
|
+
definition: definition,
|
|
351
|
+
kind: 'type',
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
i = token.endPos;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
return null;
|
|
359
|
+
};
|
|
360
|
+
/**
|
|
361
|
+
* Peek at the next non-whitespace, non-comment character starting at `fromPos`.
|
|
362
|
+
* Returns the character, or undefined if only whitespace/comments remain.
|
|
363
|
+
*/
|
|
364
|
+
TypeScriptSourceParser.peekNextSignificantChar = function (sourceText, fromPos) {
|
|
365
|
+
var tokenizer = new TypeScriptTokenizer_1.TypeScriptTokenizer(sourceText);
|
|
366
|
+
var i = fromPos;
|
|
367
|
+
while (i < sourceText.length) {
|
|
368
|
+
var token = tokenizer.getNextToken(i);
|
|
369
|
+
if (token.type === 'comment') {
|
|
370
|
+
i = token.endPos;
|
|
371
|
+
continue;
|
|
372
|
+
}
|
|
373
|
+
if (token.type === 'string') {
|
|
374
|
+
return token.value[0];
|
|
375
|
+
}
|
|
376
|
+
if (!/\s/.test(token.value)) {
|
|
377
|
+
return token.value;
|
|
378
|
+
}
|
|
379
|
+
i = token.endPos;
|
|
380
|
+
}
|
|
381
|
+
return undefined;
|
|
382
|
+
};
|
|
383
|
+
/**
|
|
384
|
+
* Determine whether a type expression continues after `fromPos`, i.e. whether
|
|
385
|
+
* the character that follows is a type-combinator/continuation operator
|
|
386
|
+
* (`|`, `&`, `[`, `.`, etc.) rather than the start of an unrelated statement.
|
|
387
|
+
*
|
|
388
|
+
* Used to decide if a top-level closing bracket terminates a semicolon-free
|
|
389
|
+
* type alias or whether the alias keeps going (e.g. a union of object types).
|
|
390
|
+
*/
|
|
391
|
+
TypeScriptSourceParser.typeContinuesAfter = function (sourceText, fromPos) {
|
|
392
|
+
var next = this.peekNextSignificantChar(sourceText, fromPos);
|
|
393
|
+
if (next === undefined) {
|
|
394
|
+
return false;
|
|
395
|
+
}
|
|
396
|
+
// Operators that mean the type expression continues across the boundary.
|
|
397
|
+
return '|&[.<'.includes(next);
|
|
398
|
+
};
|
|
399
|
+
/**
|
|
400
|
+
* Rename an interface or type definition.
|
|
401
|
+
*
|
|
402
|
+
* @example
|
|
403
|
+
* ```typescript
|
|
404
|
+
* renameTypeDefinition('interface User { name: string }', 'User', 'Person')
|
|
405
|
+
* // Returns: 'export interface Person { name: string }'
|
|
406
|
+
* ```
|
|
407
|
+
*/
|
|
408
|
+
TypeScriptSourceParser.renameTypeDefinition = function (definition, oldName, newName, exportIt) {
|
|
409
|
+
if (exportIt === void 0) { exportIt = true; }
|
|
410
|
+
var exportPrefix = exportIt ? 'export ' : '';
|
|
411
|
+
// Try interface rename
|
|
412
|
+
if (definition.includes('interface')) {
|
|
413
|
+
return definition.replace(new RegExp("interface\\s+".concat(oldName, "\\b")), "".concat(exportPrefix, "interface ").concat(newName));
|
|
414
|
+
}
|
|
415
|
+
// Try type alias rename
|
|
416
|
+
if (definition.includes('type')) {
|
|
417
|
+
return definition.replace(new RegExp("type\\s+".concat(oldName, "\\b")), "".concat(exportPrefix, "type ").concat(newName));
|
|
418
|
+
}
|
|
419
|
+
return definition;
|
|
420
|
+
};
|
|
421
|
+
/**
|
|
422
|
+
* Extract all type names referenced in a type definition.
|
|
423
|
+
* Excludes JSDoc comments and string literals.
|
|
424
|
+
*
|
|
425
|
+
* @example
|
|
426
|
+
* ```typescript
|
|
427
|
+
* extractReferencedTypes('interface Doc { author: User; tags: Tag[] }')
|
|
428
|
+
* // Returns: ['User', 'Tag']
|
|
429
|
+
* extractReferencedTypes('PaginatedResponse<Car>')
|
|
430
|
+
* // Returns: ['PaginatedResponse', 'Car']
|
|
431
|
+
* ```
|
|
432
|
+
*/
|
|
433
|
+
TypeScriptSourceParser.extractReferencedTypes = function (typeDefinition) {
|
|
434
|
+
var types = [];
|
|
435
|
+
// Remove JSDoc comments to avoid extracting type names from documentation
|
|
436
|
+
var withoutJsDoc = typeDefinition.replace(/\/\*\*[\s\S]*?\*\//g, '');
|
|
437
|
+
// Match type references in actual code
|
|
438
|
+
// Types appear after: : < Array< extends implements | &
|
|
439
|
+
// Also match standalone types (e.g., PaginatedResponse in "PaginatedResponse<Car>")
|
|
440
|
+
// But exclude types after "interface" or "type" keywords (those are definitions, not references)
|
|
441
|
+
var typeContextRegex = /(?<!interface\s)(?<!type\s)(?::\s*|<|Array<|extends\s+|implements\s+|\|\s*|&\s*)?([A-Z][a-zA-Z0-9_]*)/g;
|
|
442
|
+
var match;
|
|
443
|
+
while ((match = typeContextRegex.exec(withoutJsDoc)) !== null) {
|
|
444
|
+
var typeName = match[1];
|
|
445
|
+
// Skip if this looks like it's part of "interface Name" or "type Name"
|
|
446
|
+
var beforeMatch = withoutJsDoc.substring(Math.max(0, match.index - 15), match.index);
|
|
447
|
+
if (/\b(interface|type)\s*$/.test(beforeMatch)) {
|
|
448
|
+
continue;
|
|
449
|
+
}
|
|
450
|
+
// Filter out built-in types and duplicates
|
|
451
|
+
if (!this.isBuiltInType(typeName) && !types.includes(typeName)) {
|
|
452
|
+
types.push(typeName);
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
return types;
|
|
456
|
+
};
|
|
457
|
+
/**
|
|
458
|
+
* Check if a type name is an inline object type.
|
|
459
|
+
*/
|
|
460
|
+
TypeScriptSourceParser.isInlineObjectType = function (typeName) {
|
|
461
|
+
return typeName.trim().startsWith('{');
|
|
462
|
+
};
|
|
463
|
+
/**
|
|
464
|
+
* Parse JSDoc comment text to extract description.
|
|
465
|
+
* Strips JSDoc comment markers and leading asterisks.
|
|
466
|
+
*
|
|
467
|
+
* @example
|
|
468
|
+
* ```typescript
|
|
469
|
+
* parseJsDocDescription('/** Max cars to retrieve *\/')
|
|
470
|
+
* // Returns: "Max cars to retrieve"
|
|
471
|
+
*
|
|
472
|
+
* parseJsDocDescription('/**\n * Max cars to retrieve\n * from the database\n *\/')
|
|
473
|
+
* // Returns: "Max cars to retrieve from the database"
|
|
474
|
+
*
|
|
475
|
+
* parseJsDocDescription('')
|
|
476
|
+
* // Returns: ""
|
|
477
|
+
* ```
|
|
478
|
+
*/
|
|
479
|
+
TypeScriptSourceParser.parseJsDocDescription = function (jsDocText) {
|
|
480
|
+
if (!jsDocText) {
|
|
481
|
+
return '';
|
|
482
|
+
}
|
|
483
|
+
// Remove /** and */ markers
|
|
484
|
+
var cleaned = jsDocText.replace(/^\/\*\*/, '').replace(/\*\/$/, '');
|
|
485
|
+
// Remove leading * from each line
|
|
486
|
+
cleaned = cleaned
|
|
487
|
+
.split('\n')
|
|
488
|
+
.map(function (line) { return line.trim().replace(/^\*\s?/, ''); })
|
|
489
|
+
.filter(function (line) { return line.length > 0; })
|
|
490
|
+
.join(' ');
|
|
491
|
+
// Collapse multiple spaces into single space
|
|
492
|
+
cleaned = cleaned.replace(/\s+/g, ' ');
|
|
493
|
+
return cleaned.trim();
|
|
494
|
+
};
|
|
495
|
+
/**
|
|
496
|
+
* Extract property metadata from an object type body.
|
|
497
|
+
* Parses properties with optional JSDoc comments.
|
|
498
|
+
* Only extracts top-level properties (not nested object properties).
|
|
499
|
+
*
|
|
500
|
+
* @param objectBody The content between { and } in an object type
|
|
501
|
+
* @returns Array of property metadata (name + description)
|
|
502
|
+
*
|
|
503
|
+
* @example
|
|
504
|
+
* ```typescript
|
|
505
|
+
* const body = `
|
|
506
|
+
* /** Max cars to retrieve *\/
|
|
507
|
+
* limit: string;
|
|
508
|
+
* page?: number;
|
|
509
|
+
* `;
|
|
510
|
+
* extractPropertiesFromObjectType(body)
|
|
511
|
+
* // Returns: [
|
|
512
|
+
* // { name: "limit", description: "Max cars to retrieve" },
|
|
513
|
+
* // { name: "page", description: "" }
|
|
514
|
+
* // ]
|
|
515
|
+
* ```
|
|
516
|
+
*/
|
|
517
|
+
TypeScriptSourceParser.extractPropertiesFromObjectType = function (objectBody) {
|
|
518
|
+
var properties = [];
|
|
519
|
+
var i = 0;
|
|
520
|
+
while (i < objectBody.length) {
|
|
521
|
+
// Skip whitespace
|
|
522
|
+
while (i < objectBody.length && /\s/.test(objectBody[i])) {
|
|
523
|
+
i++;
|
|
524
|
+
}
|
|
525
|
+
if (i >= objectBody.length)
|
|
526
|
+
break;
|
|
527
|
+
// Check for JSDoc comment
|
|
528
|
+
var jsDoc = '';
|
|
529
|
+
if (objectBody[i] === '/' && i + 1 < objectBody.length && objectBody[i + 1] === '*' && i + 2 < objectBody.length && objectBody[i + 2] === '*') {
|
|
530
|
+
var endIndex = objectBody.indexOf('*/', i + 3);
|
|
531
|
+
if (endIndex !== -1) {
|
|
532
|
+
jsDoc = objectBody.slice(i, endIndex + 2);
|
|
533
|
+
i = endIndex + 2;
|
|
534
|
+
}
|
|
535
|
+
else {
|
|
536
|
+
break;
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
// Skip whitespace after JSDoc
|
|
540
|
+
while (i < objectBody.length && /\s/.test(objectBody[i])) {
|
|
541
|
+
i++;
|
|
542
|
+
}
|
|
543
|
+
if (i >= objectBody.length)
|
|
544
|
+
break;
|
|
545
|
+
// Extract property name
|
|
546
|
+
var propertyNameMatch = objectBody.slice(i).match(/^(\w+)\??:/);
|
|
547
|
+
if (!propertyNameMatch) {
|
|
548
|
+
i++;
|
|
549
|
+
continue;
|
|
550
|
+
}
|
|
551
|
+
var propertyName = propertyNameMatch[1];
|
|
552
|
+
i += propertyNameMatch[0].length;
|
|
553
|
+
// Skip the type until we hit a delimiter at top level (;, ,, or closing })
|
|
554
|
+
// Use tokenizer to properly handle strings and comments
|
|
555
|
+
var tokenizer = new TypeScriptTokenizer_1.TypeScriptTokenizer(objectBody);
|
|
556
|
+
var depth = 0;
|
|
557
|
+
while (i < objectBody.length) {
|
|
558
|
+
var token = tokenizer.getNextToken(i);
|
|
559
|
+
// Only process non-string, non-comment tokens
|
|
560
|
+
if (token.type !== 'string' && token.type !== 'comment') {
|
|
561
|
+
var char = token.value;
|
|
562
|
+
// Track depth for nested objects/arrays
|
|
563
|
+
if (char === '{' || char === '[' || char === '(') {
|
|
564
|
+
depth++;
|
|
565
|
+
}
|
|
566
|
+
else if (char === '}' || char === ']' || char === ')') {
|
|
567
|
+
depth--;
|
|
568
|
+
}
|
|
569
|
+
// End of property at top level
|
|
570
|
+
if (depth === 0 && (char === ';' || char === ',')) {
|
|
571
|
+
i = token.endPos; // Move past delimiter
|
|
572
|
+
break;
|
|
573
|
+
}
|
|
574
|
+
// End of property at a top-level newline when no `;`/`,`
|
|
575
|
+
// delimiter is used (semicolon-free style, issue #77). Only
|
|
576
|
+
// terminate when the next line starts a new member (an
|
|
577
|
+
// identifier, quoted key, or JSDoc) - not a continuation of
|
|
578
|
+
// the current type such as a leading `|` union arm.
|
|
579
|
+
if (depth === 0 && (char === '\n' || char === '\r')) {
|
|
580
|
+
var next = this.peekNextSignificantChar(objectBody, token.endPos);
|
|
581
|
+
if (next === undefined || /[A-Za-z_$"'/]/.test(next)) {
|
|
582
|
+
break; // Leave i at the newline; outer loop skips whitespace
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
i = token.endPos;
|
|
587
|
+
}
|
|
588
|
+
// Add property
|
|
589
|
+
var description = this.parseJsDocDescription(jsDoc);
|
|
590
|
+
properties.push({
|
|
591
|
+
name: propertyName,
|
|
592
|
+
description: description,
|
|
593
|
+
});
|
|
594
|
+
}
|
|
595
|
+
return properties;
|
|
596
|
+
};
|
|
597
|
+
/**
|
|
598
|
+
* Copy a type definition and recursively find all its dependencies.
|
|
599
|
+
* Returns structured data without side effects.
|
|
600
|
+
*
|
|
601
|
+
* @param sourceText Full source file text to search for types
|
|
602
|
+
* @param typeName Name of the type to copy
|
|
603
|
+
* @param newName New name for the type (use same name for dependencies)
|
|
604
|
+
* @param copiedTypes Set of already-copied type names to avoid duplication
|
|
605
|
+
* @returns Object containing the main definition, dependency definitions, and import statements
|
|
606
|
+
*
|
|
607
|
+
* @example
|
|
608
|
+
* ```typescript
|
|
609
|
+
* const source = `
|
|
610
|
+
* import { Address } from './Address';
|
|
611
|
+
* interface User {
|
|
612
|
+
* profile: Profile;
|
|
613
|
+
* address: Address;
|
|
614
|
+
* }
|
|
615
|
+
* interface Profile {
|
|
616
|
+
* name: string;
|
|
617
|
+
* }
|
|
618
|
+
* `;
|
|
619
|
+
* const result = copyTypeWithDependencies(source, 'User', 'UserSchema', new Set());
|
|
620
|
+
* // Returns: {
|
|
621
|
+
* // mainDefinition: 'export interface UserSchema { profile: Profile; address: Address; }',
|
|
622
|
+
* // dependencies: ['export interface Profile { name: string; }'],
|
|
623
|
+
* // imports: ['import { Address } from "./Address"'],
|
|
624
|
+
* // copiedTypes: Set(['User', 'Profile'])
|
|
625
|
+
* // }
|
|
626
|
+
* ```
|
|
627
|
+
*/
|
|
628
|
+
TypeScriptSourceParser.copyTypeWithDependencies = function (sourceText, typeName, newName, copiedTypes) {
|
|
629
|
+
var dependencies = [];
|
|
630
|
+
var imports = [];
|
|
631
|
+
// Handle inline object types specially
|
|
632
|
+
var mainDefinition = null;
|
|
633
|
+
if (this.isInlineObjectType(typeName)) {
|
|
634
|
+
mainDefinition = this.convertInlineObjectToInterface(typeName, newName);
|
|
635
|
+
}
|
|
636
|
+
else {
|
|
637
|
+
// Find and copy the main type from file
|
|
638
|
+
var found = this.findTypeDefinition(sourceText, typeName);
|
|
639
|
+
if (found) {
|
|
640
|
+
mainDefinition = this.renameTypeDefinition(found.definition, typeName, newName);
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
if (!mainDefinition) {
|
|
644
|
+
return { mainDefinition: null, dependencies: [], imports: [], copiedTypes: copiedTypes };
|
|
645
|
+
}
|
|
646
|
+
// Mark this type as copied
|
|
647
|
+
copiedTypes.add(typeName);
|
|
648
|
+
// Find all referenced types in the definition
|
|
649
|
+
var referencedTypes = this.extractReferencedTypes(mainDefinition);
|
|
650
|
+
// Recursively copy each referenced type (if not already copied)
|
|
651
|
+
for (var _i = 0, referencedTypes_1 = referencedTypes; _i < referencedTypes_1.length; _i++) {
|
|
652
|
+
var refType = referencedTypes_1[_i];
|
|
653
|
+
if (!copiedTypes.has(refType) && !this.isBuiltInType(refType)) {
|
|
654
|
+
// Check if this type is defined in the current file
|
|
655
|
+
var typeDef = this.findTypeDefinition(sourceText, refType);
|
|
656
|
+
if (typeDef) {
|
|
657
|
+
// Type is defined in same file - recursively copy it
|
|
658
|
+
var result = this.copyTypeWithDependencies(sourceText, refType, refType, copiedTypes);
|
|
659
|
+
if (result.mainDefinition) {
|
|
660
|
+
dependencies.push(result.mainDefinition);
|
|
661
|
+
}
|
|
662
|
+
dependencies.push.apply(dependencies, result.dependencies);
|
|
663
|
+
imports.push.apply(imports, result.imports);
|
|
664
|
+
}
|
|
665
|
+
else {
|
|
666
|
+
// Type is not in current file - must be imported
|
|
667
|
+
// Extract the import statement for it
|
|
668
|
+
var importStmt = this.extractImportForType(sourceText, refType);
|
|
669
|
+
if (importStmt && !imports.includes(importStmt)) {
|
|
670
|
+
imports.push(importStmt);
|
|
671
|
+
}
|
|
672
|
+
// Mark as copied to avoid trying to find it again
|
|
673
|
+
copiedTypes.add(refType);
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
return { mainDefinition: mainDefinition, dependencies: dependencies, imports: imports, copiedTypes: copiedTypes };
|
|
678
|
+
};
|
|
679
|
+
/**
|
|
680
|
+
* Extract import statement for a specific type from source text.
|
|
681
|
+
*
|
|
682
|
+
* @param sourceText Full source file text
|
|
683
|
+
* @param typeName Name of the type to find import for
|
|
684
|
+
* @returns Import statement or null if not found
|
|
685
|
+
*
|
|
686
|
+
* @example
|
|
687
|
+
* ```typescript
|
|
688
|
+
* const source = `
|
|
689
|
+
* import { User } from '../schemas/User';
|
|
690
|
+
* import type { Profile } from '../schemas/Profile';
|
|
691
|
+
* import Foo from '../schemas/Foo';
|
|
692
|
+
* `;
|
|
693
|
+
* extractImportForType(source, 'User')
|
|
694
|
+
* // Returns: "import { User } from '../schemas/User'"
|
|
695
|
+
*
|
|
696
|
+
* extractImportForType(source, 'Profile')
|
|
697
|
+
* // Returns: "import type { Profile } from '../schemas/Profile'"
|
|
698
|
+
*
|
|
699
|
+
* extractImportForType(source, 'Foo')
|
|
700
|
+
* // Returns: "import Foo from '../schemas/Foo'"
|
|
701
|
+
* ```
|
|
702
|
+
*/
|
|
703
|
+
TypeScriptSourceParser.extractImportForType = function (sourceText, typeName) {
|
|
704
|
+
// Supports: import Foo from '...' OR import { Foo } from '...'
|
|
705
|
+
// Also supports: import type Foo from '...' OR import type { Foo } from '...'
|
|
706
|
+
var importRegex = new RegExp("import\\s+(?:type\\s+)?(?:{[^}]*\\b".concat(typeName, "\\b[^}]*}|").concat(typeName, ")\\s+from\\s+(['\"][^'\"]+['\"])"), 'gm');
|
|
707
|
+
var match = importRegex.exec(sourceText);
|
|
708
|
+
if (match) {
|
|
709
|
+
return match[0];
|
|
710
|
+
}
|
|
711
|
+
return null;
|
|
712
|
+
};
|
|
713
|
+
/**
|
|
714
|
+
* Extract all imports from a source file.
|
|
715
|
+
* Used to get transitive dependencies when importing a type.
|
|
716
|
+
*
|
|
717
|
+
* @param sourceText Source code to extract imports from
|
|
718
|
+
* @returns Array of import statements
|
|
719
|
+
*/
|
|
720
|
+
TypeScriptSourceParser.extractAllImports = function (sourceText) {
|
|
721
|
+
var imports = [];
|
|
722
|
+
// Match all import statements (including type imports, named imports, default imports, namespace imports)
|
|
723
|
+
var importRegex = /import\s+(?:type\s+)?(?:{[^}]+}|\w+|(?:\*\s+as\s+\w+))\s+from\s+['"][^'"]+['"]/gm;
|
|
724
|
+
var match;
|
|
725
|
+
while ((match = importRegex.exec(sourceText)) !== null) {
|
|
726
|
+
imports.push(match[0]);
|
|
727
|
+
}
|
|
728
|
+
return imports;
|
|
729
|
+
};
|
|
730
|
+
/**
|
|
731
|
+
* Adjust import path to be relative to .flink/schemas/ directory.
|
|
732
|
+
*
|
|
733
|
+
* @param importStatement Original import statement
|
|
734
|
+
* @returns Adjusted import statement with corrected path
|
|
735
|
+
*
|
|
736
|
+
* @example
|
|
737
|
+
* ```typescript
|
|
738
|
+
* adjustImportPathForSchemas('import { User } from "../schemas/User"')
|
|
739
|
+
* // Returns: 'import { User } from "../../src/schemas/User"'
|
|
740
|
+
*
|
|
741
|
+
* adjustImportPathForSchemas('import Profile from "../../schemas/Profile"')
|
|
742
|
+
* // Returns: 'import Profile from "../../src/schemas/Profile"'
|
|
743
|
+
*
|
|
744
|
+
* adjustImportPathForSchemas('import { Req } from "../clients/SupermetricsClient"')
|
|
745
|
+
* // Returns: 'import { Req } from "../../src/clients/SupermetricsClient"'
|
|
746
|
+
*
|
|
747
|
+
* adjustImportPathForSchemas('import { Foo } from "@company/shared"')
|
|
748
|
+
* // Returns: 'import { Foo } from "@company/shared"' (unchanged - not relative)
|
|
749
|
+
* ```
|
|
750
|
+
*/
|
|
751
|
+
TypeScriptSourceParser.adjustImportPathForSchemas = function (importStatement) {
|
|
752
|
+
// schemas.ts is at: .flink/schemas/schemas.ts
|
|
753
|
+
// Handler imports can be from anywhere in src/ (handlers, schemas, clients, etc.)
|
|
754
|
+
// We need to adjust ALL relative imports to work from .flink/schemas/
|
|
755
|
+
// Extract the path from import statement
|
|
756
|
+
var pathMatch = importStatement.match(/from\s+(['"])([^'"]+)['"]/);
|
|
757
|
+
if (!pathMatch) {
|
|
758
|
+
return importStatement;
|
|
759
|
+
}
|
|
760
|
+
var quote = pathMatch[1];
|
|
761
|
+
var importPath = pathMatch[2];
|
|
762
|
+
// Skip non-relative imports (package imports like "@company/shared", "lodash")
|
|
763
|
+
if (!importPath.startsWith('./') && !importPath.startsWith('../')) {
|
|
764
|
+
return importStatement;
|
|
765
|
+
}
|
|
766
|
+
// For relative imports, we need to adjust the path to work from .flink/schemas/
|
|
767
|
+
// Original: from handler at src/handlers/foo/Bar.ts importing "../clients/Client"
|
|
768
|
+
// Resolves to: src/clients/Client
|
|
769
|
+
// From schemas.ts at .flink/schemas/schemas.ts, we need: "../../src/clients/Client"
|
|
770
|
+
// Extract the path after src/ directory
|
|
771
|
+
// Patterns we handle:
|
|
772
|
+
// - "../schemas/User" → "../../src/schemas/User"
|
|
773
|
+
// - "../../schemas/User" → "../../src/schemas/User"
|
|
774
|
+
// - "../clients/Client" → "../../src/clients/Client"
|
|
775
|
+
// - "../../types/Foo" → "../../src/types/Foo"
|
|
776
|
+
// Find the src directory marker in the path
|
|
777
|
+
var adjustedPath;
|
|
778
|
+
if (importPath.includes('/schemas/')) {
|
|
779
|
+
// Special case for schemas - extract everything after '/schemas/'
|
|
780
|
+
var schemasIndex = importPath.indexOf('/schemas/');
|
|
781
|
+
var pathAfterSchemas = importPath.substring(schemasIndex + '/schemas/'.length);
|
|
782
|
+
adjustedPath = "../../src/schemas/".concat(pathAfterSchemas);
|
|
783
|
+
}
|
|
784
|
+
else {
|
|
785
|
+
// General case: assume the import resolves to src/<something>
|
|
786
|
+
// Count the number of "../" to understand directory depth, then reconstruct
|
|
787
|
+
// For simplicity, we'll assume all imports from handlers resolve to src/*
|
|
788
|
+
// Pattern: any number of "../" optionally followed by "./" followed by a directory path
|
|
789
|
+
// Strip both "../" and "./" prefixes
|
|
790
|
+
var pathWithoutLeadingDots = importPath.replace(/^(\.\.\/)*/, '').replace(/^\.\//, '');
|
|
791
|
+
adjustedPath = "../../src/".concat(pathWithoutLeadingDots);
|
|
792
|
+
}
|
|
793
|
+
return importStatement.replace("from ".concat(quote).concat(importPath).concat(quote), "from ".concat(quote).concat(adjustedPath).concat(quote));
|
|
794
|
+
};
|
|
795
|
+
/**
|
|
796
|
+
* Extract property metadata from a named type definition.
|
|
797
|
+
* Searches for the type definition and parses its properties.
|
|
798
|
+
*
|
|
799
|
+
* @param sourceText Full source file text
|
|
800
|
+
* @param typeName Name of the type to extract properties from
|
|
801
|
+
* @returns Array of property metadata, or null if type not found
|
|
802
|
+
*
|
|
803
|
+
* @example
|
|
804
|
+
* ```typescript
|
|
805
|
+
* const source = `
|
|
806
|
+
* interface Query {
|
|
807
|
+
* /** Max items *\/
|
|
808
|
+
* limit: string;
|
|
809
|
+
* page?: number;
|
|
810
|
+
* }
|
|
811
|
+
* `;
|
|
812
|
+
* extractPropertyMetadata(source, 'Query')
|
|
813
|
+
* // Returns: [
|
|
814
|
+
* // { name: "limit", description: "Max items" },
|
|
815
|
+
* // { name: "page", description: "" }
|
|
816
|
+
* // ]
|
|
817
|
+
* ```
|
|
818
|
+
*/
|
|
819
|
+
TypeScriptSourceParser.extractPropertyMetadata = function (sourceText, typeName) {
|
|
820
|
+
// Find the type definition
|
|
821
|
+
var typeDef = this.findTypeDefinition(sourceText, typeName);
|
|
822
|
+
if (!typeDef) {
|
|
823
|
+
return null;
|
|
824
|
+
}
|
|
825
|
+
// Extract the object body (content between { and })
|
|
826
|
+
var definition = typeDef.definition;
|
|
827
|
+
// Find the opening brace
|
|
828
|
+
var openBraceIndex = definition.indexOf('{');
|
|
829
|
+
if (openBraceIndex === -1) {
|
|
830
|
+
return null;
|
|
831
|
+
}
|
|
832
|
+
// Use tokenizer to find the matching closing brace (handles strings and comments)
|
|
833
|
+
var tokenizer = new TypeScriptTokenizer_1.TypeScriptTokenizer(definition);
|
|
834
|
+
var closeBraceIndex = tokenizer.findMatchingBracketAt(openBraceIndex, '{');
|
|
835
|
+
if (closeBraceIndex === -1) {
|
|
836
|
+
return null;
|
|
837
|
+
}
|
|
838
|
+
// Extract the object body (excluding the outer braces)
|
|
839
|
+
var objectBody = definition.slice(openBraceIndex + 1, closeBraceIndex);
|
|
840
|
+
return this.extractPropertiesFromObjectType(objectBody);
|
|
841
|
+
};
|
|
842
|
+
/**
|
|
843
|
+
* Consolidates duplicate imports from the same module.
|
|
844
|
+
* Merges named imports and preserves default imports.
|
|
845
|
+
*
|
|
846
|
+
* @param imports Array of import statements
|
|
847
|
+
* @returns Consolidated import statements with duplicates merged
|
|
848
|
+
*
|
|
849
|
+
* @example
|
|
850
|
+
* ```typescript
|
|
851
|
+
* const imports = [
|
|
852
|
+
* 'import { Ad } from "../../src/schemas/Ad"',
|
|
853
|
+
* 'import { AdStatus } from "../../src/schemas/Ad"',
|
|
854
|
+
* 'import { User } from "../../src/schemas/User"'
|
|
855
|
+
* ];
|
|
856
|
+
* consolidateImports(imports)
|
|
857
|
+
* // Returns: [
|
|
858
|
+
* // 'import { Ad, AdStatus } from "../../src/schemas/Ad"',
|
|
859
|
+
* // 'import { User } from "../../src/schemas/User"'
|
|
860
|
+
* // ]
|
|
861
|
+
* ```
|
|
862
|
+
*/
|
|
863
|
+
TypeScriptSourceParser.consolidateImports = function (imports) {
|
|
864
|
+
// Map: module path -> { namedImports: Set<string>, defaultImport?: string }
|
|
865
|
+
var importMap = new Map();
|
|
866
|
+
var _loop_1 = function (importStmt) {
|
|
867
|
+
// Parse import statement to extract module path and imports
|
|
868
|
+
// Patterns:
|
|
869
|
+
// - import { Foo, Bar } from "path"
|
|
870
|
+
// - import type { Foo, Bar } from "path"
|
|
871
|
+
// - import Foo from "path"
|
|
872
|
+
// - import type Foo from "path"
|
|
873
|
+
var namedMatch = importStmt.match(/import\s+(?:type\s+)?\{([^}]+)\}\s+from\s+(['"])([^'"]+)['"]/);
|
|
874
|
+
var defaultMatch = importStmt.match(/import\s+(?:type\s+)?(\w+)\s+from\s+(['"])([^'"]+)['"]/);
|
|
875
|
+
if (namedMatch) {
|
|
876
|
+
var namedImports = namedMatch[1]
|
|
877
|
+
.split(',')
|
|
878
|
+
.map(function (s) { return s.trim(); })
|
|
879
|
+
.filter(function (s) { return s.length > 0; });
|
|
880
|
+
var modulePath = namedMatch[3];
|
|
881
|
+
if (!importMap.has(modulePath)) {
|
|
882
|
+
importMap.set(modulePath, { namedImports: new Set() });
|
|
883
|
+
}
|
|
884
|
+
var entry_1 = importMap.get(modulePath);
|
|
885
|
+
namedImports.forEach(function (name) { return entry_1.namedImports.add(name); });
|
|
886
|
+
}
|
|
887
|
+
else if (defaultMatch) {
|
|
888
|
+
var defaultImport = defaultMatch[1];
|
|
889
|
+
var modulePath = defaultMatch[3];
|
|
890
|
+
if (!importMap.has(modulePath)) {
|
|
891
|
+
importMap.set(modulePath, { namedImports: new Set() });
|
|
892
|
+
}
|
|
893
|
+
var entry = importMap.get(modulePath);
|
|
894
|
+
entry.defaultImport = defaultImport;
|
|
895
|
+
}
|
|
896
|
+
};
|
|
897
|
+
for (var _i = 0, imports_1 = imports; _i < imports_1.length; _i++) {
|
|
898
|
+
var importStmt = imports_1[_i];
|
|
899
|
+
_loop_1(importStmt);
|
|
900
|
+
}
|
|
901
|
+
// Generate consolidated import statements
|
|
902
|
+
var consolidated = [];
|
|
903
|
+
var entries = Array.from(importMap.entries());
|
|
904
|
+
for (var _a = 0, entries_1 = entries; _a < entries_1.length; _a++) {
|
|
905
|
+
var _b = entries_1[_a], modulePath = _b[0], _c = _b[1], namedImports = _c.namedImports, defaultImport = _c.defaultImport;
|
|
906
|
+
if (defaultImport && namedImports.size > 0) {
|
|
907
|
+
// Both default and named imports
|
|
908
|
+
var named = Array.from(namedImports).sort().join(', ');
|
|
909
|
+
consolidated.push("import ".concat(defaultImport, ", { ").concat(named, " } from \"").concat(modulePath, "\""));
|
|
910
|
+
}
|
|
911
|
+
else if (defaultImport) {
|
|
912
|
+
// Default import only
|
|
913
|
+
consolidated.push("import ".concat(defaultImport, " from \"").concat(modulePath, "\""));
|
|
914
|
+
}
|
|
915
|
+
else if (namedImports.size > 0) {
|
|
916
|
+
// Named imports only
|
|
917
|
+
var named = Array.from(namedImports).sort().join(', ');
|
|
918
|
+
consolidated.push("import { ".concat(named, " } from \"").concat(modulePath, "\""));
|
|
919
|
+
}
|
|
920
|
+
}
|
|
921
|
+
return consolidated;
|
|
922
|
+
};
|
|
923
|
+
return TypeScriptSourceParser;
|
|
924
|
+
}());
|
|
925
|
+
exports.TypeScriptSourceParser = TypeScriptSourceParser;
|