gemi 0.56.0 → 0.58.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (257) hide show
  1. package/dist/app/index.js +1 -1
  2. package/dist/broadcasting/index.js +1 -1
  3. package/dist/bun/plugin.js +1 -1
  4. package/dist/bun/preload.js +1 -1
  5. package/dist/{chunk-jdj7k3r9.js → chunk-0a2xgcj3.js} +2 -2
  6. package/dist/{chunk-jdj7k3r9.js.map → chunk-0a2xgcj3.js.map} +1 -1
  7. package/dist/{chunk-3e88tyee.js → chunk-3337e5g0.js} +2 -2
  8. package/dist/{chunk-3e88tyee.js.map → chunk-3337e5g0.js.map} +1 -1
  9. package/dist/chunk-3aa287k7.js +6 -0
  10. package/dist/{chunk-cv9w5cmb.js.map → chunk-3aa287k7.js.map} +2 -2
  11. package/dist/{chunk-01am9k5v.js → chunk-3g5bjvdf.js} +2 -2
  12. package/dist/{chunk-01am9k5v.js.map → chunk-3g5bjvdf.js.map} +1 -1
  13. package/dist/{chunk-w9k9s4wh.js → chunk-3xadx444.js} +2 -2
  14. package/dist/{chunk-w9k9s4wh.js.map → chunk-3xadx444.js.map} +1 -1
  15. package/dist/{chunk-npg72mez.js → chunk-3zxwscmf.js} +2 -2
  16. package/dist/{chunk-kgmr9qxx.js.map → chunk-3zxwscmf.js.map} +1 -1
  17. package/dist/{chunk-64s1pzz1.js → chunk-437085pe.js} +2 -2
  18. package/dist/{chunk-64s1pzz1.js.map → chunk-437085pe.js.map} +1 -1
  19. package/dist/{chunk-eqrd31ye.js → chunk-4yt5x8s2.js} +2 -2
  20. package/dist/{chunk-eqrd31ye.js.map → chunk-4yt5x8s2.js.map} +1 -1
  21. package/dist/{chunk-9r0sb4zn.js → chunk-5athahgr.js} +2 -2
  22. package/dist/{chunk-9r0sb4zn.js.map → chunk-5athahgr.js.map} +1 -1
  23. package/dist/{chunk-g30q4n5y.js → chunk-5n2rvfh3.js} +2 -2
  24. package/dist/{chunk-g30q4n5y.js.map → chunk-5n2rvfh3.js.map} +1 -1
  25. package/dist/{chunk-1zfsgffv.js → chunk-6235kb30.js} +3 -3
  26. package/dist/{chunk-1zfsgffv.js.map → chunk-6235kb30.js.map} +1 -1
  27. package/dist/{chunk-javjeayw.js → chunk-7b0x860b.js} +2 -2
  28. package/dist/{chunk-javjeayw.js.map → chunk-7b0x860b.js.map} +1 -1
  29. package/dist/{chunk-4qwwy968.js → chunk-7ef5n8k2.js} +2 -2
  30. package/dist/{chunk-4qwwy968.js.map → chunk-7ef5n8k2.js.map} +1 -1
  31. package/dist/{chunk-q0waxxz5.js → chunk-7j6wbv12.js} +2 -2
  32. package/dist/{chunk-q0waxxz5.js.map → chunk-7j6wbv12.js.map} +1 -1
  33. package/dist/chunk-86jebsm4.js +9 -0
  34. package/dist/{chunk-kry5vwam.js.map → chunk-86jebsm4.js.map} +3 -3
  35. package/dist/chunk-87qab82w.js +5 -0
  36. package/dist/chunk-87qab82w.js.map +37 -0
  37. package/dist/{chunk-36pg61vt.js → chunk-8gew8b9a.js} +2 -2
  38. package/dist/{chunk-36pg61vt.js.map → chunk-8gew8b9a.js.map} +1 -1
  39. package/dist/{chunk-v6v6sem5.js → chunk-9m2tbf3n.js} +2 -2
  40. package/dist/{chunk-v6v6sem5.js.map → chunk-9m2tbf3n.js.map} +1 -1
  41. package/dist/{chunk-gzdf2025.js → chunk-a2sgjpvq.js} +2 -2
  42. package/dist/{chunk-gzdf2025.js.map → chunk-a2sgjpvq.js.map} +1 -1
  43. package/dist/chunk-b35e128b.js +5 -0
  44. package/dist/{chunk-b50zmz3t.js.map → chunk-b35e128b.js.map} +1 -1
  45. package/dist/{chunk-ct274qts.js → chunk-cyaz97p5.js} +2 -2
  46. package/dist/{chunk-ct274qts.js.map → chunk-cyaz97p5.js.map} +1 -1
  47. package/dist/{chunk-v06qcyj5.js → chunk-d125j8t0.js} +3 -3
  48. package/dist/{chunk-v06qcyj5.js.map → chunk-d125j8t0.js.map} +1 -1
  49. package/dist/{chunk-hs5v3eqj.js → chunk-dgsgjg53.js} +2 -2
  50. package/dist/{chunk-hs5v3eqj.js.map → chunk-dgsgjg53.js.map} +1 -1
  51. package/dist/{chunk-xjy5apyr.js → chunk-eejmhtnc.js} +2 -2
  52. package/dist/{chunk-xjy5apyr.js.map → chunk-eejmhtnc.js.map} +1 -1
  53. package/dist/{chunk-3y75q5a2.js → chunk-fjm4y8bn.js} +2 -2
  54. package/dist/{chunk-3y75q5a2.js.map → chunk-fjm4y8bn.js.map} +1 -1
  55. package/dist/{chunk-9c89q2mz.js → chunk-grdahng8.js} +2 -2
  56. package/dist/{chunk-9c89q2mz.js.map → chunk-grdahng8.js.map} +1 -1
  57. package/dist/{chunk-699z6d8y.js → chunk-gw6agevz.js} +3 -3
  58. package/dist/{chunk-699z6d8y.js.map → chunk-gw6agevz.js.map} +1 -1
  59. package/dist/{chunk-62ke19q4.js → chunk-hppagzz4.js} +4 -4
  60. package/dist/{chunk-62ke19q4.js.map → chunk-hppagzz4.js.map} +1 -1
  61. package/dist/chunk-hwa5sqw5.js +19 -0
  62. package/dist/{chunk-tmnhkphv.js.map → chunk-hwa5sqw5.js.map} +12 -6
  63. package/dist/chunk-hxf1re93.js +4 -0
  64. package/dist/{chunk-vkngcrzq.js.map → chunk-hxf1re93.js.map} +6 -5
  65. package/dist/{chunk-d36dfqxw.js → chunk-j0c6ytkj.js} +3 -3
  66. package/dist/{chunk-d36dfqxw.js.map → chunk-j0c6ytkj.js.map} +1 -1
  67. package/dist/{chunk-kgmr9qxx.js → chunk-jhkjz9jr.js} +2 -2
  68. package/dist/{chunk-npg72mez.js.map → chunk-jhkjz9jr.js.map} +1 -1
  69. package/dist/{chunk-62723jyy.js → chunk-k0fvsyeh.js} +1 -1
  70. package/dist/{chunk-31kcf7dq.js → chunk-keehyx51.js} +2 -2
  71. package/dist/{chunk-31kcf7dq.js.map → chunk-keehyx51.js.map} +1 -1
  72. package/dist/{chunk-enhkf60v.js → chunk-m3xy5xyf.js} +2 -2
  73. package/dist/{chunk-enhkf60v.js.map → chunk-m3xy5xyf.js.map} +1 -1
  74. package/dist/{chunk-c75mymmq.js → chunk-mkfpnymy.js} +1 -1
  75. package/dist/{chunk-rgb69nh1.js → chunk-mwpdp09e.js} +2 -2
  76. package/dist/{chunk-rgb69nh1.js.map → chunk-mwpdp09e.js.map} +1 -1
  77. package/dist/chunk-pmhd6zfc.js +37 -0
  78. package/dist/chunk-pmhd6zfc.js.map +20 -0
  79. package/dist/chunk-qb5mv6pj.js +5 -0
  80. package/dist/chunk-qb5mv6pj.js.map +12 -0
  81. package/dist/{chunk-1pwwrpa3.js → chunk-qgxr0g36.js} +2 -2
  82. package/dist/{chunk-1pwwrpa3.js.map → chunk-qgxr0g36.js.map} +1 -1
  83. package/dist/{chunk-4yafsffx.js → chunk-sy7jbdeb.js} +2 -2
  84. package/dist/{chunk-4yafsffx.js.map → chunk-sy7jbdeb.js.map} +1 -1
  85. package/dist/{chunk-gasdfwva.js → chunk-szss069z.js} +2 -2
  86. package/dist/{chunk-gasdfwva.js.map → chunk-szss069z.js.map} +1 -1
  87. package/dist/{chunk-m0ggfy1m.js → chunk-tss5svjr.js} +2 -2
  88. package/dist/{chunk-m0ggfy1m.js.map → chunk-tss5svjr.js.map} +1 -1
  89. package/dist/{chunk-dzzmqv0j.js → chunk-vr90r27j.js} +2 -2
  90. package/dist/{chunk-dzzmqv0j.js.map → chunk-vr90r27j.js.map} +1 -1
  91. package/dist/{chunk-pvdbrt4z.js → chunk-w62m5f0n.js} +3 -3
  92. package/dist/{chunk-pvdbrt4z.js.map → chunk-w62m5f0n.js.map} +1 -1
  93. package/dist/{chunk-cn2r5jfj.js → chunk-w7rf99w6.js} +2 -2
  94. package/dist/{chunk-cn2r5jfj.js.map → chunk-w7rf99w6.js.map} +1 -1
  95. package/dist/{chunk-tja0c815.js → chunk-wbrj0gya.js} +2 -2
  96. package/dist/{chunk-tja0c815.js.map → chunk-wbrj0gya.js.map} +1 -1
  97. package/dist/{chunk-rsdg619q.js → chunk-xdv1b8mr.js} +2 -2
  98. package/dist/{chunk-rsdg619q.js.map → chunk-xdv1b8mr.js.map} +1 -1
  99. package/dist/{chunk-h3mwgbg7.js → chunk-xey9cbap.js} +2 -2
  100. package/dist/{chunk-h3mwgbg7.js.map → chunk-xey9cbap.js.map} +1 -1
  101. package/dist/{chunk-wgpa04jb.js → chunk-xzk827r3.js} +2 -2
  102. package/dist/{chunk-wgpa04jb.js.map → chunk-xzk827r3.js.map} +1 -1
  103. package/dist/{chunk-x14sk95v.js → chunk-y6a8r2bn.js} +3 -3
  104. package/dist/{chunk-x14sk95v.js.map → chunk-y6a8r2bn.js.map} +1 -1
  105. package/dist/{chunk-33wjsw4r.js → chunk-yed5whgs.js} +3 -3
  106. package/dist/{chunk-33wjsw4r.js.map → chunk-yed5whgs.js.map} +1 -1
  107. package/dist/{chunk-02gdzs5t.js → chunk-yf7vz71n.js} +1 -1
  108. package/dist/{chunk-y9fp58bg.js → chunk-yjzs247s.js} +2 -2
  109. package/dist/{chunk-y9fp58bg.js.map → chunk-yjzs247s.js.map} +1 -1
  110. package/dist/{chunk-kgg1eqne.js → chunk-yy0eb9wn.js} +2 -2
  111. package/dist/{chunk-kgg1eqne.js.map → chunk-yy0eb9wn.js.map} +1 -1
  112. package/dist/{chunk-4xx78ba9.js → chunk-zbxgbr12.js} +2 -2
  113. package/dist/{chunk-4xx78ba9.js.map → chunk-zbxgbr12.js.map} +1 -1
  114. package/dist/{chunk-8k1zqrvh.js → chunk-zh2egcyb.js} +2 -2
  115. package/dist/{chunk-8k1zqrvh.js.map → chunk-zh2egcyb.js.map} +1 -1
  116. package/dist/chunks/ThemeProvider-li1J_igh.js.map +1 -1
  117. package/dist/client/ClientRouter.d.ts.map +1 -1
  118. package/dist/client/ProgressManager.d.ts +1 -1
  119. package/dist/client/RouteStateContext.d.ts +9 -0
  120. package/dist/client/RouteStateContext.d.ts.map +1 -1
  121. package/dist/client/ServerDataProvider.d.ts +7 -0
  122. package/dist/client/ServerDataProvider.d.ts.map +1 -1
  123. package/dist/client/index.d.ts +2 -1
  124. package/dist/client/index.d.ts.map +1 -1
  125. package/dist/client/index.js +68 -10
  126. package/dist/client/index.js.map +1 -1
  127. package/dist/client/rpc.d.ts +42 -0
  128. package/dist/client/rpc.d.ts.map +1 -1
  129. package/dist/client/useFeature.d.ts +40 -0
  130. package/dist/client/useFeature.d.ts.map +1 -0
  131. package/dist/config/index.js +1 -1
  132. package/dist/console/run.js +2 -2
  133. package/dist/console/run.js.map +1 -1
  134. package/dist/container/index.js +2 -2
  135. package/dist/container/index.js.map +1 -1
  136. package/dist/database/index.js +2 -2
  137. package/dist/database/index.js.map +1 -1
  138. package/dist/email/index.js +2 -2
  139. package/dist/email/index.js.map +1 -1
  140. package/dist/facades/Features.d.ts +57 -0
  141. package/dist/facades/Features.d.ts.map +1 -0
  142. package/dist/facades/index.d.ts +1 -0
  143. package/dist/facades/index.d.ts.map +1 -1
  144. package/dist/facades/index.js +2 -2
  145. package/dist/facades/index.js.map +1 -1
  146. package/dist/foundation/index.js +2 -2
  147. package/dist/foundation/index.js.map +1 -1
  148. package/dist/gemi.d.ts +13 -5
  149. package/dist/http/ApiRouter.d.ts +3 -2
  150. package/dist/http/ApiRouter.d.ts.map +1 -1
  151. package/dist/http/HttpRequest.d.ts +4 -0
  152. package/dist/http/HttpRequest.d.ts.map +1 -1
  153. package/dist/http/ViewRouter.d.ts +127 -4
  154. package/dist/http/ViewRouter.d.ts.map +1 -1
  155. package/dist/http/index.d.ts +1 -0
  156. package/dist/http/index.d.ts.map +1 -1
  157. package/dist/http/index.js +2 -2
  158. package/dist/http/index.js.map +1 -1
  159. package/dist/http/middlewareList.d.ts +25 -0
  160. package/dist/http/middlewareList.d.ts.map +1 -0
  161. package/dist/http/requestContext.d.ts +57 -0
  162. package/dist/http/requestContext.d.ts.map +1 -1
  163. package/dist/i18n/dictionaryRuntime.js +2 -2
  164. package/dist/i18n/dictionaryRuntime.js.map +1 -1
  165. package/dist/i18n/index.js +2 -2
  166. package/dist/i18n/index.js.map +1 -1
  167. package/dist/ide/typescript-plugin/index.js +1206 -0
  168. package/dist/ide/typescript-plugin/index.js.map +17 -0
  169. package/dist/kernel/index.js +3 -3
  170. package/dist/kernel/index.js.map +3 -3
  171. package/dist/kernel/providers.d.ts +16 -4
  172. package/dist/kernel/providers.d.ts.map +1 -1
  173. package/dist/orm/context.d.ts +65 -0
  174. package/dist/orm/context.d.ts.map +1 -1
  175. package/dist/orm/index.js +2 -2
  176. package/dist/orm/index.js.map +1 -1
  177. package/dist/server/index.js +2 -2
  178. package/dist/server/index.js.map +1 -1
  179. package/dist/services/discovery.d.ts +27 -0
  180. package/dist/services/discovery.d.ts.map +1 -1
  181. package/dist/services/events/Event.d.ts +208 -0
  182. package/dist/services/events/Event.d.ts.map +1 -0
  183. package/dist/services/events/EventManager.d.ts +285 -0
  184. package/dist/services/events/EventManager.d.ts.map +1 -0
  185. package/dist/services/events/EventServiceProvider.d.ts +46 -0
  186. package/dist/services/events/EventServiceProvider.d.ts.map +1 -0
  187. package/dist/services/events/FakeEventManager.d.ts +155 -0
  188. package/dist/services/events/FakeEventManager.d.ts.map +1 -0
  189. package/dist/services/events/FakeEventManager.test-d.d.ts +2 -0
  190. package/dist/services/events/FakeEventManager.test-d.d.ts.map +1 -0
  191. package/dist/services/events/Listener.d.ts +189 -0
  192. package/dist/services/events/Listener.d.ts.map +1 -0
  193. package/dist/services/events/Listener.test-d.d.ts +2 -0
  194. package/dist/services/events/Listener.test-d.d.ts.map +1 -0
  195. package/dist/services/events/config.d.ts +55 -0
  196. package/dist/services/events/config.d.ts.map +1 -0
  197. package/dist/services/events/listenerJob.d.ts +43 -0
  198. package/dist/services/events/listenerJob.d.ts.map +1 -0
  199. package/dist/services/features/FeatureFlagStore.d.ts +60 -0
  200. package/dist/services/features/FeatureFlagStore.d.ts.map +1 -0
  201. package/dist/services/features/FeatureManager.d.ts +82 -0
  202. package/dist/services/features/FeatureManager.d.ts.map +1 -0
  203. package/dist/services/features/FeaturesServiceProvider.d.ts +6 -0
  204. package/dist/services/features/FeaturesServiceProvider.d.ts.map +1 -0
  205. package/dist/services/features/bucket.d.ts +57 -0
  206. package/dist/services/features/bucket.d.ts.map +1 -0
  207. package/dist/services/features/config.d.ts +57 -0
  208. package/dist/services/features/config.d.ts.map +1 -0
  209. package/dist/services/features/context.d.ts +31 -0
  210. package/dist/services/features/context.d.ts.map +1 -0
  211. package/dist/services/features/defineFeature.d.ts +145 -0
  212. package/dist/services/features/defineFeature.d.ts.map +1 -0
  213. package/dist/services/features/evaluate.d.ts +74 -0
  214. package/dist/services/features/evaluate.d.ts.map +1 -0
  215. package/dist/services/features/sources/DatabaseFeatureFlagSource.d.ts +19 -0
  216. package/dist/services/features/sources/DatabaseFeatureFlagSource.d.ts.map +1 -0
  217. package/dist/services/features/sources/FeatureFlagSource.d.ts +30 -0
  218. package/dist/services/features/sources/FeatureFlagSource.d.ts.map +1 -0
  219. package/dist/services/features/sources/StaticFeatureFlagSource.d.ts +24 -0
  220. package/dist/services/features/sources/StaticFeatureFlagSource.d.ts.map +1 -0
  221. package/dist/services/features/types.d.ts +63 -0
  222. package/dist/services/features/types.d.ts.map +1 -0
  223. package/dist/services/index.d.ts +18 -1
  224. package/dist/services/index.d.ts.map +1 -1
  225. package/dist/services/index.js +8 -8
  226. package/dist/services/index.js.map +8 -4
  227. package/dist/services/queue/QueueManager.d.ts +31 -0
  228. package/dist/services/queue/QueueManager.d.ts.map +1 -1
  229. package/dist/services/router/ViewRouteDispatcher.d.ts +8 -0
  230. package/dist/services/router/ViewRouteDispatcher.d.ts.map +1 -1
  231. package/dist/services/router/createFlatViewRoutes.d.ts +14 -0
  232. package/dist/services/router/createFlatViewRoutes.d.ts.map +1 -1
  233. package/dist/services/router/streamQueryInjection.d.ts.map +1 -1
  234. package/dist/support/index.js +2 -2
  235. package/dist/support/index.js.map +1 -1
  236. package/dist/testing/Page.d.ts +12 -0
  237. package/dist/testing/Page.d.ts.map +1 -1
  238. package/dist/testing/index.d.ts +24 -0
  239. package/dist/testing/index.d.ts.map +1 -1
  240. package/dist/testing/index.js +7 -3
  241. package/dist/testing/index.js.map +1 -1
  242. package/ide/typescript-plugin/package.json +5 -0
  243. package/package.json +4 -2
  244. package/dist/chunk-4t80js0n.js +0 -33
  245. package/dist/chunk-4t80js0n.js.map +0 -18
  246. package/dist/chunk-98a576s9.js +0 -5
  247. package/dist/chunk-98a576s9.js.map +0 -30
  248. package/dist/chunk-b50zmz3t.js +0 -5
  249. package/dist/chunk-cv9w5cmb.js +0 -6
  250. package/dist/chunk-f9mfw82d.js +0 -5
  251. package/dist/chunk-f9mfw82d.js.map +0 -12
  252. package/dist/chunk-kry5vwam.js +0 -9
  253. package/dist/chunk-tmnhkphv.js +0 -19
  254. package/dist/chunk-vkngcrzq.js +0 -4
  255. /package/dist/{chunk-62723jyy.js.map → chunk-k0fvsyeh.js.map} +0 -0
  256. /package/dist/{chunk-c75mymmq.js.map → chunk-mkfpnymy.js.map} +0 -0
  257. /package/dist/{chunk-02gdzs5t.js.map → chunk-yf7vz71n.js.map} +0 -0
@@ -0,0 +1,1206 @@
1
+ // ide/typescript-plugin/ast.ts
2
+ function unwrapExpression(ts, node) {
3
+ let current = node;
4
+ for (;; ) {
5
+ if (ts.isParenthesizedExpression(current))
6
+ current = current.expression;
7
+ else if (ts.isAsExpression(current))
8
+ current = current.expression;
9
+ else if (ts.isSatisfiesExpression(current))
10
+ current = current.expression;
11
+ else if (ts.isNonNullExpression(current))
12
+ current = current.expression;
13
+ else if (ts.isTypeAssertionExpression(current))
14
+ current = current.expression;
15
+ else
16
+ return current;
17
+ }
18
+ }
19
+ function unwrapBuilderChain(ts, node) {
20
+ const chainable = new Set(["middleware", "alwaysRun"]);
21
+ let current = unwrapExpression(ts, node);
22
+ while (ts.isCallExpression(current) && ts.isPropertyAccessExpression(current.expression) && chainable.has(current.expression.name.text)) {
23
+ current = unwrapExpression(ts, current.expression.expression);
24
+ }
25
+ return current;
26
+ }
27
+ function getThisCall(ts, node) {
28
+ if (!ts.isCallExpression(node))
29
+ return;
30
+ const callee = node.expression;
31
+ if (!ts.isPropertyAccessExpression(callee))
32
+ return;
33
+ if (callee.expression.kind !== ts.SyntaxKind.ThisKeyword)
34
+ return;
35
+ return { method: callee.name.text, args: node.arguments, node };
36
+ }
37
+ function getStringValue(ts, checker, node) {
38
+ if (!node)
39
+ return;
40
+ const expression = unwrapExpression(ts, node);
41
+ if (ts.isStringLiteralLike(expression))
42
+ return expression.text;
43
+ const type = checker.getTypeAtLocation(expression);
44
+ if (type.isStringLiteral())
45
+ return type.value;
46
+ return;
47
+ }
48
+ function getPropertyKeyText(ts, checker, name) {
49
+ if (ts.isStringLiteralLike(name))
50
+ return name.text;
51
+ if (ts.isIdentifier(name))
52
+ return name.text;
53
+ if (ts.isNumericLiteral(name))
54
+ return name.text;
55
+ if (ts.isComputedPropertyName(name))
56
+ return getStringValue(ts, checker, name.expression);
57
+ return;
58
+ }
59
+ function resolveClassDeclaration(ts, checker, node) {
60
+ if (ts.isClassExpression(node))
61
+ return node;
62
+ let symbol = checker.getSymbolAtLocation(node);
63
+ if (!symbol)
64
+ return;
65
+ if (symbol.flags & ts.SymbolFlags.Alias)
66
+ symbol = checker.getAliasedSymbol(symbol);
67
+ const declaration = symbol.valueDeclaration ?? symbol.declarations?.[0];
68
+ return declaration && ts.isClassLike(declaration) ? declaration : undefined;
69
+ }
70
+ function getRoutesObjectLiteral(ts, classDeclaration) {
71
+ for (const member of classDeclaration.members) {
72
+ if (!ts.isPropertyDeclaration(member))
73
+ continue;
74
+ if (!member.name || !ts.isIdentifier(member.name) || member.name.text !== "routes")
75
+ continue;
76
+ if (!member.initializer)
77
+ continue;
78
+ const initializer = unwrapExpression(ts, member.initializer);
79
+ if (ts.isObjectLiteralExpression(initializer))
80
+ return initializer;
81
+ }
82
+ return;
83
+ }
84
+ function spanOf(node) {
85
+ const start = node.getStart(node.getSourceFile());
86
+ return { start, length: node.getEnd() - start };
87
+ }
88
+ function nameNodeOf(ts, declaration) {
89
+ const named = declaration;
90
+ return named.name && !ts.isComputedPropertyName(named.name) ? named.name : declaration;
91
+ }
92
+ function targetFromDeclaration(ts, declaration, name, containerName, kind) {
93
+ return {
94
+ fileName: declaration.getSourceFile().fileName,
95
+ span: spanOf(nameNodeOf(ts, declaration)),
96
+ contextSpan: spanOf(declaration),
97
+ name,
98
+ containerName,
99
+ kind
100
+ };
101
+ }
102
+ function displayNameOfClass(ts, checker, expression) {
103
+ const declaration = resolveClassDeclaration(ts, checker, expression);
104
+ if (declaration?.name)
105
+ return declaration.name.text;
106
+ return expression.getText();
107
+ }
108
+
109
+ // ide/typescript-plugin/callSite.ts
110
+ var HTTP_VERBS = new Set(["GET", "POST", "PUT", "PATCH", "DELETE"]);
111
+ var VIEW_ATTRIBUTES = new Set(["href", "to"]);
112
+ var ACTION_ATTRIBUTES = new Set(["action"]);
113
+ function findRouteQuery(ts, checker, sourceFile, position) {
114
+ const node = findStringLiteral(ts, sourceFile, position);
115
+ if (!node)
116
+ return;
117
+ if (!isRouteReferencePosition(ts, node))
118
+ return;
119
+ return {
120
+ node,
121
+ path: node.text,
122
+ allowedPaths: allowedPathsAt(ts, checker, node),
123
+ ...contextHints(ts, checker, node)
124
+ };
125
+ }
126
+ function findStringLiteral(ts, sourceFile, position) {
127
+ let found;
128
+ const visit = (node) => {
129
+ if (position < node.getFullStart() || position > node.getEnd())
130
+ return;
131
+ if (ts.isStringLiteralLike(node)) {
132
+ const start = node.getStart(sourceFile);
133
+ if (position > start && position < node.getEnd())
134
+ found = node;
135
+ }
136
+ ts.forEachChild(node, visit);
137
+ };
138
+ ts.forEachChild(sourceFile, visit);
139
+ return found;
140
+ }
141
+ function isRouteReferencePosition(ts, node) {
142
+ const parent = node.parent;
143
+ if (!parent)
144
+ return false;
145
+ if (ts.isImportDeclaration(parent) || ts.isExportDeclaration(parent))
146
+ return false;
147
+ if (ts.isImportTypeNode(parent) || ts.isExternalModuleReference(parent))
148
+ return false;
149
+ if (ts.isImportSpecifier(parent) || ts.isExportSpecifier(parent))
150
+ return false;
151
+ if ((ts.isPropertyAssignment(parent) || ts.isPropertySignature(parent) || ts.isMethodDeclaration(parent) || ts.isPropertyDeclaration(parent) || ts.isEnumMember(parent)) && parent.name === node) {
152
+ return false;
153
+ }
154
+ if (ts.isLiteralTypeNode(parent))
155
+ return false;
156
+ if (ts.isElementAccessExpression(parent) && parent.argumentExpression === node)
157
+ return false;
158
+ return true;
159
+ }
160
+ function allowedPathsAt(ts, checker, node) {
161
+ const site = argumentSite(ts, node);
162
+ if (!site)
163
+ return;
164
+ const declaration = checker.getResolvedSignature(site.call)?.getDeclaration();
165
+ if (!declaration || !ts.isFunctionLike(declaration))
166
+ return;
167
+ const parameter = declaration.parameters[site.index];
168
+ if (!parameter || parameter.dotDotDotToken)
169
+ return;
170
+ let type = checker.getTypeAtLocation(parameter);
171
+ if (site.property !== undefined) {
172
+ const symbol = type.getProperty(site.property);
173
+ if (!symbol)
174
+ return;
175
+ type = checker.getTypeOfSymbolAtLocation(symbol, parameter);
176
+ }
177
+ const constraint = checker.getBaseConstraintOfType(type) ?? type;
178
+ return stringLiteralSet(constraint);
179
+ }
180
+ function argumentSite(ts, node) {
181
+ const parent = node.parent;
182
+ if (!parent)
183
+ return;
184
+ if (ts.isCallExpression(parent) || ts.isNewExpression(parent)) {
185
+ const index2 = [...parent.arguments ?? []].indexOf(node);
186
+ return index2 < 0 ? undefined : { call: parent, index: index2 };
187
+ }
188
+ if (!ts.isPropertyAssignment(parent) || parent.initializer !== node)
189
+ return;
190
+ const property = ts.isIdentifier(parent.name) || ts.isStringLiteralLike(parent.name) ? parent.name.text : undefined;
191
+ if (property === undefined)
192
+ return;
193
+ const object = parent.parent;
194
+ if (!ts.isObjectLiteralExpression(object))
195
+ return;
196
+ const call = object.parent;
197
+ if (!call || !ts.isCallExpression(call) && !ts.isNewExpression(call))
198
+ return;
199
+ const index = [...call.arguments ?? []].indexOf(object);
200
+ return index < 0 ? undefined : { call, index, property };
201
+ }
202
+ function stringLiteralSet(type) {
203
+ const members = type.isUnion() ? type.types : [type];
204
+ const paths = new Set;
205
+ for (const member of members) {
206
+ if (!member.isStringLiteral())
207
+ return;
208
+ paths.add(member.value);
209
+ }
210
+ return paths.size > 0 ? paths : undefined;
211
+ }
212
+ function contextHints(ts, checker, node) {
213
+ const attribute = enclosingJsxAttribute(ts, node);
214
+ if (attribute) {
215
+ const name = ts.isIdentifier(attribute.name) ? attribute.name.text : attribute.name.getText();
216
+ if (VIEW_ATTRIBUTES.has(name))
217
+ return { prefer: "view" };
218
+ if (ACTION_ATTRIBUTES.has(name)) {
219
+ return { prefer: "api", verb: siblingMethodVerb(ts, checker, attribute) ?? "POST" };
220
+ }
221
+ return {};
222
+ }
223
+ const call = node.parent;
224
+ if (call && ts.isCallExpression(call)) {
225
+ const index = call.arguments.indexOf(node);
226
+ const previous = index > 0 ? call.arguments[index - 1] : undefined;
227
+ const value = getStringValue(ts, checker, previous)?.toUpperCase();
228
+ if (value && HTTP_VERBS.has(value))
229
+ return { verb: value, prefer: "api" };
230
+ }
231
+ return {};
232
+ }
233
+ function enclosingJsxAttribute(ts, node) {
234
+ const parent = node.parent;
235
+ if (!parent)
236
+ return;
237
+ if (ts.isJsxAttribute(parent))
238
+ return parent;
239
+ if (ts.isJsxExpression(parent) && parent.parent && ts.isJsxAttribute(parent.parent)) {
240
+ return parent.parent;
241
+ }
242
+ return;
243
+ }
244
+ function siblingMethodVerb(ts, checker, attribute) {
245
+ const attributes = attribute.parent;
246
+ if (!attributes || !ts.isJsxAttributes(attributes))
247
+ return;
248
+ for (const sibling of attributes.properties) {
249
+ if (!ts.isJsxAttribute(sibling))
250
+ continue;
251
+ const name = ts.isIdentifier(sibling.name) ? sibling.name.text : sibling.name.getText();
252
+ if (name !== "method" || !sibling.initializer)
253
+ continue;
254
+ const initializer = ts.isJsxExpression(sibling.initializer) ? sibling.initializer.expression : sibling.initializer;
255
+ const value = getStringValue(ts, checker, initializer)?.toUpperCase();
256
+ if (value && HTTP_VERBS.has(value))
257
+ return value;
258
+ }
259
+ return;
260
+ }
261
+
262
+ // ide/typescript-plugin/lookup.ts
263
+ var VERB_ORDER = ["GET", "POST", "PUT", "PATCH", "DELETE"];
264
+ var indexes = new WeakMap;
265
+ function indexOf(table) {
266
+ const cached = indexes.get(table);
267
+ if (cached)
268
+ return cached;
269
+ const knownPaths = new Set;
270
+ const pathsByVerb = new Map;
271
+ for (const entries of table.api.values()) {
272
+ for (const entry of entries) {
273
+ let paths = pathsByVerb.get(entry.verb);
274
+ if (!paths)
275
+ pathsByVerb.set(entry.verb, paths = new Set);
276
+ paths.add(entry.path);
277
+ knownPaths.add(entry.path);
278
+ }
279
+ }
280
+ const viewPaths = new Set;
281
+ for (const entries of table.views.values()) {
282
+ for (const entry of entries) {
283
+ viewPaths.add(entry.path);
284
+ knownPaths.add(entry.path);
285
+ }
286
+ }
287
+ const index = { pathsByVerb, viewPaths, knownPaths };
288
+ indexes.set(table, index);
289
+ return index;
290
+ }
291
+ function lookupRoute(table, query) {
292
+ let candidates = [
293
+ ...(table.api.get(query.path) ?? []).map((entry) => ({ kind: "api", entry })),
294
+ ...(table.views.get(query.path) ?? []).map((entry) => ({ kind: "view", entry }))
295
+ ];
296
+ if (candidates.length === 0)
297
+ return [];
298
+ if (query.prefer) {
299
+ candidates = narrow(candidates, (candidate) => candidate.kind === query.prefer);
300
+ }
301
+ if (query.verb) {
302
+ candidates = narrow(candidates, (candidate) => candidate.kind === "api" && candidate.entry.verb === query.verb);
303
+ }
304
+ if (query.allowedPaths) {
305
+ const { pathsByVerb, viewPaths, knownPaths } = indexOf(table);
306
+ const allowed = intersect(query.allowedPaths, knownPaths);
307
+ if (allowed.size > 0) {
308
+ candidates = narrow(candidates, (candidate) => candidate.kind === "api" ? isSubset(allowed, pathsByVerb.get(candidate.entry.verb)) : isSubset(allowed, viewPaths));
309
+ }
310
+ }
311
+ candidates.sort(compareCandidates);
312
+ return candidates.map((candidate) => ({ candidate, targets: candidate.entry.targets }));
313
+ }
314
+ function narrow(candidates, predicate) {
315
+ const kept = candidates.filter(predicate);
316
+ return kept.length > 0 ? kept : candidates;
317
+ }
318
+ function isSubset(subset, superset) {
319
+ if (!superset)
320
+ return false;
321
+ for (const value of subset) {
322
+ if (!superset.has(value))
323
+ return false;
324
+ }
325
+ return true;
326
+ }
327
+ function intersect(subset, universe) {
328
+ const kept = new Set;
329
+ for (const value of subset) {
330
+ if (universe.has(value))
331
+ kept.add(value);
332
+ }
333
+ return kept;
334
+ }
335
+ function compareCandidates(a, b) {
336
+ if (a.kind !== b.kind)
337
+ return a.kind === "api" ? -1 : 1;
338
+ if (a.kind === "api" && b.kind === "api") {
339
+ return VERB_ORDER.indexOf(a.entry.verb) - VERB_ORDER.indexOf(b.entry.verb);
340
+ }
341
+ const rank = (kind) => kind === "view" ? 0 : 1;
342
+ return rank(a.entry.kind) - rank(b.entry.kind);
343
+ }
344
+ function describeCandidate(candidate) {
345
+ return candidate.kind === "api" ? `${candidate.entry.verb} ${candidate.entry.path}` : `${candidate.entry.kind} ${candidate.entry.path}`;
346
+ }
347
+ function describeTarget(target) {
348
+ switch (target.kind) {
349
+ case "controller-method":
350
+ return `${target.containerName}.${target.name}()`;
351
+ case "inline-handler":
352
+ return "inline handler";
353
+ case "view-component":
354
+ return `${target.name} component`;
355
+ case "route-entry":
356
+ return `${target.containerName} routes entry`;
357
+ }
358
+ }
359
+
360
+ // ide/typescript-plugin/entryPoints.ts
361
+ var RPC_INTERFACES = {
362
+ api: { interfaceName: "RPC" },
363
+ view: { interfaceName: "ViewRPC" }
364
+ };
365
+ var CONFIG_HELPER = "defineRouteConfig";
366
+ var CONFIG_MODULE = "gemi/services";
367
+ var CLIENT_MODULE = "gemi/client";
368
+ var FALLBACK_API_ROUTER = "app/http/routes/api";
369
+ var FALLBACK_VIEW_ROUTER = "app/http/routes/view";
370
+ function findRootRouters(ts, program, projectRoot) {
371
+ const checker = program.getTypeChecker();
372
+ const result = { api: [], view: [], dependencies: [], diagnostics: [] };
373
+ const seen = new Set;
374
+ for (const kind of ["api", "view"]) {
375
+ const { interfaceName } = RPC_INTERFACES[kind];
376
+ for (const declaration of findInterfaceDeclarations(ts, checker, program, interfaceName)) {
377
+ result.dependencies.push(declaration.getSourceFile().fileName);
378
+ for (const mount of readMounts(ts, checker, declaration)) {
379
+ const fileName = mount.declaration.getSourceFile().fileName;
380
+ const key = `${kind}\x00${mount.prefix}\x00${fileName}\x00${mount.declaration.pos}`;
381
+ if (seen.has(key))
382
+ continue;
383
+ seen.add(key);
384
+ result[kind].push(mount);
385
+ result.dependencies.push(fileName);
386
+ }
387
+ }
388
+ }
389
+ const hasAppMount = (kind) => result[kind].some((mount) => isApplicationFile(mount.declaration.getSourceFile().fileName, projectRoot));
390
+ if (hasAppMount("api") || hasAppMount("view"))
391
+ return result;
392
+ result.diagnostics.push("the RPC / ViewRPC augmentation names none of this project's routers — falling back " + "to the app's route config. Check that gemi/client is imported and that " + `${projectRoot}/${FALLBACK_API_ROUTER}.ts typechecks, so route types and route jumps agree.`);
393
+ const config = findRouteConfigCall(ts, program);
394
+ if (config) {
395
+ result.dependencies.push(config.getSourceFile().fileName);
396
+ const object = unwrapExpression(ts, config.arguments[0] ?? config);
397
+ if (ts.isObjectLiteralExpression(object)) {
398
+ for (const kind of ["api", "view"]) {
399
+ const declaration = readRootRouter(ts, checker, object, kind);
400
+ if (!declaration)
401
+ continue;
402
+ result[kind].push({ declaration, prefix: "" });
403
+ result.dependencies.push(declaration.getSourceFile().fileName);
404
+ }
405
+ }
406
+ }
407
+ if (!hasAppMount("api")) {
408
+ const declaration = findConventionalRouter(ts, program, projectRoot, FALLBACK_API_ROUTER);
409
+ if (declaration) {
410
+ result.api.push({ declaration, prefix: "" });
411
+ result.dependencies.push(declaration.getSourceFile().fileName);
412
+ }
413
+ }
414
+ if (!hasAppMount("view")) {
415
+ const declaration = findConventionalRouter(ts, program, projectRoot, FALLBACK_VIEW_ROUTER);
416
+ if (declaration) {
417
+ result.view.push({ declaration, prefix: "" });
418
+ result.dependencies.push(declaration.getSourceFile().fileName);
419
+ }
420
+ }
421
+ if (!hasAppMount("api") && !hasAppMount("view")) {
422
+ result.diagnostics.push(`no application routers found: no ${CONFIG_HELPER}() call and nothing at ${projectRoot}/${FALLBACK_API_ROUTER}`);
423
+ }
424
+ return result;
425
+ }
426
+ function isApplicationFile(fileName, projectRoot) {
427
+ return fileName.startsWith(`${projectRoot}/`) && !fileName.includes("/node_modules/");
428
+ }
429
+ function findInterfaceDeclarations(ts, checker, program, name) {
430
+ const fromModule = findClientModuleSymbol(ts, checker, program);
431
+ if (fromModule) {
432
+ const exported = checker.getExportsOfModule(fromModule).find((symbol) => symbol.name === name);
433
+ const resolved = exported && exported.flags & ts.SymbolFlags.Alias ? checker.getAliasedSymbol(exported) : exported;
434
+ const declarations = resolved?.declarations?.filter((declaration) => ts.isInterfaceDeclaration(declaration));
435
+ if (declarations && declarations.length > 0)
436
+ return declarations;
437
+ }
438
+ for (const sourceFile of program.getSourceFiles()) {
439
+ if (sourceFile.fileName.includes("/node_modules/"))
440
+ continue;
441
+ const local = findInterfaceIn(ts, sourceFile, name);
442
+ if (!local)
443
+ continue;
444
+ const symbol = checker.getSymbolAtLocation(local.name);
445
+ const declarations = symbol?.declarations?.filter((declaration) => ts.isInterfaceDeclaration(declaration));
446
+ return declarations && declarations.length > 0 ? declarations : [local];
447
+ }
448
+ return [];
449
+ }
450
+ function findClientModuleSymbol(ts, checker, program) {
451
+ for (const sourceFile of program.getSourceFiles()) {
452
+ if (sourceFile.fileName.includes("/node_modules/"))
453
+ continue;
454
+ for (const statement of sourceFile.statements) {
455
+ const reference = clientModuleReference(ts, statement);
456
+ if (!reference)
457
+ continue;
458
+ const symbol = checker.getSymbolAtLocation(reference);
459
+ if (symbol)
460
+ return symbol;
461
+ }
462
+ }
463
+ return;
464
+ }
465
+ function clientModuleReference(ts, statement) {
466
+ if (ts.isImportDeclaration(statement) || ts.isExportDeclaration(statement)) {
467
+ const specifier = statement.moduleSpecifier;
468
+ if (specifier && ts.isStringLiteralLike(specifier) && specifier.text === CLIENT_MODULE) {
469
+ return specifier;
470
+ }
471
+ return;
472
+ }
473
+ if (ts.isModuleDeclaration(statement) && ts.isStringLiteralLike(statement.name) && statement.name.text === CLIENT_MODULE) {
474
+ return statement.name;
475
+ }
476
+ return;
477
+ }
478
+ function findInterfaceIn(ts, sourceFile, name) {
479
+ let found;
480
+ const visit = (node) => {
481
+ if (found)
482
+ return;
483
+ if (ts.isInterfaceDeclaration(node) && node.name.text === name) {
484
+ found = node;
485
+ return;
486
+ }
487
+ if (ts.isSourceFile(node) || ts.isModuleDeclaration(node) || ts.isModuleBlock(node)) {
488
+ ts.forEachChild(node, visit);
489
+ }
490
+ };
491
+ visit(sourceFile);
492
+ return found;
493
+ }
494
+ function readMounts(ts, checker, declaration) {
495
+ const mounts = [];
496
+ for (const clause of declaration.heritageClauses ?? []) {
497
+ for (const type of clause.types) {
498
+ let router;
499
+ let prefix = "";
500
+ for (const argument of type.typeArguments ?? []) {
501
+ if (!router) {
502
+ const resolved = resolveClassFromTypeNode(ts, checker, argument);
503
+ if (resolved) {
504
+ router = resolved;
505
+ continue;
506
+ }
507
+ }
508
+ if (!prefix)
509
+ prefix = readPrefix(ts, checker, argument);
510
+ }
511
+ if (router)
512
+ mounts.push({ declaration: router, prefix });
513
+ }
514
+ }
515
+ return mounts;
516
+ }
517
+ function resolveClassFromTypeNode(ts, checker, node) {
518
+ if (!ts.isTypeReferenceNode(node))
519
+ return;
520
+ const name = ts.isQualifiedName(node.typeName) ? node.typeName.right : node.typeName;
521
+ return resolveClassDeclaration(ts, checker, name);
522
+ }
523
+ function readPrefix(ts, checker, node) {
524
+ if (!node)
525
+ return "";
526
+ if (ts.isLiteralTypeNode(node) && ts.isStringLiteral(node.literal))
527
+ return node.literal.text;
528
+ const type = checker.getTypeFromTypeNode(node);
529
+ return type.isStringLiteral() ? type.value : "";
530
+ }
531
+ function findRouteConfigCall(ts, program) {
532
+ for (const sourceFile of program.getSourceFiles()) {
533
+ if (sourceFile.isDeclarationFile)
534
+ continue;
535
+ if (sourceFile.fileName.includes("/node_modules/"))
536
+ continue;
537
+ const localName = importedNameOf(ts, sourceFile);
538
+ if (!localName)
539
+ continue;
540
+ let found;
541
+ const visit = (node) => {
542
+ if (found)
543
+ return;
544
+ if (ts.isCallExpression(node) && ts.isIdentifier(node.expression) && node.expression.text === localName) {
545
+ found = node;
546
+ return;
547
+ }
548
+ ts.forEachChild(node, visit);
549
+ };
550
+ ts.forEachChild(sourceFile, visit);
551
+ if (found)
552
+ return found;
553
+ }
554
+ return;
555
+ }
556
+ function importedNameOf(ts, sourceFile) {
557
+ for (const statement of sourceFile.statements) {
558
+ if (!ts.isImportDeclaration(statement))
559
+ continue;
560
+ const specifier = statement.moduleSpecifier;
561
+ if (!ts.isStringLiteralLike(specifier) || specifier.text !== CONFIG_MODULE)
562
+ continue;
563
+ const bindings = statement.importClause?.namedBindings;
564
+ if (!bindings || !ts.isNamedImports(bindings))
565
+ continue;
566
+ for (const element of bindings.elements) {
567
+ const imported = element.propertyName?.text ?? element.name.text;
568
+ if (imported === CONFIG_HELPER)
569
+ return element.name.text;
570
+ }
571
+ }
572
+ return;
573
+ }
574
+ function readRootRouter(ts, checker, config, section) {
575
+ const sectionValue = getPropertyValue(ts, config, section);
576
+ if (!sectionValue || !ts.isObjectLiteralExpression(sectionValue))
577
+ return;
578
+ const rootRouter = getPropertyValue(ts, sectionValue, "rootRouter");
579
+ return rootRouter ? resolveClassDeclaration(ts, checker, rootRouter) : undefined;
580
+ }
581
+ function getPropertyValue(ts, object, name) {
582
+ for (const property of object.properties) {
583
+ if (ts.isPropertyAssignment(property)) {
584
+ const key = property.name;
585
+ const text = ts.isIdentifier(key) || ts.isStringLiteralLike(key) ? key.text : undefined;
586
+ if (text === name)
587
+ return unwrapExpression(ts, property.initializer);
588
+ } else if (ts.isShorthandPropertyAssignment(property) && property.name.text === name) {
589
+ return property.name;
590
+ }
591
+ }
592
+ return;
593
+ }
594
+ function findConventionalRouter(ts, program, projectRoot, relativePath) {
595
+ const checker = program.getTypeChecker();
596
+ for (const extension of [".ts", ".tsx"]) {
597
+ const sourceFile = program.getSourceFile(`${projectRoot}/${relativePath}${extension}`);
598
+ if (!sourceFile)
599
+ continue;
600
+ const moduleSymbol = checker.getSymbolAtLocation(sourceFile);
601
+ if (!moduleSymbol)
602
+ continue;
603
+ for (const exported of checker.getExportsOfModule(moduleSymbol)) {
604
+ if (exported.name !== "default")
605
+ continue;
606
+ const resolved = exported.flags & ts.SymbolFlags.Alias ? checker.getAliasedSymbol(exported) : exported;
607
+ const declaration = resolved.valueDeclaration ?? resolved.declarations?.[0];
608
+ if (declaration && ts.isClassLike(declaration))
609
+ return declaration;
610
+ }
611
+ }
612
+ return;
613
+ }
614
+
615
+ // ide/typescript-plugin/routePath.ts
616
+ function removeDoubleSlash(input) {
617
+ const at = input.indexOf("//");
618
+ if (at === -1)
619
+ return input;
620
+ return removeDoubleSlash(`${input.slice(0, at)}/${input.slice(at + 2)}`);
621
+ }
622
+ function removeGroupPrefix(input) {
623
+ const open = input.indexOf("(");
624
+ if (open === -1)
625
+ return input;
626
+ const close = input.indexOf(")", open + 1);
627
+ if (close === -1)
628
+ return input;
629
+ return removeDoubleSlash(`${input.slice(0, open)}${input.slice(close + 1)}`);
630
+ }
631
+ function parsePrefixAndKey(prefix, key) {
632
+ const joined = `${prefix}${key}`;
633
+ if (joined === "//")
634
+ return "/";
635
+ const doubleSlash = joined.indexOf("//");
636
+ if (doubleSlash !== -1) {
637
+ return `${removeGroupPrefix(joined.slice(0, doubleSlash))}/${removeGroupPrefix(joined.slice(doubleSlash + 2))}`;
638
+ }
639
+ if (joined.endsWith("/")) {
640
+ const first = joined.indexOf("/");
641
+ if (first !== -1 && first < joined.length - 1) {
642
+ return `${removeGroupPrefix(joined.slice(0, first))}/${removeGroupPrefix(joined.slice(first + 1, -1))}`;
643
+ }
644
+ }
645
+ return removeGroupPrefix(joined);
646
+ }
647
+ function removeTrailingId(input) {
648
+ const at = input.indexOf("/:");
649
+ if (at === -1)
650
+ return input;
651
+ const head = input.slice(0, at);
652
+ const tail = input.slice(at + 2);
653
+ if (tail.includes("/:"))
654
+ return `${head}/:${removeTrailingId(tail)}`;
655
+ if (head.startsWith("/:"))
656
+ return "X";
657
+ return head;
658
+ }
659
+ function joinHandlerMapKey(prefix, key) {
660
+ return `${prefix}${key === "/" ? "" : key}`;
661
+ }
662
+
663
+ // ide/typescript-plugin/routeTable.ts
664
+ var VERBS = {
665
+ get: "GET",
666
+ post: "POST",
667
+ put: "PUT",
668
+ patch: "PATCH",
669
+ delete: "DELETE"
670
+ };
671
+ var RESOURCE_ROUTES = [
672
+ { method: "list", verb: "GET", scope: "collection" },
673
+ { method: "store", verb: "POST", scope: "collection" },
674
+ { method: "show", verb: "GET", scope: "member" },
675
+ { method: "update", verb: "PUT", scope: "member" },
676
+ { method: "delete", verb: "DELETE", scope: "member" }
677
+ ];
678
+ var VIEW_EXTENSIONS = [".tsx", ".jsx", ".ts", ".js"];
679
+ function buildRouteTable(ts, program, options) {
680
+ return new RouteTableBuilder(ts, program, options).build();
681
+ }
682
+
683
+ class RouteTableBuilder {
684
+ ts;
685
+ program;
686
+ options;
687
+ checker;
688
+ api = new Map;
689
+ views = new Map;
690
+ dependencies = new Set;
691
+ diagnostics = [];
692
+ constructor(ts, program, options) {
693
+ this.ts = ts;
694
+ this.program = program;
695
+ this.options = options;
696
+ this.checker = program.getTypeChecker();
697
+ }
698
+ build() {
699
+ const roots = findRootRouters(this.ts, this.program, this.options.projectRoot);
700
+ for (const dependency of roots.dependencies)
701
+ this.dependencies.add(dependency);
702
+ this.diagnostics.push(...roots.diagnostics);
703
+ for (const mount of roots.api)
704
+ this.walkApiRouter(mount.declaration, mount.prefix, []);
705
+ for (const mount of roots.view)
706
+ this.walkViewRouter(mount.declaration, mount.prefix, []);
707
+ return {
708
+ api: this.api,
709
+ views: this.views,
710
+ dependencies: [...this.dependencies],
711
+ diagnostics: this.diagnostics
712
+ };
713
+ }
714
+ walkApiRouter(classDeclaration, prefix, stack) {
715
+ const ts = this.ts;
716
+ const routes = getRoutesObjectLiteral(ts, classDeclaration);
717
+ if (!routes)
718
+ return;
719
+ this.dependencies.add(classDeclaration.getSourceFile().fileName);
720
+ for (const property of routes.properties) {
721
+ if (!ts.isPropertyAssignment(property)) {
722
+ this.noteUnreadableEntry(property, prefix, classDeclaration);
723
+ continue;
724
+ }
725
+ const key = getPropertyKeyText(ts, this.checker, property.name);
726
+ if (key === undefined)
727
+ continue;
728
+ const value = unwrapExpression(ts, property.initializer);
729
+ const nested = resolveClassDeclaration(ts, this.checker, value);
730
+ if (nested && getRoutesObjectLiteral(ts, nested)) {
731
+ if (stack.includes(nested)) {
732
+ this.diagnostics.push(`router cycle at ${parsePrefixAndKey(prefix, key)}; stopped descending`);
733
+ continue;
734
+ }
735
+ this.walkApiRouter(nested, parsePrefixAndKey(prefix, key), [...stack, nested]);
736
+ continue;
737
+ }
738
+ if (ts.isObjectLiteralExpression(value)) {
739
+ const path = joinHandlerMapKey(prefix, key);
740
+ for (const inner of value.properties) {
741
+ if (!ts.isPropertyAssignment(inner))
742
+ continue;
743
+ this.addApiRoute(path, unwrapExpression(ts, inner.initializer), inner, classDeclaration);
744
+ }
745
+ continue;
746
+ }
747
+ this.addApiRoute(parsePrefixAndKey(prefix, key), value, property, classDeclaration);
748
+ }
749
+ }
750
+ addApiRoute(path, value, entryNode, router) {
751
+ const call = getThisCall(this.ts, unwrapBuilderChain(this.ts, value));
752
+ if (!call)
753
+ return;
754
+ const fallback = this.routeEntryTarget(entryNode, router);
755
+ if (call.method === "resource") {
756
+ const controller = call.args[0];
757
+ const collection = removeTrailingId(path);
758
+ for (const { method, verb: verb2, scope } of RESOURCE_ROUTES) {
759
+ const target = controller ? this.controllerMethodTarget(controller, method) : undefined;
760
+ this.pushApi({
761
+ path: scope === "collection" ? collection : path,
762
+ verb: verb2,
763
+ inRpc: true,
764
+ targets: [target ?? fallback]
765
+ });
766
+ }
767
+ return;
768
+ }
769
+ const verb = VERBS[call.method];
770
+ if (verb) {
771
+ this.pushApi({ path, verb, inRpc: true, targets: this.handlerTargets(call.args, fallback) });
772
+ return;
773
+ }
774
+ if (call.method === "file" || call.method === "stream") {
775
+ this.pushApi({
776
+ path,
777
+ verb: "GET",
778
+ inRpc: false,
779
+ targets: this.handlerTargets(call.args, fallback)
780
+ });
781
+ return;
782
+ }
783
+ if (call.method === "proxy") {
784
+ this.pushApi({ path, verb: "GET", inRpc: false, targets: [fallback] });
785
+ }
786
+ }
787
+ pushApi(entry) {
788
+ const existing = this.api.get(entry.path);
789
+ if (existing)
790
+ existing.push(entry);
791
+ else
792
+ this.api.set(entry.path, [entry]);
793
+ }
794
+ walkViewRouter(classDeclaration, prefix, stack) {
795
+ const routes = getRoutesObjectLiteral(this.ts, classDeclaration);
796
+ if (!routes)
797
+ return;
798
+ this.dependencies.add(classDeclaration.getSourceFile().fileName);
799
+ this.walkViewRoutes(routes, prefix, stack, classDeclaration);
800
+ }
801
+ walkViewRoutes(routes, prefix, stack, router) {
802
+ const ts = this.ts;
803
+ for (const property of routes.properties) {
804
+ if (!ts.isPropertyAssignment(property)) {
805
+ this.noteUnreadableEntry(property, prefix, router);
806
+ continue;
807
+ }
808
+ const key = getPropertyKeyText(ts, this.checker, property.name);
809
+ if (key === undefined)
810
+ continue;
811
+ const value = unwrapExpression(ts, property.initializer);
812
+ const path = parsePrefixAndKey(prefix, key);
813
+ const nested = resolveClassDeclaration(ts, this.checker, value);
814
+ if (nested && getRoutesObjectLiteral(ts, nested)) {
815
+ if (stack.includes(nested)) {
816
+ this.diagnostics.push(`view router cycle at ${path}; stopped descending`);
817
+ continue;
818
+ }
819
+ this.walkViewRouter(nested, path, [...stack, nested]);
820
+ continue;
821
+ }
822
+ const call = getThisCall(ts, unwrapBuilderChain(ts, value));
823
+ if (!call)
824
+ continue;
825
+ const fallback = this.routeEntryTarget(property, router);
826
+ switch (call.method) {
827
+ case "view":
828
+ this.pushView({
829
+ path,
830
+ kind: "view",
831
+ inRpc: true,
832
+ targets: this.viewTargets(call.args[0], call.args[1], fallback)
833
+ });
834
+ break;
835
+ case "redirect":
836
+ this.pushView({
837
+ path,
838
+ kind: "view",
839
+ inRpc: true,
840
+ targets: this.viewTargets(undefined, call.args[0], fallback)
841
+ });
842
+ break;
843
+ case "file":
844
+ this.pushView({
845
+ path,
846
+ kind: "view",
847
+ inRpc: false,
848
+ targets: this.viewTargets(undefined, call.args[0], fallback)
849
+ });
850
+ break;
851
+ case "layout": {
852
+ const second = call.args[1] ? unwrapExpression(ts, call.args[1]) : undefined;
853
+ const third = call.args[2] ? unwrapExpression(ts, call.args[2]) : undefined;
854
+ const children = third && ts.isObjectLiteralExpression(third) ? third : second && ts.isObjectLiteralExpression(second) ? second : undefined;
855
+ const handler = children === second ? undefined : second;
856
+ this.pushView({
857
+ path,
858
+ kind: "layout",
859
+ inRpc: true,
860
+ targets: this.viewTargets(call.args[0], handler, fallback)
861
+ });
862
+ if (children)
863
+ this.walkViewRoutes(children, path, stack, router);
864
+ break;
865
+ }
866
+ }
867
+ }
868
+ }
869
+ pushView(entry) {
870
+ const existing = this.views.get(entry.path);
871
+ if (existing)
872
+ existing.push(entry);
873
+ else
874
+ this.views.set(entry.path, [entry]);
875
+ }
876
+ viewTargets(viewPath, handler, fallback) {
877
+ const targets = [];
878
+ const component = viewPath ? this.viewComponentTarget(viewPath) : undefined;
879
+ if (component)
880
+ targets.push(component);
881
+ if (handler)
882
+ targets.push(...this.handlerTargets([handler], fallback, { silent: true }));
883
+ return targets.length > 0 ? targets : [fallback];
884
+ }
885
+ viewComponentTarget(viewPath) {
886
+ const ts = this.ts;
887
+ const relative = getStringValue(ts, this.checker, viewPath);
888
+ if (!relative)
889
+ return;
890
+ for (const extension of VIEW_EXTENSIONS) {
891
+ const fileName = `${this.options.viewsDir}/${relative}${extension}`;
892
+ const sourceFile = this.program.getSourceFile(fileName);
893
+ if (sourceFile) {
894
+ this.dependencies.add(fileName);
895
+ const exported = this.defaultExportDeclaration(sourceFile);
896
+ if (exported) {
897
+ return targetFromDeclaration(ts, exported, relative, "view", "view-component");
898
+ }
899
+ return {
900
+ fileName,
901
+ span: { start: 0, length: 0 },
902
+ name: relative,
903
+ containerName: "view",
904
+ kind: "view-component"
905
+ };
906
+ }
907
+ if (this.options.fileExists(fileName)) {
908
+ return {
909
+ fileName,
910
+ span: { start: 0, length: 0 },
911
+ name: relative,
912
+ containerName: "view",
913
+ kind: "view-component"
914
+ };
915
+ }
916
+ }
917
+ return;
918
+ }
919
+ defaultExportDeclaration(sourceFile) {
920
+ const moduleSymbol = this.checker.getSymbolAtLocation(sourceFile);
921
+ if (!moduleSymbol)
922
+ return;
923
+ for (const exported of this.checker.getExportsOfModule(moduleSymbol)) {
924
+ if (exported.name !== "default")
925
+ continue;
926
+ const resolved = exported.flags & this.ts.SymbolFlags.Alias ? this.checker.getAliasedSymbol(exported) : exported;
927
+ const declaration = resolved.valueDeclaration ?? resolved.declarations?.[0];
928
+ if (declaration)
929
+ return declaration;
930
+ }
931
+ return;
932
+ }
933
+ handlerTargets(args, fallback, options = {}) {
934
+ const ts = this.ts;
935
+ const first = args[0] ? unwrapExpression(ts, args[0]) : undefined;
936
+ if (!first)
937
+ return options.silent ? [] : [fallback];
938
+ if (ts.isArrayLiteralExpression(first)) {
939
+ const [controller, method] = first.elements;
940
+ const name = getStringValue(ts, this.checker, method);
941
+ const target = controller && name ? this.controllerMethodTarget(controller, name) : undefined;
942
+ return [target ?? fallback];
943
+ }
944
+ if (ts.isFunctionExpression(first) || ts.isArrowFunction(first)) {
945
+ return [
946
+ {
947
+ fileName: first.getSourceFile().fileName,
948
+ span: spanOf(first),
949
+ contextSpan: spanOf(first),
950
+ name: "handler",
951
+ containerName: "",
952
+ kind: "inline-handler"
953
+ }
954
+ ];
955
+ }
956
+ const methodName = getStringValue(ts, this.checker, args[1]);
957
+ if (methodName) {
958
+ const target = this.controllerMethodTarget(first, methodName);
959
+ if (target)
960
+ return [target];
961
+ }
962
+ return options.silent ? [] : [fallback];
963
+ }
964
+ controllerMethodTarget(controller, methodName) {
965
+ const type = this.checker.getTypeAtLocation(controller);
966
+ const instance = type.getConstructSignatures()[0]?.getReturnType();
967
+ const property = instance?.getProperty(methodName);
968
+ const declaration = property?.declarations?.[0];
969
+ if (!declaration)
970
+ return;
971
+ this.dependencies.add(declaration.getSourceFile().fileName);
972
+ return targetFromDeclaration(this.ts, declaration, methodName, displayNameOfClass(this.ts, this.checker, controller), "controller-method");
973
+ }
974
+ noteUnreadableEntry(property, prefix, router) {
975
+ const ts = this.ts;
976
+ const what = ts.isSpreadAssignment(property) ? `the spread \`...${property.expression.getText()}\`` : ts.isShorthandPropertyAssignment(property) ? `the shorthand entry \`${property.name.text}\`` : "an entry";
977
+ this.diagnostics.push(`${router.name?.text ?? "router"} mounted at ${prefix || "/"}: ${what} in \`routes\` ` + `cannot be read statically — the routes it holds are typed but not jumpable`);
978
+ }
979
+ routeEntryTarget(property, router) {
980
+ return {
981
+ fileName: property.getSourceFile().fileName,
982
+ span: spanOf(property.name),
983
+ contextSpan: spanOf(property),
984
+ name: getPropertyKeyText(this.ts, this.checker, property.name) ?? "route",
985
+ containerName: router.name?.text ?? "router",
986
+ kind: "route-entry"
987
+ };
988
+ }
989
+ }
990
+
991
+ // ide/typescript-plugin/plugin.ts
992
+ function decorateLanguageService(host) {
993
+ const { ts, languageService } = host;
994
+ const routes = createRouteTableCache(host);
995
+ const forwarded = Object.create(null);
996
+ const source = languageService;
997
+ for (const key of Object.keys(source)) {
998
+ const member = source[key];
999
+ if (typeof member !== "function")
1000
+ continue;
1001
+ forwarded[key] = (...args) => member.apply(languageService, args);
1002
+ }
1003
+ const proxy = forwarded;
1004
+ proxy.getDefinitionAndBoundSpan = (fileName, position) => {
1005
+ const matched = match(fileName, position);
1006
+ if (!matched)
1007
+ return languageService.getDefinitionAndBoundSpan(fileName, position);
1008
+ const definitions = toDefinitions(ts, matched.matches);
1009
+ if (definitions.length === 0) {
1010
+ return languageService.getDefinitionAndBoundSpan(fileName, position);
1011
+ }
1012
+ return { textSpan: matched.textSpan, definitions };
1013
+ };
1014
+ proxy.getDefinitionAtPosition = (fileName, position) => {
1015
+ const matched = match(fileName, position);
1016
+ if (!matched)
1017
+ return languageService.getDefinitionAtPosition(fileName, position);
1018
+ const definitions = toDefinitions(ts, matched.matches);
1019
+ return definitions.length > 0 ? definitions : languageService.getDefinitionAtPosition(fileName, position);
1020
+ };
1021
+ proxy.getQuickInfoAtPosition = (fileName, position) => {
1022
+ const original = languageService.getQuickInfoAtPosition(fileName, position);
1023
+ const matched = match(fileName, position);
1024
+ if (!matched)
1025
+ return original;
1026
+ const { heading, documentation } = describeMatches(host, matched.matches);
1027
+ if (original) {
1028
+ return {
1029
+ ...original,
1030
+ documentation: [...original.documentation ?? [], ...documentation]
1031
+ };
1032
+ }
1033
+ return {
1034
+ kind: ts.ScriptElementKind.string,
1035
+ kindModifiers: "",
1036
+ textSpan: matched.textSpan,
1037
+ displayParts: heading,
1038
+ documentation
1039
+ };
1040
+ };
1041
+ return proxy;
1042
+ function match(fileName, position) {
1043
+ try {
1044
+ const program = languageService.getProgram();
1045
+ const sourceFile = program?.getSourceFile(fileName);
1046
+ if (!program || !sourceFile)
1047
+ return;
1048
+ const query = findRouteQuery(ts, program.getTypeChecker(), sourceFile, position);
1049
+ if (!query)
1050
+ return;
1051
+ const matches = lookupRoute(routes.get(program), query);
1052
+ if (matches.length === 0)
1053
+ return;
1054
+ const start = query.node.getStart(sourceFile) + 1;
1055
+ return { matches, textSpan: { start, length: query.node.text.length } };
1056
+ } catch (error) {
1057
+ host.log(`route lookup failed at ${fileName}:${position} — ${describeError(error)}`);
1058
+ return;
1059
+ }
1060
+ }
1061
+ }
1062
+ function describeError(error) {
1063
+ return error instanceof Error ? `${error.message}
1064
+ ${error.stack ?? ""}` : String(error);
1065
+ }
1066
+ function toDefinitions(ts, matches) {
1067
+ const definitions = [];
1068
+ const seen = new Set;
1069
+ for (const { candidate, targets } of matches) {
1070
+ for (const target of targets) {
1071
+ const key = `${target.fileName}:${target.span.start}`;
1072
+ if (seen.has(key))
1073
+ continue;
1074
+ seen.add(key);
1075
+ definitions.push({
1076
+ fileName: target.fileName,
1077
+ textSpan: toTextSpan(target.span),
1078
+ contextSpan: target.contextSpan ? toTextSpan(target.contextSpan) : undefined,
1079
+ kind: scriptElementKind(ts, target.kind),
1080
+ name: target.name,
1081
+ containerName: target.containerName || describeCandidate(candidate),
1082
+ containerKind: ts.ScriptElementKind.unknown
1083
+ });
1084
+ }
1085
+ }
1086
+ return definitions;
1087
+ }
1088
+ function describeMatches(host, matches) {
1089
+ const lines = [];
1090
+ for (const { candidate, targets } of matches) {
1091
+ lines.push(describeCandidate(candidate));
1092
+ for (const target of targets) {
1093
+ lines.push(` → ${describeTarget(target)} · ${location(host, target)}`);
1094
+ }
1095
+ }
1096
+ return {
1097
+ heading: [
1098
+ {
1099
+ text: matches.map(({ candidate }) => describeCandidate(candidate)).join(", "),
1100
+ kind: "text"
1101
+ }
1102
+ ],
1103
+ documentation: [{ text: lines.join(`
1104
+ `), kind: "text" }]
1105
+ };
1106
+ }
1107
+ function location(host, target) {
1108
+ const relative = target.fileName.startsWith(`${host.projectRoot}/`) ? target.fileName.slice(host.projectRoot.length + 1) : target.fileName;
1109
+ const sourceFile = host.languageService.getProgram()?.getSourceFile(target.fileName);
1110
+ if (!sourceFile)
1111
+ return relative;
1112
+ const { line } = sourceFile.getLineAndCharacterOfPosition(target.span.start);
1113
+ return `${relative}:${line + 1}`;
1114
+ }
1115
+ function toTextSpan(span) {
1116
+ return { start: span.start, length: span.length };
1117
+ }
1118
+ function scriptElementKind(ts, kind) {
1119
+ switch (kind) {
1120
+ case "controller-method":
1121
+ return ts.ScriptElementKind.memberFunctionElement;
1122
+ case "inline-handler":
1123
+ return ts.ScriptElementKind.functionElement;
1124
+ case "view-component":
1125
+ return ts.ScriptElementKind.functionElement;
1126
+ case "route-entry":
1127
+ return ts.ScriptElementKind.memberVariableElement;
1128
+ }
1129
+ }
1130
+ function createRouteTableCache(host) {
1131
+ let cached;
1132
+ return {
1133
+ get(program) {
1134
+ const fileCount = program.getSourceFiles().length;
1135
+ if (cached && cached.fileCount === fileCount && isUnchanged(cached.versions)) {
1136
+ return cached.table;
1137
+ }
1138
+ const started = Date.now();
1139
+ const table = buildRouteTable(host.ts, program, {
1140
+ projectRoot: host.projectRoot,
1141
+ viewsDir: host.viewsDir,
1142
+ fileExists: host.fileExists
1143
+ });
1144
+ const versions = new Map;
1145
+ for (const fileName of table.dependencies) {
1146
+ versions.set(fileName, host.getScriptVersion(fileName));
1147
+ }
1148
+ cached = { table, versions, fileCount };
1149
+ host.log(`built route table in ${Date.now() - started}ms: ${table.api.size} api paths, ` + `${table.views.size} view paths, from ${table.dependencies.length} files`);
1150
+ for (const diagnostic of table.diagnostics)
1151
+ host.log(diagnostic);
1152
+ return table;
1153
+ }
1154
+ };
1155
+ function isUnchanged(versions) {
1156
+ for (const [fileName, version] of versions) {
1157
+ if (host.getScriptVersion(fileName) !== version)
1158
+ return false;
1159
+ }
1160
+ return true;
1161
+ }
1162
+ }
1163
+
1164
+ // ide/typescript-plugin/index.ts
1165
+ function init(modules) {
1166
+ const tsModule = modules.typescript;
1167
+ return {
1168
+ create(info) {
1169
+ const log = (message) => info.project.projectService.logger.info(`[gemi] ${message}`);
1170
+ try {
1171
+ const config = info.config ?? {};
1172
+ if (config.enable === false) {
1173
+ log("disabled by config");
1174
+ return info.languageService;
1175
+ }
1176
+ const projectRoot = trimTrailingSlash(config.projectRoot ? absolute(config.projectRoot, info.project.getCurrentDirectory()) : info.project.getCurrentDirectory());
1177
+ const viewsDir = trimTrailingSlash(config.viewsDir ? absolute(config.viewsDir, projectRoot) : `${projectRoot}/app/views`);
1178
+ log(`activated for ${projectRoot} (views: ${viewsDir})`);
1179
+ return decorateLanguageService({
1180
+ ts: tsModule,
1181
+ languageService: info.languageService,
1182
+ projectRoot,
1183
+ viewsDir,
1184
+ fileExists: (fileName) => info.serverHost.fileExists(fileName),
1185
+ getScriptVersion: (fileName) => info.project.getScriptVersion(fileName),
1186
+ log
1187
+ });
1188
+ } catch (error) {
1189
+ log(`failed to activate, falling back to the plain language service — ${describeError(error)}`);
1190
+ return info.languageService;
1191
+ }
1192
+ }
1193
+ };
1194
+ }
1195
+ function absolute(path, base) {
1196
+ const normalized = path.replace(/\\/g, "/");
1197
+ if (normalized.startsWith("/") || /^[a-zA-Z]:\//.test(normalized))
1198
+ return normalized;
1199
+ return `${trimTrailingSlash(base)}/${normalized.replace(/^\.\//, "")}`;
1200
+ }
1201
+ function trimTrailingSlash(path) {
1202
+ return path.length > 1 && path.endsWith("/") ? path.slice(0, -1) : path;
1203
+ }
1204
+ module.exports = init;
1205
+
1206
+ //# debugId=3EB5BA7A2D4DD49664756E2164756E21