@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.
Files changed (280) hide show
  1. package/CHANGELOG.md +1051 -0
  2. package/SCHEMA_EXTRACTION_ANALYSIS.md +494 -0
  3. package/SIMPLE_AST_FEASIBILITY.md +570 -0
  4. package/bin/flink.ts +13 -2
  5. package/cli/build.ts +24 -44
  6. package/cli/clean.ts +13 -25
  7. package/cli/cli-utils.ts +190 -17
  8. package/cli/dev.ts +252 -0
  9. package/cli/loadEnvFiles.ts +116 -0
  10. package/cli/run.ts +45 -62
  11. package/dist/bin/flink.js +61 -2
  12. package/dist/cli/build.js +20 -25
  13. package/dist/cli/clean.js +12 -10
  14. package/dist/cli/cli-utils.d.ts +34 -3
  15. package/dist/cli/cli-utils.js +193 -12
  16. package/dist/cli/dev.d.ts +2 -0
  17. package/dist/cli/dev.js +279 -0
  18. package/dist/cli/loadEnvFiles.d.ts +30 -0
  19. package/dist/cli/loadEnvFiles.js +113 -0
  20. package/dist/cli/run.js +47 -46
  21. package/dist/src/DependencyTracker.d.ts +44 -0
  22. package/dist/src/DependencyTracker.js +239 -0
  23. package/dist/src/FlinkApp.d.ts +163 -10
  24. package/dist/src/FlinkApp.js +847 -184
  25. package/dist/src/FlinkContext.d.ts +41 -0
  26. package/dist/src/FlinkErrors.d.ts +19 -6
  27. package/dist/src/FlinkErrors.js +36 -42
  28. package/dist/src/FlinkHttpHandler.d.ts +219 -26
  29. package/dist/src/FlinkHttpHandler.js +37 -1
  30. package/dist/src/FlinkJob.d.ts +10 -0
  31. package/dist/src/FlinkLog.d.ts +82 -18
  32. package/dist/src/FlinkLog.js +165 -13
  33. package/dist/src/FlinkLogFactory.d.ts +288 -0
  34. package/dist/src/FlinkLogFactory.js +619 -0
  35. package/dist/src/FlinkRepo.d.ts +10 -2
  36. package/dist/src/FlinkRepo.js +11 -1
  37. package/dist/src/FlinkRequestContext.d.ts +63 -0
  38. package/dist/src/FlinkRequestContext.js +74 -0
  39. package/dist/src/FlinkResponse.d.ts +6 -0
  40. package/dist/src/FlinkService.d.ts +38 -0
  41. package/dist/src/FlinkService.js +46 -0
  42. package/dist/src/LeaderElection.d.ts +45 -0
  43. package/dist/src/LeaderElection.js +269 -0
  44. package/dist/src/SchemaCache.d.ts +84 -0
  45. package/dist/src/SchemaCache.js +289 -0
  46. package/dist/src/TypeScriptCompiler.d.ts +161 -51
  47. package/dist/src/TypeScriptCompiler.js +1253 -617
  48. package/dist/src/TypeScriptUtils.js +4 -0
  49. package/dist/src/ai/AgentRunner.d.ts +39 -0
  50. package/dist/src/ai/AgentRunner.js +760 -0
  51. package/dist/src/ai/ConversationAgent.d.ts +279 -0
  52. package/dist/src/ai/ConversationAgent.js +404 -0
  53. package/dist/src/ai/ConversationFlinkAgent.d.ts +278 -0
  54. package/dist/src/ai/ConversationFlinkAgent.js +404 -0
  55. package/dist/src/ai/FlinkAgent.d.ts +690 -0
  56. package/dist/src/ai/FlinkAgent.js +729 -0
  57. package/dist/src/ai/FlinkTool.d.ts +135 -0
  58. package/dist/src/ai/FlinkTool.js +2 -0
  59. package/dist/src/ai/InMemoryConversationAgent.d.ts +121 -0
  60. package/dist/src/ai/InMemoryConversationAgent.js +209 -0
  61. package/dist/src/ai/LLMAdapter.d.ts +148 -0
  62. package/dist/src/ai/LLMAdapter.js +2 -0
  63. package/dist/src/ai/PersistentFlinkAgent.d.ts +278 -0
  64. package/dist/src/ai/PersistentFlinkAgent.js +403 -0
  65. package/dist/src/ai/SubAgentExecutor.d.ts +38 -0
  66. package/dist/src/ai/SubAgentExecutor.js +223 -0
  67. package/dist/src/ai/ToolExecutor.d.ts +64 -0
  68. package/dist/src/ai/ToolExecutor.js +497 -0
  69. package/dist/src/ai/agentInstructions.d.ts +68 -0
  70. package/dist/src/ai/agentInstructions.js +286 -0
  71. package/dist/src/ai/index.d.ts +8 -0
  72. package/dist/src/ai/index.js +26 -0
  73. package/dist/src/ai/instructionFileLoader.d.ts +44 -0
  74. package/dist/src/ai/instructionFileLoader.js +179 -0
  75. package/dist/src/auth/FlinkAuthPlugin.d.ts +1 -1
  76. package/dist/src/handlers/StreamWriterFactory.d.ts +20 -0
  77. package/dist/src/handlers/StreamWriterFactory.js +83 -0
  78. package/dist/src/index.d.ts +14 -0
  79. package/dist/src/index.js +17 -0
  80. package/dist/src/loadPluginSchemas.d.ts +45 -0
  81. package/dist/src/loadPluginSchemas.js +143 -0
  82. package/dist/src/schema-extraction/ComplexTypeDetection.d.ts +40 -0
  83. package/dist/src/schema-extraction/ComplexTypeDetection.js +75 -0
  84. package/dist/src/schema-extraction/TypeScriptSourceParser.d.ts +321 -0
  85. package/dist/src/schema-extraction/TypeScriptSourceParser.js +925 -0
  86. package/dist/src/schema-extraction/TypeScriptSourceParser.spec.d.ts +1 -0
  87. package/dist/src/schema-extraction/TypeScriptSourceParser.spec.js +233 -0
  88. package/dist/src/schema-extraction/TypeScriptTokenizer.d.ts +57 -0
  89. package/dist/src/schema-extraction/TypeScriptTokenizer.js +177 -0
  90. package/dist/src/schema-extraction/index.d.ts +2 -0
  91. package/dist/src/schema-extraction/index.js +20 -0
  92. package/dist/src/schema-extraction/types.d.ts +31 -0
  93. package/dist/src/schema-extraction/types.js +2 -0
  94. package/dist/src/utils/loadFlinkConfig.d.ts +53 -0
  95. package/dist/src/utils/loadFlinkConfig.js +77 -0
  96. package/dist/src/utils.d.ts +30 -0
  97. package/dist/src/utils.js +52 -0
  98. package/dist/src/workers/SchemaGeneratorWorker.d.ts +1 -0
  99. package/dist/src/workers/SchemaGeneratorWorker.js +49 -0
  100. package/dist/src/workers/WorkerPool.d.ts +60 -0
  101. package/dist/src/workers/WorkerPool.js +306 -0
  102. package/examples/logging-hierarchical-example.ts +125 -0
  103. package/package.json +29 -4
  104. package/readme.md +499 -0
  105. package/spec/AgentDescendantDetection.spec.ts +335 -0
  106. package/spec/AgentDuplicateDetection.spec.ts +112 -0
  107. package/spec/AgentObserver.spec.ts +266 -0
  108. package/spec/AgentRunner.spec.ts +1062 -0
  109. package/spec/AsyncLocalStorageContext.spec.ts +223 -0
  110. package/spec/ConversationHooks.spec.ts +257 -0
  111. package/spec/FlinkAgent.spec.ts +681 -0
  112. package/spec/FlinkApp.htmlResponse.spec.ts +260 -0
  113. package/spec/FlinkApp.onError.invocation.spec.ts +151 -0
  114. package/spec/FlinkApp.onError.spec.ts +1 -2
  115. package/spec/FlinkApp.query.spec.ts +107 -0
  116. package/spec/FlinkApp.routeOrdering.spec.ts +61 -0
  117. package/spec/FlinkApp.undefinedResponse.spec.ts +123 -0
  118. package/spec/FlinkApp.validationMode.spec.ts +155 -0
  119. package/spec/FlinkJob.spec.ts +171 -0
  120. package/spec/FlinkLogFactory.spec.ts +337 -0
  121. package/spec/FlinkRepo.spec.ts +1 -1
  122. package/spec/LeaderElection.spec.ts +174 -0
  123. package/spec/StreamingIntegration.spec.ts +139 -0
  124. package/spec/ToolExecutor.spec.ts +465 -0
  125. package/spec/TypeScriptCompiler.spec.ts +1 -1
  126. package/spec/TypeScriptSourceParser.spec.ts +1215 -0
  127. package/spec/TypeScriptTokenizer.spec.ts +366 -0
  128. package/spec/ai/ContextCompaction.spec.ts +405 -0
  129. package/spec/ai/ConversationAgent.spec.ts +520 -0
  130. package/spec/ai/InMemoryConversationAgent.spec.ts +144 -0
  131. package/spec/ai/agentInstructions.spec.ts +358 -0
  132. package/spec/fixtures/agent-instructions/TestAgent.ts +24 -0
  133. package/spec/fixtures/agent-instructions/simple.md +3 -0
  134. package/spec/fixtures/agent-instructions/template.md +18 -0
  135. package/spec/fixtures/agent-instructions/yaml-format.yaml +9 -0
  136. package/spec/mock-project/dist/.tsbuildinfo +1 -0
  137. package/spec/mock-project/dist/spec/mock-project/src/handlers/GetCar.js +56 -0
  138. package/spec/mock-project/dist/spec/mock-project/src/handlers/GetCar2.js +58 -0
  139. package/spec/mock-project/dist/spec/mock-project/src/handlers/GetCarWithArraySchema.js +52 -0
  140. package/spec/mock-project/dist/spec/mock-project/src/handlers/GetCarWithArraySchema2.js +52 -0
  141. package/spec/mock-project/dist/spec/mock-project/src/handlers/GetCarWithArraySchema3.js +52 -0
  142. package/spec/mock-project/dist/spec/mock-project/src/handlers/GetCarWithLiteralSchema.js +54 -0
  143. package/spec/mock-project/dist/spec/mock-project/src/handlers/GetCarWithLiteralSchema2.js +54 -0
  144. package/spec/mock-project/dist/spec/mock-project/src/handlers/GetCarWithSchemaInFile.js +57 -0
  145. package/spec/mock-project/dist/spec/mock-project/src/handlers/GetCarWithSchemaInFile2.js +57 -0
  146. package/spec/mock-project/dist/spec/mock-project/src/handlers/ManuallyAddedHandler.js +53 -0
  147. package/spec/mock-project/dist/spec/mock-project/src/handlers/ManuallyAddedHandler2.js +55 -0
  148. package/spec/mock-project/dist/spec/mock-project/src/handlers/PatchCar.js +57 -0
  149. package/spec/mock-project/dist/spec/mock-project/src/handlers/PatchOnboardingSession.js +75 -0
  150. package/spec/mock-project/dist/spec/mock-project/src/handlers/PatchOrderWithComplexTypes.js +57 -0
  151. package/spec/mock-project/dist/spec/mock-project/src/handlers/PatchProductWithIntersection.js +58 -0
  152. package/spec/mock-project/dist/spec/mock-project/src/handlers/PatchUserWithUnion.js +58 -0
  153. package/spec/mock-project/dist/spec/mock-project/src/handlers/PostCar.js +54 -0
  154. package/spec/mock-project/dist/spec/mock-project/src/handlers/PostLogin.js +55 -0
  155. package/spec/mock-project/dist/spec/mock-project/src/handlers/PostLogout.js +54 -0
  156. package/spec/mock-project/dist/spec/mock-project/src/handlers/PutCar.js +54 -0
  157. package/spec/mock-project/dist/spec/mock-project/src/index.js +83 -0
  158. package/spec/mock-project/dist/spec/mock-project/src/repos/CarRepo.js +26 -0
  159. package/spec/mock-project/dist/spec/mock-project/src/schemas/Car.js +2 -0
  160. package/spec/mock-project/dist/spec/mock-project/src/schemas/DefaultExportSchema.js +2 -0
  161. package/spec/mock-project/dist/spec/mock-project/src/schemas/FileWithTwoSchemas.js +2 -0
  162. package/spec/mock-project/dist/src/FlinkApp.js +1000 -0
  163. package/spec/mock-project/dist/src/FlinkContext.js +2 -0
  164. package/spec/mock-project/dist/src/FlinkErrors.js +143 -0
  165. package/spec/mock-project/dist/src/FlinkHttpHandler.js +47 -0
  166. package/spec/mock-project/dist/src/FlinkJob.js +2 -0
  167. package/spec/mock-project/dist/src/FlinkLog.js +119 -0
  168. package/spec/mock-project/dist/src/FlinkLogFactory.js +617 -0
  169. package/spec/mock-project/dist/src/FlinkPlugin.js +2 -0
  170. package/spec/mock-project/dist/src/FlinkRepo.js +224 -0
  171. package/spec/mock-project/dist/src/FlinkRequestContext.js +74 -0
  172. package/spec/mock-project/dist/src/FlinkResponse.js +2 -0
  173. package/spec/mock-project/dist/src/ai/AgentExecutor.js +279 -0
  174. package/spec/mock-project/dist/src/ai/AgentRunner.js +632 -0
  175. package/spec/mock-project/dist/src/ai/ConversationAgent.js +402 -0
  176. package/spec/mock-project/dist/src/ai/ConversationFlinkAgent.js +422 -0
  177. package/spec/mock-project/dist/src/ai/FlinkAgent.js +699 -0
  178. package/spec/mock-project/dist/src/ai/FlinkTool.js +2 -0
  179. package/spec/mock-project/dist/src/ai/InMemoryConversationAgent.js +209 -0
  180. package/spec/mock-project/dist/src/ai/LLMAdapter.js +2 -0
  181. package/spec/mock-project/dist/src/ai/SubAgentExecutor.js +223 -0
  182. package/spec/mock-project/dist/src/ai/ToolExecutor.js +412 -0
  183. package/spec/mock-project/dist/src/ai/agentInstructions.js +246 -0
  184. package/spec/mock-project/dist/src/auth/FlinkAuthPlugin.js +2 -0
  185. package/spec/mock-project/dist/src/auth/FlinkAuthUser.js +2 -0
  186. package/spec/mock-project/dist/src/handlers/GetCar.js +26 -52
  187. package/spec/mock-project/dist/src/handlers/GetCar.js.map +1 -0
  188. package/spec/mock-project/dist/src/handlers/GetCar2.js +32 -54
  189. package/spec/mock-project/dist/src/handlers/GetCar2.js.map +1 -0
  190. package/spec/mock-project/dist/src/handlers/GetCarWithArraySchema.js +26 -48
  191. package/spec/mock-project/dist/src/handlers/GetCarWithArraySchema.js.map +1 -0
  192. package/spec/mock-project/dist/src/handlers/GetCarWithArraySchema2.js +28 -48
  193. package/spec/mock-project/dist/src/handlers/GetCarWithArraySchema2.js.map +1 -0
  194. package/spec/mock-project/dist/src/handlers/GetCarWithArraySchema3.js +29 -48
  195. package/spec/mock-project/dist/src/handlers/GetCarWithArraySchema3.js.map +1 -0
  196. package/spec/mock-project/dist/src/handlers/GetCarWithLiteralSchema.js +26 -50
  197. package/spec/mock-project/dist/src/handlers/GetCarWithLiteralSchema.js.map +1 -0
  198. package/spec/mock-project/dist/src/handlers/GetCarWithLiteralSchema2.js +28 -50
  199. package/spec/mock-project/dist/src/handlers/GetCarWithLiteralSchema2.js.map +1 -0
  200. package/spec/mock-project/dist/src/handlers/GetCarWithSchemaInFile.js +27 -53
  201. package/spec/mock-project/dist/src/handlers/GetCarWithSchemaInFile.js.map +1 -0
  202. package/spec/mock-project/dist/src/handlers/GetCarWithSchemaInFile2.js +29 -53
  203. package/spec/mock-project/dist/src/handlers/GetCarWithSchemaInFile2.js.map +1 -0
  204. package/spec/mock-project/dist/src/handlers/ManuallyAddedHandler.js +16 -49
  205. package/spec/mock-project/dist/src/handlers/ManuallyAddedHandler.js.map +1 -0
  206. package/spec/mock-project/dist/src/handlers/ManuallyAddedHandler2.js +25 -50
  207. package/spec/mock-project/dist/src/handlers/ManuallyAddedHandler2.js.map +1 -0
  208. package/spec/mock-project/dist/src/handlers/PatchCar.js +27 -53
  209. package/spec/mock-project/dist/src/handlers/PatchCar.js.map +1 -0
  210. package/spec/mock-project/dist/src/handlers/PatchOnboardingSession.js +44 -70
  211. package/spec/mock-project/dist/src/handlers/PatchOnboardingSession.js.map +1 -0
  212. package/spec/mock-project/dist/src/handlers/PatchOrderWithComplexTypes.js +27 -53
  213. package/spec/mock-project/dist/src/handlers/PatchOrderWithComplexTypes.js.map +1 -0
  214. package/spec/mock-project/dist/src/handlers/PatchProductWithIntersection.js +28 -54
  215. package/spec/mock-project/dist/src/handlers/PatchProductWithIntersection.js.map +1 -0
  216. package/spec/mock-project/dist/src/handlers/PatchUserWithUnion.js +28 -54
  217. package/spec/mock-project/dist/src/handlers/PatchUserWithUnion.js.map +1 -0
  218. package/spec/mock-project/dist/src/handlers/PostCar.js +24 -50
  219. package/spec/mock-project/dist/src/handlers/PostCar.js.map +1 -0
  220. package/spec/mock-project/dist/src/handlers/PostLogin.js +25 -51
  221. package/spec/mock-project/dist/src/handlers/PostLogin.js.map +1 -0
  222. package/spec/mock-project/dist/src/handlers/PostLogout.js +24 -50
  223. package/spec/mock-project/dist/src/handlers/PostLogout.js.map +1 -0
  224. package/spec/mock-project/dist/src/handlers/PutCar.js +24 -50
  225. package/spec/mock-project/dist/src/handlers/PutCar.js.map +1 -0
  226. package/spec/mock-project/dist/src/handlers/StreamWriterFactory.js +83 -0
  227. package/spec/mock-project/dist/src/index.js +52 -76
  228. package/spec/mock-project/dist/src/index.js.map +1 -0
  229. package/spec/mock-project/dist/src/mock-data-generator.js +9 -0
  230. package/spec/mock-project/dist/src/repos/CarRepo.js +12 -24
  231. package/spec/mock-project/dist/src/repos/CarRepo.js.map +1 -0
  232. package/spec/mock-project/dist/src/schemas/Car.js +3 -1
  233. package/spec/mock-project/dist/src/schemas/Car.js.map +1 -0
  234. package/spec/mock-project/dist/src/schemas/DefaultExportSchema.js +3 -1
  235. package/spec/mock-project/dist/src/schemas/DefaultExportSchema.js.map +1 -0
  236. package/spec/mock-project/dist/src/schemas/FileWithTwoSchemas.js +3 -1
  237. package/spec/mock-project/dist/src/schemas/FileWithTwoSchemas.js.map +1 -0
  238. package/spec/mock-project/dist/src/utils.js +290 -0
  239. package/spec/mock-project/tsconfig.json +6 -1
  240. package/spec/schema-generation-nested-objects.spec.ts +97 -0
  241. package/spec/testHelpers.ts +49 -0
  242. package/spec/utils.caseConversion.spec.ts +78 -0
  243. package/spec/utils.spec.ts +13 -13
  244. package/src/DependencyTracker.ts +166 -0
  245. package/src/FlinkApp.ts +919 -155
  246. package/src/FlinkContext.ts +43 -0
  247. package/src/FlinkErrors.ts +32 -12
  248. package/src/FlinkHttpHandler.ts +246 -28
  249. package/src/FlinkJob.ts +11 -0
  250. package/src/FlinkLog.ts +119 -12
  251. package/src/FlinkLogFactory.ts +699 -0
  252. package/src/FlinkRepo.ts +10 -3
  253. package/src/FlinkRequestContext.ts +95 -0
  254. package/src/FlinkResponse.ts +6 -0
  255. package/src/FlinkService.ts +49 -0
  256. package/src/LeaderElection.ts +203 -0
  257. package/src/SchemaCache.ts +232 -0
  258. package/src/TypeScriptCompiler.ts +1347 -610
  259. package/src/TypeScriptUtils.ts +5 -0
  260. package/src/ai/AgentRunner.ts +646 -0
  261. package/src/ai/ConversationAgent.ts +413 -0
  262. package/src/ai/FlinkAgent.ts +1069 -0
  263. package/src/ai/FlinkTool.ts +165 -0
  264. package/src/ai/InMemoryConversationAgent.ts +149 -0
  265. package/src/ai/LLMAdapter.ts +126 -0
  266. package/src/ai/ToolExecutor.ts +485 -0
  267. package/src/ai/agentInstructions.ts +245 -0
  268. package/src/ai/index.ts +8 -0
  269. package/src/ai/instructionFileLoader.ts +156 -0
  270. package/src/auth/FlinkAuthPlugin.ts +2 -1
  271. package/src/handlers/StreamWriterFactory.ts +84 -0
  272. package/src/index.ts +14 -0
  273. package/src/loadPluginSchemas.ts +141 -0
  274. package/src/schema-extraction/TypeScriptSourceParser.ts +1058 -0
  275. package/src/schema-extraction/TypeScriptTokenizer.ts +205 -0
  276. package/src/schema-extraction/index.ts +2 -0
  277. package/src/schema-extraction/types.ts +34 -0
  278. package/src/utils/loadFlinkConfig.ts +89 -0
  279. package/src/utils.ts +52 -0
  280. package/tsconfig.json +6 -1
@@ -0,0 +1,570 @@
1
+ # Simple AST / Enhanced Text Parsing: Feasibility Analysis
2
+
3
+ ## Question
4
+ Can we handle high-risk TypeScript features (template literals, conditional types, mapped types, string literals with brackets) by building more sophisticated text parsing instead of falling back to ts-morph?
5
+
6
+ ## TL;DR Recommendation
7
+
8
+ **✅ YES for String Literals** - Build simple tokenizer (High ROI, Low complexity)
9
+ **🤔 MAYBE for Template Literals** - Possible but complex (Medium ROI, Medium complexity)
10
+ **❌ NO for Conditional/Mapped Types** - Use ts-morph fallback (Low ROI, High complexity)
11
+
12
+ **Recommended Approach:** Hybrid strategy
13
+ 1. Enhanced tokenizer for strings/comments (handles 99% of cases)
14
+ 2. ts-morph fallback for truly complex types (handles remaining 1%)
15
+
16
+ ---
17
+
18
+ ## Feasibility Analysis by Feature
19
+
20
+ ### 1. String Literals with Brackets ✅ FEASIBLE
21
+
22
+ **Problem:**
23
+ ```typescript
24
+ interface Config {
25
+ pattern: "{user:id}"; // Parser sees { as object start
26
+ regex: "/test>/"; // Parser sees > as generic close
27
+ quote: "He said \"hi\""; // Escape handling
28
+ }
29
+ ```
30
+
31
+ **Solution: Simple String State Machine**
32
+
33
+ ```typescript
34
+ /**
35
+ * Enhanced bracket counting with string literal awareness
36
+ */
37
+ function findMatchingBracket(text: string, startPos: number): number {
38
+ let depth = 1;
39
+ let i = startPos + 1;
40
+ let inString = false;
41
+ let stringChar = '';
42
+
43
+ while (i < text.length && depth > 0) {
44
+ const char = text[i];
45
+ const prevChar = text[i - 1];
46
+
47
+ // Handle string state transitions
48
+ if (!inString) {
49
+ if (char === '"' || char === "'" || char === '`') {
50
+ inString = true;
51
+ stringChar = char;
52
+ } else {
53
+ // Only count brackets outside strings
54
+ if (char === '{') depth++;
55
+ else if (char === '}') depth--;
56
+ else if (char === '<') depth++;
57
+ else if (char === '>') depth--;
58
+ }
59
+ } else {
60
+ // Inside string - check for closing quote
61
+ if (char === stringChar && prevChar !== '\\') {
62
+ inString = false;
63
+ stringChar = '';
64
+ }
65
+ }
66
+
67
+ i++;
68
+ }
69
+
70
+ return depth === 0 ? i - 1 : -1;
71
+ }
72
+ ```
73
+
74
+ **Complexity:** Low
75
+ **Benefit:** High (fixes most common edge case)
76
+ **Verdict:** ✅ **IMPLEMENT THIS**
77
+
78
+ ---
79
+
80
+ ### 2. Template Literal Types 🤔 MAYBE FEASIBLE
81
+
82
+ **Problem:**
83
+ ```typescript
84
+ type Route = `/${string}`;
85
+ type EventName = `on${Capitalize<string>}`;
86
+ type Path = `users/${number}/posts/${number}`;
87
+ ```
88
+
89
+ **Challenge:** Template expressions `${...}` contain TypeScript code
90
+
91
+ **Solution: Template Literal State Machine**
92
+
93
+ ```typescript
94
+ /**
95
+ * Parse template literal type
96
+ */
97
+ function parseTemplateLiteral(text: string, startPos: number): {
98
+ literalParts: string[];
99
+ expressions: string[];
100
+ } {
101
+ const literalParts: string[] = [];
102
+ const expressions: string[] = [];
103
+
104
+ let i = startPos + 1; // Skip opening `
105
+ let currentLiteral = '';
106
+ let inExpression = false;
107
+ let exprDepth = 0;
108
+
109
+ while (i < text.length) {
110
+ const char = text[i];
111
+ const nextChar = text[i + 1];
112
+
113
+ if (!inExpression) {
114
+ if (char === '$' && nextChar === '{') {
115
+ // Start of expression
116
+ literalParts.push(currentLiteral);
117
+ currentLiteral = '';
118
+ inExpression = true;
119
+ exprDepth = 1;
120
+ i += 2; // Skip ${
121
+ continue;
122
+ } else if (char === '`') {
123
+ // End of template
124
+ literalParts.push(currentLiteral);
125
+ break;
126
+ } else {
127
+ currentLiteral += char;
128
+ }
129
+ } else {
130
+ // Inside ${...} expression
131
+ if (char === '{') exprDepth++;
132
+ else if (char === '}') {
133
+ exprDepth--;
134
+ if (exprDepth === 0) {
135
+ inExpression = false;
136
+ i++;
137
+ continue;
138
+ }
139
+ }
140
+ expressions.push(char);
141
+ }
142
+
143
+ i++;
144
+ }
145
+
146
+ return { literalParts, expressions };
147
+ }
148
+ ```
149
+
150
+ **But wait... the expressions contain TypeScript code!**
151
+
152
+ Inside `${}` we can have:
153
+ - Type references: `${string}`, `${User}`
154
+ - Utility types: `${Capitalize<string>}`
155
+ - Conditional types: `${T extends string ? T : never}`
156
+ - Mapped types: `${keyof T}`
157
+
158
+ This means we need to **recursively parse TypeScript types** inside template expressions!
159
+
160
+ **Complexity:** Medium-High (needs recursive type parser)
161
+ **Benefit:** Medium (template literal types are growing in popularity but still relatively rare)
162
+ **Verdict:** 🤔 **POSSIBLE BUT COMPLEX - Consider ts-morph fallback**
163
+
164
+ ---
165
+
166
+ ### 3. Conditional Types ❌ NOT FEASIBLE
167
+
168
+ **Problem:**
169
+ ```typescript
170
+ type ExtractParams<T> = T extends `${infer Start}/${infer Rest}`
171
+ ? Start | ExtractParams<Rest>
172
+ : T;
173
+
174
+ type IsString<T> = T extends string ? true : false;
175
+ ```
176
+
177
+ **Challenge:** Understanding `extends`, `infer`, ternary operator in type context
178
+
179
+ **What we'd need to parse:**
180
+ 1. Generic type parameters with constraints: `<T extends Constraint>`
181
+ 2. Type inference: `infer Start`, `infer Rest`
182
+ 3. Ternary operator: `? TrueType : FalseType`
183
+ 4. Recursive type references: `ExtractParams<Rest>`
184
+ 5. Template literal patterns: `` `${infer Start}` ``
185
+
186
+ **Attempted Solution:**
187
+ ```typescript
188
+ function parseConditionalType(text: string) {
189
+ // Need to:
190
+ // 1. Find the "extends" keyword (but not in other contexts!)
191
+ // 2. Parse the constraint expression
192
+ // 3. Find the "?" operator (but not in other contexts!)
193
+ // 4. Parse the true branch (might contain nested conditionals!)
194
+ // 5. Find the ":" operator (but not in other contexts!)
195
+ // 6. Parse the false branch (might contain nested conditionals!)
196
+ // 7. Handle "infer" keyword and capture groups
197
+ // 8. Track nested template literals with expressions
198
+
199
+ // This is essentially re-implementing TypeScript's type parser! 😱
200
+ }
201
+ ```
202
+
203
+ **Reality Check:**
204
+ - TypeScript's parser is ~50,000 lines of code
205
+ - Conditional types interact with ALL other type features
206
+ - Edge cases are numerous and subtle
207
+ - We'd be maintaining a subset parser that needs to evolve with TypeScript
208
+
209
+ **Complexity:** Very High
210
+ **Benefit:** Low (conditional types are rare in tool schemas)
211
+ **Verdict:** ❌ **NOT WORTH IT - Use ts-morph fallback**
212
+
213
+ ---
214
+
215
+ ### 4. Mapped Types ❌ NOT FEASIBLE
216
+
217
+ **Problem:**
218
+ ```typescript
219
+ type Readonly<T> = {
220
+ readonly [P in keyof T]: T[P];
221
+ };
222
+
223
+ type Getters<T> = {
224
+ [K in keyof T as `get${Capitalize<K>}`]: () => T[K];
225
+ };
226
+ ```
227
+
228
+ **Challenge:** Understanding `in`, `keyof`, `as`, type remapping
229
+
230
+ **What we'd need to parse:**
231
+ 1. Index signature with type parameter: `[P in keyof T]`
232
+ 2. Type operators: `keyof T`, `typeof x`, `T[K]`
233
+ 3. Type remapping: `as NewType`
234
+ 4. Template literal remapping: `` as `get${Capitalize<K>}` ``
235
+ 5. Modifiers: `readonly`, `?`, `+`, `-`
236
+
237
+ **Complexity:** Very High
238
+ **Benefit:** Very Low (mapped types almost never appear in tool schemas)
239
+ **Verdict:** ❌ **NOT WORTH IT - Use ts-morph fallback**
240
+
241
+ ---
242
+
243
+ ## Comparative Analysis
244
+
245
+ | Feature | Text Parsing Complexity | Frequency in Schemas | Benefit/Effort Ratio |
246
+ |---------|------------------------|---------------------|---------------------|
247
+ | String literals with brackets | ⭐ Low | ⭐⭐⭐ High | ✅ **Excellent** |
248
+ | Template literal types | ⭐⭐⭐ Medium-High | ⭐⭐ Medium | 🤔 **Fair** |
249
+ | Conditional types | ⭐⭐⭐⭐⭐ Very High | ⭐ Low | ❌ **Poor** |
250
+ | Mapped types | ⭐⭐⭐⭐⭐ Very High | ⭐ Very Low | ❌ **Poor** |
251
+
252
+ ---
253
+
254
+ ## Recommended Implementation: Hybrid Strategy
255
+
256
+ ### Phase 1: Enhanced Tokenizer (High Value, Low Effort) ✅
257
+
258
+ Build a simple tokenizer that properly handles:
259
+ - String literals (all three quote types)
260
+ - Escape sequences
261
+ - Comments (line and block)
262
+ - Bracket/paren/angle depth tracking
263
+
264
+ **Implementation:**
265
+
266
+ ```typescript
267
+ /**
268
+ * Simple TypeScript tokenizer for schema extraction
269
+ */
270
+ class TypeScriptTokenizer {
271
+ private text: string;
272
+ private pos: number = 0;
273
+
274
+ constructor(text: string) {
275
+ this.text = text;
276
+ }
277
+
278
+ /**
279
+ * Find matching closing bracket, properly handling strings and comments
280
+ */
281
+ findMatchingBracket(openChar: '{' | '<' | '(' | '['): number {
282
+ const closeChar = this.getClosingBracket(openChar);
283
+ let depth = 1;
284
+ let i = this.pos + 1;
285
+
286
+ while (i < this.text.length && depth > 0) {
287
+ const token = this.getNextToken(i);
288
+
289
+ if (token.type === 'bracket') {
290
+ if (token.value === openChar) depth++;
291
+ else if (token.value === closeChar) depth--;
292
+ }
293
+
294
+ i = token.endPos;
295
+ }
296
+
297
+ return depth === 0 ? i - 1 : -1;
298
+ }
299
+
300
+ /**
301
+ * Get next meaningful token, skipping strings and comments
302
+ */
303
+ private getNextToken(startPos: number): Token {
304
+ const char = this.text[startPos];
305
+
306
+ // String literal
307
+ if (char === '"' || char === "'" || char === '`') {
308
+ return this.parseStringLiteral(startPos, char);
309
+ }
310
+
311
+ // Line comment
312
+ if (char === '/' && this.text[startPos + 1] === '/') {
313
+ return this.parseLineComment(startPos);
314
+ }
315
+
316
+ // Block comment
317
+ if (char === '/' && this.text[startPos + 1] === '*') {
318
+ return this.parseBlockComment(startPos);
319
+ }
320
+
321
+ // Bracket
322
+ if ('{}<>()[]'.includes(char)) {
323
+ return {
324
+ type: 'bracket',
325
+ value: char,
326
+ startPos,
327
+ endPos: startPos + 1,
328
+ };
329
+ }
330
+
331
+ // Other character
332
+ return {
333
+ type: 'char',
334
+ value: char,
335
+ startPos,
336
+ endPos: startPos + 1,
337
+ };
338
+ }
339
+
340
+ private parseStringLiteral(startPos: number, quoteChar: string): Token {
341
+ let i = startPos + 1;
342
+ let escaped = false;
343
+
344
+ while (i < this.text.length) {
345
+ if (escaped) {
346
+ escaped = false;
347
+ i++;
348
+ continue;
349
+ }
350
+
351
+ if (this.text[i] === '\\') {
352
+ escaped = true;
353
+ i++;
354
+ continue;
355
+ }
356
+
357
+ if (this.text[i] === quoteChar) {
358
+ return {
359
+ type: 'string',
360
+ value: this.text.slice(startPos, i + 1),
361
+ startPos,
362
+ endPos: i + 1,
363
+ };
364
+ }
365
+
366
+ i++;
367
+ }
368
+
369
+ throw new Error(`Unclosed string literal at position ${startPos}`);
370
+ }
371
+
372
+ private parseLineComment(startPos: number): Token {
373
+ const newlinePos = this.text.indexOf('\n', startPos);
374
+ const endPos = newlinePos === -1 ? this.text.length : newlinePos + 1;
375
+
376
+ return {
377
+ type: 'comment',
378
+ value: this.text.slice(startPos, endPos),
379
+ startPos,
380
+ endPos,
381
+ };
382
+ }
383
+
384
+ private parseBlockComment(startPos: number): Token {
385
+ const endPos = this.text.indexOf('*/', startPos + 2);
386
+
387
+ if (endPos === -1) {
388
+ throw new Error(`Unclosed block comment at position ${startPos}`);
389
+ }
390
+
391
+ return {
392
+ type: 'comment',
393
+ value: this.text.slice(startPos, endPos + 2),
394
+ startPos,
395
+ endPos: endPos + 2,
396
+ };
397
+ }
398
+
399
+ private getClosingBracket(open: string): string {
400
+ const pairs: Record<string, string> = {
401
+ '{': '}',
402
+ '<': '>',
403
+ '(': ')',
404
+ '[': ']',
405
+ };
406
+ return pairs[open];
407
+ }
408
+ }
409
+
410
+ interface Token {
411
+ type: 'string' | 'comment' | 'bracket' | 'char';
412
+ value: string;
413
+ startPos: number;
414
+ endPos: number;
415
+ }
416
+ ```
417
+
418
+ **Usage in findTypeDefinition():**
419
+
420
+ ```typescript
421
+ static findTypeDefinition(sourceText: string, typeName: string): TypeDefinition | null {
422
+ // ... existing regex to find interface/type ...
423
+
424
+ // Use tokenizer instead of manual bracket counting
425
+ const tokenizer = new TypeScriptTokenizer(sourceText);
426
+ tokenizer.pos = braceStart;
427
+ const endPos = tokenizer.findMatchingBracket('{');
428
+
429
+ if (endPos === -1) {
430
+ return null;
431
+ }
432
+
433
+ const definition = sourceText.slice(startIndex, endPos + 1).trim();
434
+ return { name: typeName, definition, kind: 'interface' };
435
+ }
436
+ ```
437
+
438
+ **Benefits:**
439
+ - ✅ Fixes string literal edge cases
440
+ - ✅ Robust comment handling
441
+ - ✅ Proper escape sequence handling
442
+ - ✅ ~100 lines of code (manageable)
443
+ - ✅ Reusable for all bracket matching
444
+
445
+ ---
446
+
447
+ ### Phase 2: Template Literal Detection (Optional) 🤔
448
+
449
+ **Simple Approach:** Detect but don't parse
450
+
451
+ ```typescript
452
+ function hasTemplateLiteralType(text: string): boolean {
453
+ // Match: type Name = `...`
454
+ return /type\s+\w+\s*=\s*`/.test(text);
455
+ }
456
+
457
+ function extractSchemasFast(filePath: string) {
458
+ const fileText = fs.readFileSync(filePath, 'utf8');
459
+
460
+ // Detect template literal types
461
+ if (hasTemplateLiteralType(fileText)) {
462
+ perfLog.info(`${path.basename(filePath)}: Template literal types detected, using ts-morph`);
463
+ return extractSchemasWithTsMorph(filePath);
464
+ }
465
+
466
+ // Continue with fast extraction...
467
+ }
468
+ ```
469
+
470
+ **Benefits:**
471
+ - ✅ Simple detection (1 line regex)
472
+ - ✅ Maintains safety for complex case
473
+ - ✅ No need to parse template expressions
474
+
475
+ ---
476
+
477
+ ### Phase 3: ts-morph Fallback for Complex Types ✅
478
+
479
+ For conditional and mapped types, just use ts-morph:
480
+
481
+ ```typescript
482
+ function hasComplexTypeFeatures(text: string): boolean {
483
+ return (
484
+ hasConditionalType(text) ||
485
+ hasMappedType(text) ||
486
+ hasTemplateLiteralType(text) // If Phase 2 not implemented
487
+ );
488
+ }
489
+
490
+ function hasConditionalType(text: string): boolean {
491
+ // Match: T extends U ? A : B
492
+ return /\bextends\b.*?\?.*?:/.test(text);
493
+ }
494
+
495
+ function hasMappedType(text: string): boolean {
496
+ // Match: [K in keyof T]
497
+ return /\[\s*\w+\s+in\s+keyof\s+/.test(text);
498
+ }
499
+ ```
500
+
501
+ **Benefits:**
502
+ - ✅ 100% correctness for complex cases
503
+ - ✅ Minimal performance impact (rare cases)
504
+ - ✅ No need to maintain complex parser
505
+
506
+ ---
507
+
508
+ ## Implementation Effort vs Benefit
509
+
510
+ | Approach | Lines of Code | Dev Time | Maintenance | Performance | Safety |
511
+ |----------|--------------|----------|-------------|-------------|--------|
512
+ | **Enhanced Tokenizer** | ~100 | 4 hours | Low | 1200x | 99% |
513
+ | **+ Template Parsing** | ~300 | 16 hours | Medium | 1150x | 99.5% |
514
+ | **+ Full Type Parser** | ~5000+ | 200+ hours | High | 1100x | 99.9% |
515
+ | **Hybrid (Tokenizer + Fallback)** | ~150 | 6 hours | Low | 1100x | **100%** |
516
+
517
+ ---
518
+
519
+ ## Recommended Path Forward
520
+
521
+ ### ✅ Implement Now
522
+ 1. **Enhanced tokenizer** for string/comment handling (~4 hours, high value)
523
+ 2. **Detection functions** for complex types (~1 hour)
524
+ 3. **ts-morph fallback** for complex cases (~1 hour)
525
+
526
+ **Total effort:** ~6 hours
527
+ **Result:** 99.9%+ safety, ~1100x speedup, minimal maintenance
528
+
529
+ ### 🤔 Consider Later
530
+ 4. **Template literal parsing** if usage grows (~16 hours, medium value)
531
+
532
+ ### ❌ Don't Implement
533
+ 5. **Full conditional type parsing** - not worth the effort
534
+ 6. **Full mapped type parsing** - not worth the effort
535
+
536
+ ---
537
+
538
+ ## Conclusion
539
+
540
+ **YES** to enhanced tokenizer (string/comment handling) ✅
541
+ **NO** to full AST for complex types ❌
542
+ **RECOMMENDED:** Hybrid approach with simple tokenizer + ts-morph fallback
543
+
544
+ ### Why Hybrid is Optimal
545
+
546
+ 1. **Performance:** Maintains ~1100x speedup (vs 1250x pure text)
547
+ 2. **Safety:** 100% correctness via ts-morph fallback
548
+ 3. **Complexity:** ~150 lines of tokenizer code (manageable)
549
+ 4. **Maintenance:** Minimal - only maintain tokenizer, not full parser
550
+ 5. **Future-proof:** TypeScript can add new features, we just fallback
551
+
552
+ ### The Reality
553
+
554
+ Building a full TypeScript type parser means:
555
+ - Re-implementing 10-20% of TypeScript's parser
556
+ - Keeping up with TypeScript versions (3-4 releases/year)
557
+ - Handling edge cases that take TypeScript team months to fix
558
+ - Testing against thousands of type combinations
559
+
560
+ **It's not worth it when ts-morph is available as a safety net.**
561
+
562
+ ### Final Recommendation
563
+
564
+ Implement **enhanced tokenizer** (Phase 1) to handle string literals robustly, then use **ts-morph fallback** for truly complex types. This gives us:
565
+ - ✅ Best performance (1100x+ speedup)
566
+ - ✅ Best safety (100% correctness)
567
+ - ✅ Best maintainability (small codebase)
568
+ - ✅ Best of both worlds
569
+
570
+ **Start with Phase 1, measure real-world fallback frequency, then decide if Phase 2 is needed.**
package/bin/flink.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- const commands = ["build", "generate" /* 'generate' is alias for 'build' */, "run", "clean", "help"];
3
+ const commands = ["build", "generate" /* 'generate' is alias for 'build' */, "run", "dev", "clean", "help"];
4
4
 
5
5
  const argv = process.argv.slice(2);
6
6
  let argCommand = argv[0];
@@ -21,6 +21,17 @@ if (argCommand === "generate") {
21
21
 
22
22
  const cmd = require("../cli/" + argCommand);
23
23
 
24
- cmd(argv.slice(1));
24
+ (async () => {
25
+ try {
26
+ await cmd(argv.slice(1));
27
+ } catch (error: any) {
28
+ if (process.env.DEBUG === "true") {
29
+ console.error(error);
30
+ } else {
31
+ console.error(`Error: ${error.message}`);
32
+ }
33
+ process.exit(1);
34
+ }
35
+ })();
25
36
 
26
37
  export default () => {};
package/cli/build.ts CHANGED
@@ -1,48 +1,28 @@
1
1
  #!/usr/bin/env node
2
- import TypeScriptCompiler from "../src/TypeScriptCompiler";
3
- import { getOption } from "./cli-utils";
4
-
5
- module.exports = async function run(args: string[]) {
6
- const startTime = Date.now();
7
-
8
- if (args.includes("--help")) {
9
- console.log(`
10
- Description
11
- Builds the application.
12
- Will generate intermediates files in .flink and compile/transpile
13
- javascript bundle in /dist folder
14
-
15
- Usage
16
- $ flink build <dir>
17
-
18
- <dir> represents the directory of the Flink application.
19
- If no directory is provided, the current directory will be used.
20
-
21
- Options
22
- --help Displays this message
23
- `);
24
-
25
- process.exit(0);
26
- }
27
-
28
- let dir = "./";
29
- if (args[0] && !args[0].startsWith("--")) {
30
- dir = args[0];
2
+ import { parseArgs, hasFlag, printHelp, compile } from "./cli-utils";
3
+ import { FlinkLogFactory } from "../src/FlinkLogFactory";
4
+ import { loadFlinkConfig } from "../src/utils/loadFlinkConfig";
5
+
6
+ // Load config BEFORE creating logger
7
+ const flinkConfig = loadFlinkConfig();
8
+ FlinkLogFactory.configure(flinkConfig?.logging);
9
+
10
+ module.exports = async function build(args: string[]) {
11
+ const parsed = parseArgs(args);
12
+
13
+ if (hasFlag(parsed, "help")) {
14
+ printHelp({
15
+ description:
16
+ "Builds the application.\n Will generate intermediates files in .flink and compile/transpile\n javascript bundle in /dist folder",
17
+ usage: "$ flink build <dir>",
18
+ options: [{ name: "help", description: "Displays this message" }],
19
+ });
20
+ return;
31
21
  }
32
22
 
33
- const exclude = getOption(args, "exclude", "/spec") as string;
34
-
35
- await TypeScriptCompiler.clean(dir);
36
-
37
- const compiler = new TypeScriptCompiler(dir);
38
-
39
- if (!compiler.getPreEmitDiagnostics()) {
40
- process.exit(1);
41
- }
42
-
43
- await Promise.all([compiler.parseRepos(), compiler.parseHandlers(exclude.split(",")), compiler.parseJobs(), compiler.generateStartScript()]);
44
-
45
- console.log(`Compilation done, took ${Date.now() - startTime}ms`);
46
-
47
- compiler.emit();
23
+ await compile({
24
+ dir: parsed.dir,
25
+ typeCheck: true,
26
+ timingLogs: true,
27
+ });
48
28
  };